aboutsummaryrefslogtreecommitdiff
path: root/cc3200/mods/modwlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'cc3200/mods/modwlan.c')
-rw-r--r--cc3200/mods/modwlan.c1199
1 files changed, 1199 insertions, 0 deletions
diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c
new file mode 100644
index 000000000..22b8cae9c
--- /dev/null
+++ b/cc3200/mods/modwlan.c
@@ -0,0 +1,1199 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "std.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "simplelink.h"
+#include "mpconfig.h"
+#include MICROPY_HAL_H
+#include "misc.h"
+#include "nlr.h"
+#include "qstr.h"
+#include "obj.h"
+#include "objtuple.h"
+#include "objlist.h"
+#include "runtime.h"
+#include "modnetwork.h"
+#include "modwlan.h"
+#include "pybioctl.h"
+#include "pybuart.h"
+#include "pybstdio.h"
+#include "osi.h"
+#include "debug.h"
+#include "serverstask.h"
+#include "mpexception.h"
+
+#ifdef USE_FREERTOS
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#endif
+
+
+/******************************************************************************
+ DEFINE TYPES
+ ******************************************************************************/
+// Status bits - These are used to set/reset the corresponding bits in a given variable
+typedef enum{
+ STATUS_BIT_NWP_INIT = 0, // If this bit is set: Network Processor is
+ // powered up
+
+ STATUS_BIT_CONNECTION, // If this bit is set: the device is connected to
+ // the AP or client is connected to device (AP)
+
+ STATUS_BIT_IP_LEASED, // If this bit is set: the device has leased IP to
+ // any connected client
+
+ STATUS_BIT_IP_ACQUIRED, // If this bit is set: the device has acquired an IP
+
+ STATUS_BIT_SMARTCONFIG_START, // If this bit is set: the SmartConfiguration
+ // process is started from SmartConfig app
+
+ STATUS_BIT_P2P_DEV_FOUND, // If this bit is set: the device (P2P mode)
+ // found any p2p-device in scan
+
+ STATUS_BIT_P2P_REQ_RECEIVED, // If this bit is set: the device (P2P mode)
+ // found any p2p-negotiation request
+
+ STATUS_BIT_CONNECTION_FAILED, // If this bit is set: the device(P2P mode)
+ // connection to client(or reverse way) is failed
+
+ STATUS_BIT_PING_DONE // If this bit is set: the device has completed
+ // the ping operation
+}e_StatusBits;
+
+typedef struct _wlan_obj_t {
+ mp_obj_base_t base;
+ SlWlanMode_t mode;
+ uint32_t status;
+ uint8_t macAddr[SL_MAC_ADDR_LEN];
+ uint8_t ssid_name[33];
+ uint8_t bssid[6];
+ bool servers_enabled;
+
+ // IPVv4 data
+ uint32_t ip;
+ uint32_t gateway;
+ uint32_t dns;
+
+} wlan_obj_t;
+
+/******************************************************************************
+ DEFINE CONSTANTS
+ ******************************************************************************/
+#define CLR_STATUS_BIT_ALL(status) (status = 0)
+#define SET_STATUS_BIT(status, bit) (status |= ( 1 << (bit)))
+#define CLR_STATUS_BIT(status, bit) (status &= ~(1 << (bit)))
+#define GET_STATUS_BIT(status, bit) (0 != (status & (1 << (bit))))
+
+#define IS_NW_PROCSR_ON(status) GET_STATUS_BIT(status, STATUS_BIT_NWP_INIT)
+#define IS_CONNECTED(status) GET_STATUS_BIT(status, STATUS_BIT_CONNECTION)
+#define IS_IP_LEASED(status) GET_STATUS_BIT(status, STATUS_BIT_IP_LEASED)
+#define IS_IP_ACQUIRED(status) GET_STATUS_BIT(status, STATUS_BIT_IP_ACQUIRED)
+#define IS_SMART_CFG_START(status) GET_STATUS_BIT(status, STATUS_BIT_SMARTCONFIG_START)
+#define IS_P2P_DEV_FOUND(status) GET_STATUS_BIT(status, STATUS_BIT_P2P_DEV_FOUND)
+#define IS_P2P_REQ_RCVD(status) GET_STATUS_BIT(status, STATUS_BIT_P2P_REQ_RECEIVED)
+#define IS_CONNECT_FAILED(status) GET_STATUS_BIT(status, STATUS_BIT_CONNECTION_FAILED)
+#define IS_PING_DONE(status) GET_STATUS_BIT(status, STATUS_BIT_PING_DONE)
+
+#define MODWLAN_SL_SCAN_ENABLE 1
+#define MODWLAN_SL_SCAN_DISABLE 0
+#define MODWLAN_SL_MAX_NETWORKS 20
+
+#define MODWLAN_TIMEOUT_MS 5000
+#define MODWLAN_MAX_NETWORKS 20
+
+#define ASSERT_ON_ERROR( x ) ASSERT((x) >= 0 )
+
+#define IPV4_ADDR_STR_LEN_MAX (16)
+#define SL_STOP_TIMEOUT 500
+
+#define WLAN_MAX_RX_SIZE 16000
+
+#define MAKE_SOCKADDR(addr, ip, port) sockaddr addr; \
+ addr.sa_family = AF_INET; \
+ addr.sa_data[0] = port >> 8; \
+ addr.sa_data[1] = port; \
+ addr.sa_data[2] = ip[0]; \
+ addr.sa_data[3] = ip[1]; \
+ addr.sa_data[4] = ip[2]; \
+ addr.sa_data[5] = ip[3];
+
+#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
+ ip[0] = addr.sa_data[2]; \
+ ip[1] = addr.sa_data[3]; \
+ ip[2] = addr.sa_data[4]; \
+ ip[3] = addr.sa_data[5];
+
+/******************************************************************************
+ DECLARE PUBLIC DATA
+ ******************************************************************************/
+STATIC wlan_obj_t wlan_obj;
+
+/******************************************************************************
+ DECLARE EXPORTED DATA
+ ******************************************************************************/
+SemaphoreHandle_t xWlanSemaphore = NULL;
+
+/******************************************************************************
+ DECLARE PRIVATE FUNCTIONS
+ ******************************************************************************/
+STATIC void wlan_initialize_data (void);
+STATIC void wlan_reenable (SlWlanMode_t mode);
+STATIC void wlan_get_sl_mac (void);
+STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec,
+ const char* key, uint32_t key_len);
+
+
+//*****************************************************************************
+//
+//! \brief The Function Handles WLAN Events
+//!
+//! \param[in] pWlanEvent - Pointer to WLAN Event Info
+//!
+//! \return None
+//!
+//*****************************************************************************
+void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent)
+{
+ if(!pWlanEvent) {
+ return;
+ }
+
+ switch(pWlanEvent->Event)
+ {
+ case SL_WLAN_CONNECT_EVENT:
+ {
+ SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION);
+ //
+ // Information about the connected AP (like name, MAC etc) will be
+ // available in 'slWlanConnectAsyncResponse_t'-Applications
+ // can use it if required
+ //
+ slWlanConnectAsyncResponse_t *pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected;
+
+ // Copy new connection SSID and BSSID to global parameters
+ memcpy(wlan_obj.ssid_name, pEventData->ssid_name, pEventData->ssid_len);
+ memcpy(wlan_obj.bssid, pEventData->bssid, SL_BSSID_LENGTH);
+ }
+ break;
+ case SL_WLAN_DISCONNECT_EVENT:
+ {
+ slWlanConnectAsyncResponse_t* pEventData = NULL;
+
+ CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION);
+ CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED);
+
+ pEventData = &pWlanEvent->EventData.STAandP2PModeDisconnected;
+
+ // If the user has initiated the 'Disconnect' request,
+ //'reason_code' is SL_USER_INITIATED_DISCONNECTION
+ if (SL_USER_INITIATED_DISCONNECTION == pEventData->reason_code) {
+
+ }
+ else {
+
+ }
+ memset(wlan_obj.ssid_name, 0, sizeof(wlan_obj.ssid_name));
+ memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid));
+ }
+ break;
+ case SL_WLAN_STA_CONNECTED_EVENT:
+ break;
+ case SL_WLAN_STA_DISCONNECTED_EVENT:
+ break;
+ case SL_WLAN_P2P_DEV_FOUND_EVENT:
+ break;
+ case SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT:
+ break;
+ case SL_WLAN_CONNECTION_FAILED_EVENT:
+ break;
+ default:
+ break;
+ }
+}
+
+//*****************************************************************************
+//
+//! \brief This function handles network events such as IP acquisition, IP
+//! leased, IP released etc.
+//!
+//! \param[in] pNetAppEvent - Pointer to NetApp Event Info
+//!
+//! \return None
+//!
+//*****************************************************************************
+void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
+{
+ if(!pNetAppEvent) {
+ return;
+ }
+
+ switch(pNetAppEvent->Event)
+ {
+ case SL_NETAPP_IPV4_IPACQUIRED_EVENT:
+ {
+ SlIpV4AcquiredAsync_t *pEventData = NULL;
+
+ SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED);
+
+ // Ip Acquired Event Data
+ pEventData = &pNetAppEvent->EventData.ipAcquiredV4;
+
+ // Get the IP addresses
+ wlan_obj.gateway = ntohl(pEventData->gateway);
+ wlan_obj.ip = ntohl(pEventData->ip);
+ wlan_obj.dns = ntohl(pEventData->dns);
+ }
+ break;
+ case SL_NETAPP_IPV6_IPACQUIRED_EVENT:
+ break;
+ case SL_NETAPP_IP_LEASED_EVENT:
+ break;
+ case SL_NETAPP_IP_RELEASED_EVENT:
+ break;
+ default:
+ break;
+ }
+}
+
+
+//*****************************************************************************
+//
+//! \brief This function handles HTTP server events
+//!
+//! \param[in] pServerEvent - Contains the relevant event information
+//! \param[in] pServerResponse - Should be filled by the user with the
+//! relevant response information
+//!
+//! \return None
+//!
+//****************************************************************************
+void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent, SlHttpServerResponse_t *pHttpResponse)
+{
+ if (!pHttpEvent) {
+ return;
+ }
+
+ switch (pHttpEvent->Event) {
+ case SL_NETAPP_HTTPGETTOKENVALUE_EVENT:
+ break;
+ case SL_NETAPP_HTTPPOSTTOKENVALUE_EVENT:
+ break;
+ default:
+ break;
+ }
+}
+
+//*****************************************************************************
+//
+//! \brief This function handles General Events
+//!
+//! \param[in] pDevEvent - Pointer to General Event Info
+//!
+//! \return None
+//!
+//*****************************************************************************
+void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
+{
+ if (!pDevEvent) {
+ return;
+ }
+
+ ASSERT (false);
+}
+
+
+//*****************************************************************************
+//
+//! This function handles socket events indication
+//!
+//! \param[in] pSock - Pointer to Socket Event Info
+//!
+//! \return None
+//!
+//*****************************************************************************
+void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
+{
+ if (!pSock) {
+ return;
+ }
+
+ switch( pSock->Event ) {
+ case SL_SOCKET_TX_FAILED_EVENT:
+ break;
+ default:
+ break;
+ }
+}
+
+//*****************************************************************************
+// SimpleLink Asynchronous Event Handlers -- End
+//*****************************************************************************
+
+void wlan_init0 (void) {
+ // Set the mode to an invalid one
+ wlan_obj.mode = -1;
+ wlan_obj.base.type = NULL;
+ memset (wlan_obj.macAddr, 0, SL_MAC_ADDR_LEN);
+#ifdef USE_FREERTOS
+ if (NULL == xWlanSemaphore) {
+ xWlanSemaphore = xSemaphoreCreateBinary();
+ }
+#endif
+ wlan_initialize_data ();
+}
+
+modwlan_Status_t wlan_sl_enable (SlWlanMode_t mode, const char *ssid, uint8_t ssid_len, uint8_t sec,
+ const char *key, uint8_t key_len, uint8_t channel) {
+
+ if (mode == ROLE_STA || mode == ROLE_AP || mode == ROLE_P2P) {
+ if (wlan_obj.mode < 0) {
+ wlan_obj.mode = sl_Start(0, 0, 0);
+ #ifdef USE_FREERTOS
+ xSemaphoreGive (xWlanSemaphore);
+ #endif
+ }
+
+ // get the mac address
+ wlan_get_sl_mac();
+
+ // stop the device if it's not in station mode
+ if (wlan_obj.mode != ROLE_STA) {
+ if (ROLE_AP == wlan_obj.mode) {
+ // if the device is in AP mode, we need to wait for this event
+ // before doing anything
+ while (!IS_IP_ACQUIRED(wlan_obj.status)) {
+ HAL_Delay (5);
+ }
+ }
+ // switch to STA mode
+ ASSERT_ON_ERROR(sl_WlanSetMode(ROLE_STA));
+ // stop and start again
+ wlan_reenable(ROLE_STA);
+ }
+
+ // Device in station-mode. Disconnect previous connection if any
+ // The function returns 0 if 'Disconnected done', negative number if already
+ // disconnected Wait for 'disconnection' event if 0 is returned, Ignore
+ // other return-codes
+ if (0 == sl_WlanDisconnect()) {
+ while (IS_CONNECTED (wlan_obj.status)) {
+ HAL_Delay (5);
+ }
+ }
+
+ // clear wlan data after checking any of the status flags
+ wlan_initialize_data ();
+
+ // Set connection policy to Auto + SmartConfig (Device's default connection policy)
+ ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(1, 0, 0, 0, 1), NULL, 0));
+
+ // Remove all profiles
+ ASSERT_ON_ERROR(sl_WlanProfileDel(0xFF));
+
+ // Enable the DHCP client
+ uint8_t value = 1;
+ ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE, 1, 1, &value));
+
+ // Set PM policy to normal
+ ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_PM, SL_NORMAL_POLICY, NULL, 0));
+
+ // Unregister mDNS services
+ ASSERT_ON_ERROR(sl_NetAppMDNSUnRegisterService(0, 0));
+
+ // Remove all 64 filters (8 * 8)
+ _WlanRxFilterOperationCommandBuff_t RxFilterIdMask;
+ memset ((void *)&RxFilterIdMask, 0 ,sizeof(RxFilterIdMask));
+ memset(RxFilterIdMask.FilterIdMask, 0xFF, 8);
+ ASSERT_ON_ERROR(sl_WlanRxFilterSet(SL_REMOVE_RX_FILTER, (_u8 *)&RxFilterIdMask, sizeof(_WlanRxFilterOperationCommandBuff_t)));
+
+ // Set Tx power level for station or AP mode
+ // Number between 0-15, as dB offset from max power - 0 will set max power
+ uint8_t ucPower = 0;
+ if (mode == ROLE_AP) {
+ // Disable the scanning
+ ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_SCAN, MODWLAN_SL_SCAN_DISABLE, NULL, 0));
+
+ // Switch to AP mode
+ ASSERT_ON_ERROR(sl_WlanSetMode(mode));
+ ASSERT (ssid != NULL && key != NULL);
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_AP_TX_POWER, sizeof(ucPower),
+ (unsigned char *)&ucPower));
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SSID, ssid_len, (unsigned char *)ssid));
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SECURITY_TYPE, sizeof(uint8_t), &sec));
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_PASSWORD, key_len, (unsigned char *)key));
+ _u8* country = (_u8*)"EU";
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE, 2, country));
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_CHANNEL, 1, (_u8 *)&channel));
+
+ // Stop and start again
+ wlan_reenable(mode);
+ ASSERT (wlan_obj.mode == mode);
+
+ SlNetAppDhcpServerBasicOpt_t dhcpParams;
+ dhcpParams.lease_time = 4096; // lease time (in seconds) of the IP Address
+ dhcpParams.ipv4_addr_start = SL_IPV4_VAL(192,168,1,2); // first IP Address for allocation.
+ dhcpParams.ipv4_addr_last = SL_IPV4_VAL(192,168,1,254); // last IP Address for allocation.
+ ASSERT_ON_ERROR(sl_NetAppStop(SL_NET_APP_DHCP_SERVER_ID)); // Stop DHCP server before settings
+ ASSERT_ON_ERROR(sl_NetAppSet(SL_NET_APP_DHCP_SERVER_ID, NETAPP_SET_DHCP_SRV_BASIC_OPT,
+ sizeof(SlNetAppDhcpServerBasicOpt_t), (_u8* )&dhcpParams)); // set parameters
+ ASSERT_ON_ERROR(sl_NetAppStart(SL_NET_APP_DHCP_SERVER_ID)); // Start DHCP server with new settings
+
+ SlNetCfgIpV4Args_t ipV4;
+ ipV4.ipV4 = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 IP address
+ ipV4.ipV4Mask = (_u32)SL_IPV4_VAL(255,255,255,0); // _u32 Subnet mask for this AP
+ ipV4.ipV4Gateway = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 Default gateway address
+ ipV4.ipV4DnsServer = (_u32)SL_IPV4_VAL(192,168,1,1); // _u32 DNS server address
+ ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_AP_P2P_GO_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4,
+ sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4));
+
+ // Stop and start again
+ wlan_reenable(mode);
+ }
+ // STA and P2P modes
+ else {
+ ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER,
+ sizeof(ucPower), (unsigned char *)&ucPower));
+ // Enable scanning every 60 seconds
+ uint32_t scanSeconds = 60;
+ ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_SCAN , MODWLAN_SL_SCAN_ENABLE, (_u8 *)&scanSeconds, sizeof(scanSeconds)));
+
+ if (mode == ROLE_P2P) {
+ // Switch to P2P mode
+ ASSERT_ON_ERROR(sl_WlanSetMode(mode));
+ // Stop and start again
+ wlan_reenable(mode);
+ }
+ }
+ return MODWLAN_OK;
+ }
+ return MODWLAN_ERROR_INVALID_PARAMS;
+}
+
+void wlan_sl_disable (void) {
+ if (wlan_obj.mode >= 0) {
+ #ifdef USE_FREERTOS
+ xSemaphoreTake (xWlanSemaphore, portMAX_DELAY);
+ #endif
+ wlan_obj.mode = -1;
+ ASSERT_ON_ERROR (sl_Stop(SL_STOP_TIMEOUT));
+ }
+}
+
+SlWlanMode_t wlan_get_mode (void) {
+ return wlan_obj.mode;
+}
+
+void wlan_get_mac (uint8_t *macAddress) {
+ if (macAddress) {
+ memcpy (macAddress, wlan_obj.macAddr, SL_MAC_ADDR_LEN);
+ }
+}
+
+void wlan_get_ip (uint32_t *ip) {
+ if (ip) {
+ *ip = IS_IP_ACQUIRED(wlan_obj.status) ? wlan_obj.ip : 0;
+ }
+}
+
+void wlan_set_pm_policy (uint8_t policy) {
+ ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_PM, policy, NULL, 0));
+}
+
+void wlan_servers_stop (void) {
+ servers_disable();
+ do {
+ HAL_Delay (2);
+ } while (servers_are_enabled());
+}
+
+//*****************************************************************************
+// DEFINE STATIC FUNCTIONS
+//*****************************************************************************
+
+STATIC void wlan_initialize_data (void) {
+ wlan_obj.status = 0;
+ wlan_obj.dns = 0;
+ wlan_obj.gateway = 0;
+ wlan_obj.ip = 0;
+ memset(wlan_obj.ssid_name, 0, sizeof(wlan_obj.ssid_name));
+ memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid));
+}
+
+STATIC void wlan_reenable (SlWlanMode_t mode) {
+ // Stop and start again
+ wlan_obj.mode = -1;
+#ifdef USE_FREERTOS
+ xSemaphoreTake (xWlanSemaphore, portMAX_DELAY);
+#endif
+ ASSERT_ON_ERROR(sl_Stop(SL_STOP_TIMEOUT));
+ wlan_obj.mode = sl_Start(0, 0, 0);
+#ifdef USE_FREERTOS
+ xSemaphoreGive (xWlanSemaphore);
+#endif
+ ASSERT (wlan_obj.mode == mode);
+}
+
+STATIC modwlan_Status_t wlan_do_connect (const char* ssid, uint32_t ssid_len, const char* bssid, uint8_t sec, const char* key, uint32_t key_len)
+{
+ SlSecParams_t secParams;
+
+ secParams.Key = (_i8*)key;
+ secParams.KeyLen = ((key != NULL) ? key_len : 0);
+ secParams.Type = sec;
+
+ if (0 == sl_WlanConnect((_i8*)ssid, ssid_len, (_u8*)bssid, &secParams, NULL)) {
+
+ // Wait for WLAN Event
+ uint32_t waitForConnectionMs = 0;
+ while (!IS_CONNECTED(wlan_obj.status)) {
+ HAL_Delay (5);
+ if (++waitForConnectionMs >= MODWLAN_TIMEOUT_MS) {
+ return MODWLAN_ERROR_TIMEOUT;
+ }
+ }
+
+ return MODWLAN_OK;
+ }
+
+ return MODWLAN_ERROR_INVALID_PARAMS;
+}
+
+STATIC void wlan_get_sl_mac (void) {
+ // Get the MAC address
+ uint8_t macAddrLen = SL_MAC_ADDR_LEN;
+ sl_NetCfgGet(SL_MAC_ADDRESS_GET,NULL, &macAddrLen, wlan_obj.macAddr);
+}
+
+/// \method init(mode, ssid=myWlan, security=wlan.WPA_WPA2, key=myWlanKey)
+///
+/// Initialise the UART bus with the given parameters:
+///
+/// - `mode` can be ROLE_AP, ROLE_STA and ROLE_P2P.
+/// - `ssid` is the network ssid in case of AP mode
+/// - `security` is the security type for AP mode
+/// - `key` is the key when in AP mode
+/// - `channel` is the channel to use for the AP network
+STATIC const mp_arg_t wlan_init_args[] = {
+ { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = ROLE_STA} },
+ { MP_QSTR_ssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SEC_TYPE_OPEN} },
+ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5} },
+};
+
+STATIC mp_obj_t wlan_init_helper(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(wlan_init_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(wlan_init_args), wlan_init_args, args);
+
+ // get the ssid
+ mp_uint_t ssid_len;
+ const char *ssid = mp_obj_str_get_data(args[1].u_obj, &ssid_len);
+
+ // get the key
+ mp_uint_t key_len;
+ const char *key = mp_obj_str_get_data(args[3].u_obj, &key_len);
+
+ if (key_len < 8) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_value_invalid_arguments));
+ }
+
+ // Force the channel to be between 1-11
+ uint8_t channel = args[4].u_int > 0 ? args[4].u_int % 12 : 1;
+
+ if (MODWLAN_OK != wlan_sl_enable (args[0].u_int, ssid, ssid_len, args[2].u_int, key, key_len, channel)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
+ }
+
+ return mp_const_none;
+}
+
+
+/******************************************************************************/
+// Micro Python bindings; WLAN class
+
+/// \class WLAN - driver for the WLAN functionality of the SoC
+
+/// \classmethod \constructor()
+/// Create a wlan obecjt and initialise the simplelink engine
+//
+STATIC mp_obj_t wlan_make_new (mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 0, MP_ARRAY_SIZE(wlan_init_args), true);
+
+ if (n_args > 0) {
+ // Get the mode
+ SlWlanMode_t mode = mp_obj_get_int(args[0]);
+
+ // Stop all other processes using the wlan engine
+ if ( (wlan_obj.servers_enabled = servers_are_enabled()) ) {
+ wlan_servers_stop();
+ }
+ if (mode == ROLE_AP) {
+ // start the peripheral
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ wlan_init_helper(n_args, args, &kw_args);
+ }
+ // TODO: Only STA mode supported for the moment. What if P2P?
+ else if (n_args == 1) {
+ if (MODWLAN_OK != wlan_sl_enable (mode, NULL, 0, 0, NULL, 0, 0)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
+ }
+ }
+ else {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
+ }
+
+ // Start the servers again
+ if (wlan_obj.servers_enabled) {
+ servers_enable ();
+ }
+ } else if (wlan_obj.mode < 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
+ }
+
+ wlan_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wlan;
+ // register with the network module
+ mod_network_register_nic(&wlan_obj);
+
+ return &wlan_obj;
+}
+
+STATIC void wlan_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ wlan_obj_t *self = self_in;
+ print(env, "wlan(mode=%u, status=%u", self->mode, self->status);
+ print(env, ", mac=%02x:%02x:%02x:%02x:%02x:%02x", self->macAddr[0], self->macAddr[1], self->macAddr[2],
+ self->macAddr[3], self->macAddr[4], self->macAddr[5]);
+
+ // Only print the ssid if in station or ap mode
+ if (self->mode == ROLE_STA || self->mode == ROLE_AP) {
+ print(env, ", ssid=%s", self->ssid_name);
+
+ // Only print the bssid if in station mode
+ if (self->mode == ROLE_STA) {
+ print(env, ", bssid=%02x:%02x:%02x:%02x:%02x:%02x", self->bssid[0], self->bssid[1], self->bssid[2],
+ self->bssid[3], self->bssid[4], self->bssid[5]);
+ }
+
+ char ip_str[IPV4_ADDR_STR_LEN_MAX];
+ uint8_t *ip = (uint8_t *)&self->ip;
+ snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+ print(env, ", ip=%s", ip_str);
+ ip = (uint8_t *)&self->gateway;
+ snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+ print(env, ", gateway=%s", ip_str);
+ ip = (uint8_t *)&self->dns;
+ snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+ print(env, ", dns=%s)", ip_str);
+ }
+ else {
+ print(env, ")");
+ }
+}
+
+/// \method mode()
+/// Get the wlan mode:
+///
+/// - Returns the current wlan mode. Possible values are:
+/// ROLE_STA, ROLE_AP and ROLE_P2P
+///
+STATIC mp_obj_t wlan_getmode(mp_obj_t self_in) {
+ wlan_obj_t* self = self_in;
+ return mp_obj_new_int(self->mode);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_getmode_obj, wlan_getmode);
+
+STATIC mp_obj_t wlan_setpm(mp_obj_t self_in, mp_obj_t pm_mode) {
+ mp_int_t mode = mp_obj_get_int(pm_mode);
+ if (mode < SL_NORMAL_POLICY || mode > SL_LONG_SLEEP_INTERVAL_POLICY) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
+ }
+ wlan_set_pm_policy((uint8_t)mode);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(wlan_setpm_obj, wlan_setpm);
+
+/// \method connect(ssid, key=None, *, security=OPEN, bssid=None)
+STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SEC_TYPE_OPEN} },
+ { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get ssid
+ mp_uint_t ssid_len;
+ const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len);
+
+ // get key and sec
+ mp_uint_t key_len = 0;
+ const char *key = NULL;
+ mp_uint_t sec = SL_SEC_TYPE_OPEN;
+ if (args[1].u_obj != mp_const_none) {
+ key = mp_obj_str_get_data(args[1].u_obj, &key_len);
+ sec = args[2].u_int;
+ }
+
+ // get bssid
+ const char *bssid = NULL;
+ if (args[3].u_obj != mp_const_none) {
+ bssid = mp_obj_str_get_str(args[3].u_obj);
+ }
+
+ if (wlan_obj.mode != ROLE_STA) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible));
+ }
+ else {
+ if (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION)) {
+ if (0 == sl_WlanDisconnect()) {
+ while (IS_CONNECTED(wlan_obj.status)) {
+ HAL_Delay (5);
+ }
+ }
+ }
+ // connect to the requested access point
+ modwlan_Status_t status;
+ status = wlan_do_connect (ssid, ssid_len, bssid, sec, key, key_len);
+ if (status != MODWLAN_OK) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_connect_obj, 1, wlan_connect);
+
+/// \method wlan_disconnect()
+/// Closes the current WLAN connection
+///
+STATIC mp_obj_t wlan_disconnect(mp_obj_t self_in) {
+ sl_WlanDisconnect();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_disconnect_obj, wlan_disconnect);
+
+/// \method is_connected()
+/// Returns true if connected to the AP and an IP address has been assigned. False otherwise.
+///
+STATIC mp_obj_t wlan_isconnected(mp_obj_t self_in) {
+ if (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION) &&
+ GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED)) {
+ return mp_const_true;
+ }
+ return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected);
+
+/// \method getip()
+/// Get the IP
+///
+/// - Returns the acquired IP address
+///
+STATIC mp_obj_t wlan_getip(mp_obj_t self_in) {
+ return mod_network_format_ipv4_addr ((uint8_t *)&wlan_obj.ip);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_getip_obj, wlan_getip);
+
+
+/// \method wlan_netlist()
+/// Returns a list of tuples with all the acces points within range
+STATIC mp_obj_t wlan_scan(mp_obj_t self_in) {
+ Sl_WlanNetworkEntry_t wlanEntry;
+ uint8_t _index = 0;
+ mp_obj_t nets = NULL;
+
+ do {
+ if (sl_WlanGetNetworkList(_index++, 1, &wlanEntry) <= 0) {
+ break;
+ }
+ mp_obj_t tuple[4];
+
+ tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false);
+ tuple[1] = mp_obj_new_str((const char *)wlanEntry.bssid, SL_BSSID_LENGTH, false);
+ // 'Normalize' the security type
+ if (wlanEntry.sec_type > 2) {
+ wlanEntry.sec_type = 2;
+ }
+ tuple[2] = mp_obj_new_int(wlanEntry.sec_type);
+ tuple[3] = mp_obj_new_int(wlanEntry.rssi);
+
+ if (_index == 1) {
+ // Initialize the set
+ nets = mp_obj_new_set(0, NULL);
+ }
+ // Add the network found to the list if it's unique
+ mp_obj_set_store(nets, mp_obj_new_tuple(4, tuple));
+
+ } while (_index < MODWLAN_SL_MAX_NETWORKS);
+
+ return (nets != NULL) ? nets : mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan);
+
+STATIC mp_obj_t wlan_serversstart(mp_obj_t self_in) {
+ servers_enable();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_serversstart_obj, wlan_serversstart);
+
+STATIC mp_obj_t wlan_serversstop(mp_obj_t self_in) {
+ wlan_servers_stop();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_serversstop_obj, wlan_serversstop);
+
+STATIC mp_obj_t wlan_areserversenabled(mp_obj_t self_in) {
+ return MP_BOOL(servers_are_enabled());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_areserversenabled_obj, wlan_areserversenabled);
+
+STATIC mp_obj_t wlan_serversuserpass(mp_obj_t self_in, mp_obj_t user, mp_obj_t pass) {
+ const char *_user = mp_obj_str_get_str(user);
+ const char *_pass = mp_obj_str_get_str(pass);
+ servers_set_user_pass((char *)_user, (char *)_pass);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(wlan_serversuserpass_obj, wlan_serversuserpass);
+
+STATIC const mp_map_elem_t wlan_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&wlan_connect_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_getmode), (mp_obj_t)&wlan_getmode_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_setpm), (mp_obj_t)&wlan_setpm_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&wlan_scan_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&wlan_disconnect_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&wlan_isconnected_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_getip), (mp_obj_t)&wlan_getip_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_serversstart), (mp_obj_t)&wlan_serversstart_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_serversstop), (mp_obj_t)&wlan_serversstop_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_areserversenabled), (mp_obj_t)&wlan_areserversenabled_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_serversuserpass), (mp_obj_t)&wlan_serversuserpass_obj },
+
+ // class constants
+ { MP_OBJ_NEW_QSTR(MP_QSTR_OPEN), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_OPEN) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WEP), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WEP) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WPA_WPA2), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WPA_ENT), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_ENT) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WPS_PBC), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPS_PBC) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_WPS_PIN), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPS_PIN) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_STA), MP_OBJ_NEW_SMALL_INT(ROLE_STA) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_AP), MP_OBJ_NEW_SMALL_INT(ROLE_AP) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_P2P), MP_OBJ_NEW_SMALL_INT(ROLE_P2P) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_NORMAL_PM), MP_OBJ_NEW_SMALL_INT(SL_NORMAL_POLICY) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_LOW_LATENCY_PM), MP_OBJ_NEW_SMALL_INT(SL_LOW_LATENCY_POLICY) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER_PM), MP_OBJ_NEW_SMALL_INT(SL_LOW_POWER_POLICY) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ALWAYS_ON_PM), MP_OBJ_NEW_SMALL_INT(SL_ALWAYS_ON_POLICY) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_LONG_SLEEP_PM), MP_OBJ_NEW_SMALL_INT(SL_LONG_SLEEP_INTERVAL_POLICY) },
+};
+STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table);
+
+
+/******************************************************************************/
+// Micro Python bindings; WLAN socket
+
+STATIC int wlan_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) {
+ uint32_t ip;
+ int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family);
+
+ out_ip[0] = ip >> 24;
+ out_ip[1] = ip >> 16;
+ out_ip[2] = ip >> 8;
+ out_ip[3] = ip;
+
+ return result;
+}
+
+STATIC int wlan_socket_socket(struct _mod_network_socket_obj_t *s, int *_errno) {
+ // open the socket
+ int16_t sd = sl_Socket(s->u_param.domain, s->u_param.type, s->u_param.proto);
+ if (s->sd < 0) {
+ *_errno = s->sd;
+ return -1;
+ }
+
+ // mark the socket not closed
+ s->closed = false;
+ // save the socket descriptor
+ s->sd = sd;
+
+ // make it blocking by default
+ int32_t optval = 0;
+ sl_SetSockOpt(sd, SOL_SOCKET, SO_NONBLOCKING, &optval, (SlSocklen_t)sizeof(optval));
+
+ return 0;
+}
+
+STATIC void wlan_socket_close(mod_network_socket_obj_t *s) {
+ s->closed = true;
+ sl_Close(s->sd);
+}
+
+STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = sl_Bind(s->sd, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) {
+ int ret = sl_Listen(s->sd, backlog);
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) {
+ // accept incoming connection
+ int16_t sd;
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ if ((sd = sl_Accept(s->sd, &addr, &addr_len)) < 0) {
+ *_errno = sd;
+ return -1;
+ }
+
+ // Mark the socket not closed and save the new descriptor
+ s2->closed = false;
+ s2->sd = sd;
+
+ // return ip and port
+ UNPACK_SOCKADDR(addr, ip, *port);
+
+ return 0;
+}
+
+STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = sl_Connect(s->sd, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
+ if (s->closed) {
+ sl_Close (s->sd);
+ *_errno = EBADF;
+ return -1;
+ }
+
+ mp_int_t bytes = 0;
+ if (len > 0) {
+ bytes = sl_Send(s->sd, (const void *)buf, len, 0);
+ }
+ if (bytes <= 0) {
+ *_errno = bytes;
+ return -1;
+ }
+
+ return bytes;
+}
+
+STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
+ // check if the socket is open
+ if (s->closed) {
+ // socket is closed, but the CC3200 may have some data remaining in its buffer, so check
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(s->sd, &rfds);
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 2;
+ int nfds = sl_Select(s->sd + 1, &rfds, NULL, NULL, &tv);
+ if (nfds == -1 || !FD_ISSET(s->sd, &rfds)) {
+ // no data waiting, so close socket and return 0 data
+ sl_Close(s->sd);
+ return 0;
+ }
+ }
+
+ // cap length at WLAN_MAX_RX_SIZE
+ len = MIN(len, WLAN_MAX_RX_SIZE);
+
+ // do the recv
+ int ret = sl_Recv(s->sd, buf, len, 0);
+ if (ret < 0) {
+ *_errno = ret;
+ return -1;
+ }
+
+ return ret;
+}
+
+STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = sl_SendTo(s->sd, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr));
+ if (ret < 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ mp_int_t ret = sl_RecvFrom(s->sd, buf, len, 0, &addr, &addr_len);
+ if (ret < 0) {
+ *_errno = ret;
+ return -1;
+ }
+ UNPACK_SOCKADDR(addr, ip, *port);
+ return ret;
+}
+
+STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
+ int ret = sl_SetSockOpt(socket->sd, level, opt, optval, optlen);
+ if (ret < 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_ms, int *_errno) {
+ int ret;
+ if (timeout_ms == 0 || timeout_ms == -1) {
+ int optval;
+ if (timeout_ms == 0) {
+ // set non-blocking mode
+ optval = 1;
+ } else {
+ // set blocking mode
+ optval = 0;
+ }
+ ret = sl_SetSockOpt(s->sd, SOL_SOCKET, SO_NONBLOCKING, &optval, sizeof(optval));
+ } else {
+ // set timeout
+ ret = sl_SetSockOpt(s->sd, SOL_SOCKET, SO_RCVTIMEO, &timeout_ms, sizeof(timeout_ms));
+ }
+
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ mp_int_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ int32_t sd = s->sd;
+
+ // init fds
+ fd_set rfds, wfds, xfds;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+
+ // set fds if needed
+ if (flags & MP_IOCTL_POLL_RD) {
+ FD_SET(sd, &rfds);
+
+ // A socked that just closed is available for reading. A call to
+ // recv() returns 0 which is consistent with BSD.
+ if (s->closed) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ }
+ if (flags & MP_IOCTL_POLL_WR) {
+ FD_SET(sd, &wfds);
+ }
+ if (flags & MP_IOCTL_POLL_HUP) {
+ FD_SET(sd, &xfds);
+ }
+
+ // call simplelink select with minimum timeout
+ SlTimeval_t tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
+
+ // check for error
+ if (nfds == -1) {
+ *_errno = nfds;
+ return -1;
+ }
+
+ // check return of select
+ if (FD_ISSET(sd, &rfds)) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if (FD_ISSET(sd, &wfds)) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ if (FD_ISSET(sd, &xfds)) {
+ ret |= MP_IOCTL_POLL_HUP;
+ }
+ } else {
+ *_errno = EINVAL;
+ ret = -1;
+ }
+ return ret;
+}
+
+const mod_network_nic_type_t mod_network_nic_type_wlan = {
+ .base = {
+ { &mp_type_type },
+ .name = MP_QSTR_WLAN,
+ .print = wlan_print,
+ .make_new = wlan_make_new,
+ .locals_dict = (mp_obj_t)&wlan_locals_dict,
+ },
+ .gethostbyname = wlan_gethostbyname,
+ .socket = wlan_socket_socket,
+ .close = wlan_socket_close,
+ .bind = wlan_socket_bind,
+ .listen = wlan_socket_listen,
+ .accept = wlan_socket_accept,
+ .connect = wlan_socket_connect,
+ .send = wlan_socket_send,
+ .recv = wlan_socket_recv,
+ .sendto = wlan_socket_sendto,
+ .recvfrom = wlan_socket_recvfrom,
+ .setsockopt = wlan_socket_setsockopt,
+ .settimeout = wlan_socket_settimeout,
+ .ioctl = wlan_socket_ioctl,
+};