text: #include "ThreadInterface.h"
  #include "include/thread_tasklet.h"
  #include "callback_handler.h"
  #include "mesh_system.h"
  #include "randLIB.h"
  
  #include "ns_trace.h"
  #define TRACE_GROUP "nsth"
  
  nsapi_error_t ThreadInterface::initialize(NanostackRfPhy *phy)
  {
      return MeshInterfaceNanostack::initialize(phy);
  }
  
  int ThreadInterface::connect()
  {
      if (_connect_status == NSAPI_STATUS_GLOBAL_UP || _connect_status == NSAPI_STATUS_LOCAL_UP) {
          return NSAPI_ERROR_IS_CONNECTED;
      } else if (_connect_status == NSAPI_STATUS_CONNECTING) {
          return NSAPI_ERROR_ALREADY;
      }
  
      nanostack_lock();
  
      if (register_phy() < 0) {
          nanostack_unlock();
          return NSAPI_ERROR_DEVICE_ERROR;
      }
      // After the RF is up, we can seed the random from it.
      randLIB_seed_random();
  
      mesh_error_t status = init();
      if (status != MESH_ERROR_NONE) {
          nanostack_unlock();
          return map_mesh_error(status);
      }
  
      status = mesh_connect();
      if (status != MESH_ERROR_NONE) {
          nanostack_unlock();
          return map_mesh_error(status);
      }
  
      // Release mutex before blocking
      nanostack_unlock();
  
      // In Thread wait connection for ever:
      // -routers will create new network and get local connectivity
      // -end devices will get connectivity once attached to existing network
      // -devices without network settings gets connectivity once commissioned and attached to network
      _connect_status = NSAPI_STATUS_CONNECTING;
      if (_connection_status_cb) {
          _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING);
      }
      if (_blocking) {
          int32_t count = connect_semaphore.wait(osWaitForever);
  
          if (count <= 0) {
              return NSAPI_ERROR_DHCP_FAILURE; // sort of...
          }
      }
      return 0;
  }
  
  int ThreadInterface::disconnect()
  {
      nanostack_lock();
  
      mesh_error_t status = mesh_disconnect();
  
      nanostack_unlock();
  
      return map_mesh_error(status);
  }
  
  mesh_error_t ThreadInterface::init()
  {
      thread_tasklet_init();
      __mesh_handler_set_callback(this);
      thread_tasklet_device_eui64_set(_eui64);
      _network_interface_id = thread_tasklet_network_init(_device_id);
  
      if (_network_interface_id == -2) {
          return MESH_ERROR_PARAM;
      } else if (_network_interface_id == -3) {
          return MESH_ERROR_MEMORY;
      } else if (_network_interface_id < 0) {
          return MESH_ERROR_UNKNOWN;
      }
      return MESH_ERROR_NONE;
  }
  
  bool ThreadInterface::getOwnIpAddress(char *address, int8_t len)
  {
      tr_debug("getOwnIpAddress()");
      if (thread_tasklet_get_ip_address(address, len) == 0) {
          return true;
      }
      return false;
  }
  
  mesh_error_t ThreadInterface::mesh_connect()
  {
      int8_t status;
      tr_debug("connect()");
  
      status = thread_tasklet_connect(&__mesh_handler_c_callback, _network_interface_id);
  
      if (status >= 0) {
          return MESH_ERROR_NONE;
      } else if (status == -1) {
          return MESH_ERROR_PARAM;
      } else if (status == -2) {
          return MESH_ERROR_MEMORY;
      } else if (status == -3) {
          return MESH_ERROR_STATE;
      } else {
          return MESH_ERROR_UNKNOWN;
      }
  }
  
  void ThreadInterface::device_eui64_set(const uint8_t *eui64)
  {
      memcpy(_eui64, eui64, 8);
  }
  
  mesh_error_t ThreadInterface::device_pskd_set(const char *pskd)
  {
      return (mesh_error_t)thread_tasklet_device_pskd_set(pskd);
  }
  
  mesh_error_t ThreadInterface::mesh_disconnect()
  {
      int8_t status;
  
      status = thread_tasklet_disconnect(true);
  
      if (status >= 0) {
          return MESH_ERROR_NONE;
      }
  
      return MESH_ERROR_UNKNOWN;
  }
  