/* * 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 #include #include "std.h" #include "simplelink.h" #include "py/mpconfig.h" #include "py/obj.h" #include "py/objstr.h" #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "rom_map.h" #include "prcm.h" #include "timeutils.h" #include "netutils.h" #include "modnetwork.h" #include "modusocket.h" #include "modwlan.h" #include "pybrtc.h" #include "debug.h" #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) #include "serverstask.h" #endif #include "mpexception.h" #include "mpirq.h" #include "pybsleep.h" #include "antenna.h" /****************************************************************************** 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; /****************************************************************************** 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_MAX_NETWORKS 20 #define MODWLAN_SCAN_PERIOD_S 3600 // 1 hour #define MODWLAN_WAIT_FOR_SCAN_MS 1050 #define MODWLAN_CONNECTION_WAIT_MS 2 #define ASSERT_ON_ERROR(x) ASSERT((x) >= 0) #define IPV4_ADDR_STR_LEN_MAX (16) #define WLAN_MAX_RX_SIZE 16000 #define WLAN_MAX_TX_SIZE 1476 #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[3]; \ addr.sa_data[3] = ip[2]; \ addr.sa_data[4] = ip[1]; \ addr.sa_data[5] = ip[0]; #define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \ ip[0] = addr.sa_data[5]; \ ip[1] = addr.sa_data[4]; \ ip[2] = addr.sa_data[3]; \ ip[3] = addr.sa_data[2]; /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ STATIC wlan_obj_t wlan_obj = { .mode = -1, .status = 0, .ip = 0, .auth = MICROPY_PORT_WLAN_AP_SECURITY, .channel = MICROPY_PORT_WLAN_AP_CHANNEL, .ssid = MICROPY_PORT_WLAN_AP_SSID, .key = MICROPY_PORT_WLAN_AP_KEY, .mac = {0}, //.ssid_o = {0}, //.bssid = {0}, #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) .servers_enabled = false, #endif }; STATIC const mp_irq_methods_t wlan_irq_methods; /****************************************************************************** DECLARE PUBLIC DATA ******************************************************************************/ OsiLockObj_t wlan_LockObj; /****************************************************************************** DECLARE PRIVATE FUNCTIONS ******************************************************************************/ STATIC void wlan_clear_data (void); STATIC void wlan_reenable (SlWlanMode_t mode); STATIC void wlan_servers_start (void); STATIC void wlan_servers_stop (void); STATIC void wlan_reset (void); STATIC void wlan_validate_mode (uint mode); STATIC void wlan_set_mode (uint mode); STATIC void wlan_validate_ssid_len (uint32_t len); STATIC void wlan_set_ssid (const char *ssid, uint8_t len, bool add_mac); STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len); STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len); STATIC void wlan_validate_channel (uint8_t channel); STATIC void wlan_set_channel (uint8_t channel); #if MICROPY_HW_ANTENNA_DIVERSITY STATIC void wlan_validate_antenna (uint8_t antenna); STATIC void wlan_set_antenna (uint8_t antenna); #endif STATIC void wlan_sl_disconnect (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, int32_t timeout); STATIC void wlan_get_sl_mac (void); STATIC void wlan_wep_key_unhexlify (const char *key, char *key_out); STATIC void wlan_lpds_irq_enable (mp_obj_t self_in); STATIC void wlan_lpds_irq_disable (mp_obj_t self_in); STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid); //***************************************************************************** // //! \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: { //slWlanConnectAsyncResponse_t *pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected; // copy the new connection data //memcpy(wlan_obj.bssid, pEventData->bssid, SL_BSSID_LENGTH); //memcpy(wlan_obj.ssid_o, pEventData->ssid_name, pEventData->ssid_len); //wlan_obj.ssid_o[pEventData->ssid_len] = '\0'; SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) // we must reset the servers in case that the last connection // was lost without any notification being received servers_reset(); #endif } break; case SL_WLAN_DISCONNECT_EVENT: CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED); #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) servers_reset(); servers_wlan_cycle_power(); #endif break; case SL_WLAN_STA_CONNECTED_EVENT: { //slPeerInfoAsyncResponse_t *pEventData = &pWlanEvent->EventData.APModeStaConnected; // get the mac address and name of the connected device //memcpy(wlan_obj.bssid, pEventData->mac, SL_BSSID_LENGTH); //memcpy(wlan_obj.ssid_o, pEventData->go_peer_device_name, pEventData->go_peer_device_name_len); //wlan_obj.ssid_o[pEventData->go_peer_device_name_len] = '\0'; SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) // we must reset the servers in case that the last connection // was lost without any notification being received servers_reset(); #endif } break; case SL_WLAN_STA_DISCONNECTED_EVENT: CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION); #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) servers_reset(); servers_wlan_cycle_power(); #endif break; case SL_WLAN_P2P_DEV_FOUND_EVENT: // TODO break; case SL_WLAN_P2P_NEG_REQ_RECEIVED_EVENT: // TODO break; case SL_WLAN_CONNECTION_FAILED_EVENT: // TODO 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 wlan_obj.ip = pEventData->ip; } 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; } } //***************************************************************************** // //! 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: switch( pSock->socketAsyncEvent.SockTxFailData.status) { case SL_ECLOSE: break; default: break; } break; case SL_SOCKET_ASYNC_EVENT: switch(pSock->socketAsyncEvent.SockAsyncData.type) { case SSL_ACCEPT: break; case RX_FRAGMENTATION_TOO_BIG: break; case OTHER_SIDE_CLOSE_SSL_DATA_NOT_ENCRYPTED: break; default: break; } break; default: break; } } //***************************************************************************** // SimpleLink Asynchronous Event Handlers -- End //***************************************************************************** __attribute__ ((section (".boot"))) void wlan_pre_init (void) { // create the wlan lock ASSERT(OSI_OK == sl_LockObjCreate(&wlan_LockObj, "WlanLock")); } void wlan_first_start (void) { if (wlan_obj.mode < 0) { CLR_STATUS_BIT_ALL(wlan_obj.status); wlan_obj.mode = sl_Start(0, 0, 0); sl_LockObjUnlock (&wlan_LockObj); } // get the mac address wlan_get_sl_mac(); } void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len, uint8_t channel, uint8_t antenna, bool add_mac) { // stop the servers wlan_servers_stop(); // do a basic start wlan_first_start(); // close any active connections wlan_sl_disconnect(); // 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)); // Stop the internal HTTP server sl_NetAppStop(SL_NET_APP_HTTP_SERVER_ID); // 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))); #if MICROPY_HW_ANTENNA_DIVERSITY // set the antenna type wlan_set_antenna (antenna); #endif // switch to the requested mode wlan_set_mode(mode); // stop and start again (we need to in the propper mode from now on) wlan_reenable(mode); // 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) { ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_AP_TX_POWER, sizeof(ucPower), (unsigned char *)&ucPower)); // configure all parameters wlan_set_ssid (ssid, ssid_len, add_mac); wlan_set_security (auth, key, key_len); wlan_set_channel (channel); // set the country _u8* country = (_u8*)"EU"; ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_COUNTRY_CODE, 2, country)); 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)); 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 // stop and start again wlan_reenable(mode); } else { // STA and P2P modes ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, sizeof(ucPower), (unsigned char *)&ucPower)); // set connection policy to Auto + Fast (tries to connect to the last connected AP) ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(1, 1, 0, 0, 0), NULL, 0)); } // set current time and date (needed to validate certificates) wlan_set_current_time (pyb_rtc_get_seconds()); // start the servers before returning wlan_servers_start(); } void wlan_update(void) { #ifndef SL_PLATFORM_MULTI_THREADED _SlTaskEntry(); #endif } void wlan_stop (uint32_t timeout) { wlan_servers_stop(); sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); sl_Stop(timeout); wlan_clear_data(); wlan_obj.mode = -1; } void wlan_get_mac (uint8_t *macAddress) { if (macAddress) { memcpy (macAddress, wlan_obj.mac, SL_MAC_ADDR_LEN); } } void wlan_get_ip (uint32_t *ip) { if (ip) { *ip = IS_IP_ACQUIRED(wlan_obj.status) ? wlan_obj.ip : 0; } } bool wlan_is_connected (void) { return (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION) && (GET_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED) || wlan_obj.mode != ROLE_STA)); } void wlan_set_current_time (uint32_t seconds_since_2000) { timeutils_struct_time_t tm; timeutils_seconds_since_2000_to_struct_time(seconds_since_2000, &tm); SlDateTime_t sl_datetime = {0}; sl_datetime.sl_tm_day = tm.tm_mday; sl_datetime.sl_tm_mon = tm.tm_mon; sl_datetime.sl_tm_year = tm.tm_year; sl_datetime.sl_tm_hour = tm.tm_hour; sl_datetime.sl_tm_min = tm.tm_min; sl_datetime.sl_tm_sec = tm.tm_sec; sl_DevSet(SL_DEVICE_GENERAL_CONFIGURATION, SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME, sizeof(SlDateTime_t), (_u8 *)(&sl_datetime)); } void wlan_off_on (void) { // no need to lock the WLAN object on every API call since the servers and the MicroPtyhon // task have the same priority wlan_reenable(wlan_obj.mode); } //***************************************************************************** // DEFINE STATIC FUNCTIONS //***************************************************************************** STATIC void wlan_clear_data (void) { CLR_STATUS_BIT_ALL(wlan_obj.status); wlan_obj.ip = 0; //memset(wlan_obj.ssid_o, 0, sizeof(wlan_obj.ssid)); //memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid)); } STATIC void wlan_reenable (SlWlanMode_t mode) { // stop and start again sl_LockObjLock (&wlan_LockObj, SL_OS_WAIT_FOREVER); sl_Stop(SL_STOP_TIMEOUT); wlan_clear_data(); wlan_obj.mode = sl_Start(0, 0, 0); sl_LockObjUnlock (&wlan_LockObj); ASSERT (wlan_obj.mode == mode); } STATIC void wlan_servers_start (void) { #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) // start the servers if they were enabled before if (wlan_obj.servers_enabled) { servers_start(); } #endif } STATIC void wlan_servers_stop (void) { #if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP) // Stop all other processes using the wlan engine if ((wlan_obj.servers_enabled = servers_are_enabled())) { servers_stop(); } #endif } STATIC void wlan_reset (void) { wlan_servers_stop(); wlan_reenable (wlan_obj.mode); wlan_servers_start(); } STATIC void wlan_validate_mode (uint mode) { if (mode != ROLE_STA && mode != ROLE_AP) { mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void wlan_set_mode (uint mode) { wlan_obj.mode = mode; ASSERT_ON_ERROR(sl_WlanSetMode(mode)); } STATIC void wlan_validate_ssid_len (uint32_t len) { if (len > MODWLAN_SSID_LEN_MAX) { mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void wlan_set_ssid (const char *ssid, uint8_t len, bool add_mac) { if (ssid != NULL) { // save the ssid memcpy(&wlan_obj.ssid, ssid, len); // append the last 2 bytes of the MAC address, since the use of this functionality is under our control // we can assume that the lenght of the ssid is less than (32 - 5) if (add_mac) { snprintf((char *)&wlan_obj.ssid[len], sizeof(wlan_obj.ssid) - len, "-%02x%02x", wlan_obj.mac[4], wlan_obj.mac[5]); len += 5; } wlan_obj.ssid[len] = '\0'; ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SSID, len, (unsigned char *)wlan_obj.ssid)); } } STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len) { if (auth != SL_SEC_TYPE_WEP && auth != SL_SEC_TYPE_WPA_WPA2) { goto invalid_args; } if (auth == SL_SEC_TYPE_WEP) { for (mp_uint_t i = strlen(key); i > 0; i--) { if (!unichar_isxdigit(*key++)) { goto invalid_args; } } } return; invalid_args: mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { wlan_obj.auth = auth; ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_SECURITY_TYPE, sizeof(uint8_t), &auth)); if (key != NULL) { memcpy(&wlan_obj.key, key, len); wlan_obj.key[len] = '\0'; if (auth == SL_SEC_TYPE_WEP) { _u8 wep_key[32]; wlan_wep_key_unhexlify(key, (char *)&wep_key); key = (const char *)&wep_key; len /= 2; } ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_PASSWORD, len, (unsigned char *)key)); } else { wlan_obj.key[0] = '\0'; } } STATIC void wlan_validate_channel (uint8_t channel) { if (channel < 1 || channel > 11) { mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void wlan_set_channel (uint8_t channel) { wlan_obj.channel = channel; ASSERT_ON_ERROR(sl_WlanSet(SL_WLAN_CFG_AP_ID, WLAN_AP_OPT_CHANNEL, 1, &channel)); } #if MICROPY_HW_ANTENNA_DIVERSITY STATIC void wlan_validate_antenna (uint8_t antenna) { if (antenna != ANTENNA_TYPE_INTERNAL && antenna != ANTENNA_TYPE_EXTERNAL) { mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void wlan_set_antenna (uint8_t antenna) { wlan_obj.antenna = antenna; antenna_select(antenna); } #endif STATIC void wlan_sl_disconnect (void) { // 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)) { mp_hal_delay_ms(MODWLAN_CONNECTION_WAIT_MS); wlan_update(); } } } 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, int32_t timeout) { SlSecParams_t secParams; secParams.Key = (_i8*)key; secParams.KeyLen = ((key != NULL) ? key_len : 0); secParams.Type = sec; // first close any active connections wlan_sl_disconnect(); if (!sl_WlanConnect((_i8*)ssid, ssid_len, (_u8*)bssid, &secParams, NULL)) { // wait for the WLAN Event uint32_t waitForConnectionMs = 0; while (timeout && !IS_CONNECTED(wlan_obj.status)) { mp_hal_delay_ms(MODWLAN_CONNECTION_WAIT_MS); waitForConnectionMs += MODWLAN_CONNECTION_WAIT_MS; if (timeout > 0 && waitForConnectionMs > timeout) { return MODWLAN_ERROR_TIMEOUT; } wlan_update(); } 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.mac); } STATIC void wlan_wep_key_unhexlify (const char *key, char *key_out) { byte hex_byte = 0; for (mp_uint_t i = strlen(key); i > 0 ; i--) { hex_byte += unichar_xdigit_value(*key++); if (i & 1) { hex_byte <<= 4; } else { *key_out++ = hex_byte; hex_byte = 0; } } } STATIC void wlan_lpds_irq_enable (mp_obj_t self_in) { wlan_obj_t *self = self_in; self->irq_enabled = true; } STATIC void wlan_lpds_irq_disable (mp_obj_t self_in) { wlan_obj_t *self = self_in; self->irq_enabled = false; } STATIC int wlan_irq_flags (mp_obj_t self_in) { wlan_obj_t *self = self_in; return self->irq_flags; } STATIC bool wlan_scan_result_is_unique (const mp_obj_list_t *nets, _u8 *bssid) { for (int i = 0; i < nets->len; i++) { // index 1 in the list is the bssid mp_obj_str_t *_bssid = (mp_obj_str_t *)((mp_obj_tuple_t *)nets->items[i])->items[1]; if (!memcmp (_bssid->data, bssid, SL_BSSID_LENGTH)) { return false; } } return true; } /******************************************************************************/ // Micro Python bindings; WLAN class /// \class WLAN - WiFi driver STATIC mp_obj_t wlan_init_helper(wlan_obj_t *self, const mp_arg_val_t *args) { // get the mode int8_t mode = args[0].u_int; wlan_validate_mode(mode); // get the ssid mp_uint_t ssid_len = 0; const char *ssid = NULL; if (args[1].u_obj != NULL) { ssid = mp_obj_str_get_data(args[1].u_obj, &ssid_len); wlan_validate_ssid_len(ssid_len); } // get the auth config uint8_t auth = SL_SEC_TYPE_OPEN; mp_uint_t key_len = 0; const char *key = NULL; if (args[2].u_obj != mp_const_none) { mp_obj_t *sec; mp_obj_get_array_fixed_n(args[2].u_obj, 2, &sec); auth = mp_obj_get_int(sec[0]); key = mp_obj_str_get_data(sec[1], &key_len); wlan_validate_security(auth, key, key_len); } // get the channel uint8_t channel = args[3].u_int; wlan_validate_channel(channel); // get the antenna type uint8_t antenna = args[4].u_int; #if MICROPY_HW_ANTENNA_DIVERSITY wlan_validate_antenna(antenna); #endif // initialize the wlan subsystem wlan_sl_init(mode, (const char *)ssid, ssid_len, auth, (const char *)key, key_len, channel, antenna, false); return mp_const_none; } STATIC const mp_arg_t wlan_init_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_mode, MP_ARG_INT, {.u_int = ROLE_STA} }, { MP_QSTR_ssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_antenna, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ANTENNA_TYPE_INTERNAL} }, }; STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) { // parse args mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); mp_arg_val_t args[MP_ARRAY_SIZE(wlan_init_args)]; mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), wlan_init_args, args); // setup the object wlan_obj_t *self = &wlan_obj; self->base.type = (mp_obj_t)&mod_network_nic_type_wlan; // give it to the sleep module pyb_sleep_set_wlan_obj(self); if (n_args > 1 || n_kw > 0) { // check the peripheral id if (args[0].u_int != 0) { mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // start the peripheral wlan_init_helper(self, &args[1]); } return (mp_obj_t)self; } STATIC mp_obj_t wlan_init(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) - 1]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &wlan_init_args[1], args); return wlan_init_helper(pos_args[0], args); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_init_obj, 1, wlan_init); STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { STATIC const qstr wlan_scan_info_fields[] = { MP_QSTR_ssid, MP_QSTR_bssid, MP_QSTR_sec, MP_QSTR_channel, MP_QSTR_rssi }; // check for correct wlan mode if (wlan_obj.mode == ROLE_AP) { mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } Sl_WlanNetworkEntry_t wlanEntry; mp_obj_t nets = mp_obj_new_list(0, NULL); uint8_t _index = 0; // trigger a new network scan uint32_t scanSeconds = MODWLAN_SCAN_PERIOD_S; ASSERT_ON_ERROR(sl_WlanPolicySet(SL_POLICY_SCAN , MODWLAN_SL_SCAN_ENABLE, (_u8 *)&scanSeconds, sizeof(scanSeconds))); // wait for the scan to complete mp_hal_delay_ms(MODWLAN_WAIT_FOR_SCAN_MS); do { if (sl_WlanGetNetworkList(_index++, 1, &wlanEntry) <= 0) { break; } // we must skip any duplicated results if (!wlan_scan_result_is_unique(nets, wlanEntry.bssid)) { continue; } mp_obj_t tuple[5]; tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false); tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH); // '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_const_none; tuple[4] = mp_obj_new_int(wlanEntry.rssi); // add the network to the list mp_obj_list_append(nets, mp_obj_new_attrtuple(wlan_scan_info_fields, 5, tuple)); } while (_index < MODWLAN_SL_MAX_NETWORKS); return nets; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan); 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, }, { MP_QSTR_auth, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; // check for the correct wlan mode if (wlan_obj.mode == ROLE_AP) { mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // 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 the ssid mp_uint_t ssid_len; const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len); wlan_validate_ssid_len(ssid_len); // get the auth config uint8_t auth = SL_SEC_TYPE_OPEN; mp_uint_t key_len = 0; const char *key = NULL; if (args[1].u_obj != mp_const_none) { mp_obj_t *sec; mp_obj_get_array_fixed_n(args[1].u_obj, 2, &sec); auth = mp_obj_get_int(sec[0]); key = mp_obj_str_get_data(sec[1], &key_len); wlan_validate_security(auth, key, key_len); // convert the wep key if needed if (auth == SL_SEC_TYPE_WEP) { _u8 wep_key[32]; wlan_wep_key_unhexlify(key, (char *)&wep_key); key = (const char *)&wep_key; key_len /= 2; } } // get the bssid const char *bssid = NULL; if (args[2].u_obj != mp_const_none) { bssid = mp_obj_str_get_str(args[2].u_obj); } // get the timeout int32_t timeout = -1; if (args[3].u_obj != mp_const_none) { timeout = mp_obj_get_int(args[3].u_obj); } // connect to the requested access point modwlan_Status_t status; status = wlan_do_connect (ssid, ssid_len, bssid, auth, key, key_len, timeout); if (status == MODWLAN_ERROR_TIMEOUT) { mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } else if (status == MODWLAN_ERROR_INVALID_PARAMS) { mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_connect_obj, 1, wlan_connect); STATIC mp_obj_t wlan_disconnect(mp_obj_t self_in) { wlan_sl_disconnect(); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_disconnect_obj, wlan_disconnect); STATIC mp_obj_t wlan_isconnected(mp_obj_t self_in) { return wlan_is_connected() ? mp_const_true : mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected); STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC const mp_arg_t wlan_ifconfig_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_config, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; // parse args mp_arg_val_t args[MP_ARRAY_SIZE(wlan_ifconfig_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), wlan_ifconfig_args, args); // check the interface id if (args[0].u_int != 0) { mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the configuration if (args[1].u_obj == MP_OBJ_NULL) { // get unsigned char len = sizeof(SlNetCfgIpV4Args_t); unsigned char dhcpIsOn; SlNetCfgIpV4Args_t ipV4; sl_NetCfgGet(SL_IPV4_STA_P2P_CL_GET_INFO, &dhcpIsOn, &len, (uint8_t *)&ipV4); mp_obj_t ifconfig[4] = { netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4, NETUTILS_LITTLE), netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4Mask, NETUTILS_LITTLE), netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4Gateway, NETUTILS_LITTLE), netutils_format_ipv4_addr((uint8_t *)&ipV4.ipV4DnsServer, NETUTILS_LITTLE) }; return mp_obj_new_tuple(4, ifconfig); } else { // set the configuration if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // set a static ip mp_obj_t *items; mp_obj_get_array_fixed_n(args[1].u_obj, 4, &items); SlNetCfgIpV4Args_t ipV4; netutils_parse_ipv4_addr(items[0], (uint8_t *)&ipV4.ipV4, NETUTILS_LITTLE); netutils_parse_ipv4_addr(items[1], (uint8_t *)&ipV4.ipV4Mask, NETUTILS_LITTLE); netutils_parse_ipv4_addr(items[2], (uint8_t *)&ipV4.ipV4Gateway, NETUTILS_LITTLE); netutils_parse_ipv4_addr(items[3], (uint8_t *)&ipV4.ipV4DnsServer, NETUTILS_LITTLE); if (wlan_obj.mode == ROLE_AP) { ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_AP_P2P_GO_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4)); SlNetAppDhcpServerBasicOpt_t dhcpParams; dhcpParams.lease_time = 4096; // lease time (in seconds) of the IP Address dhcpParams.ipv4_addr_start = ipV4.ipV4 + 1; // first IP Address for allocation. dhcpParams.ipv4_addr_last = (ipV4.ipV4 & 0xFFFFFF00) + 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 } else { ASSERT_ON_ERROR(sl_NetCfgSet(SL_IPV4_STA_P2P_CL_STATIC_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, sizeof(SlNetCfgIpV4Args_t), (_u8 *)&ipV4)); } } else { // check for the correct string const char *mode = mp_obj_str_get_str(args[1].u_obj); if (strcmp("dhcp", mode)) { mp_raise_ValueError(mpexception_value_invalid_arguments); } // only if we are not in AP mode if (wlan_obj.mode != ROLE_AP) { _u8 val = 1; sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE, IPCONFIG_MODE_ENABLE_IPV4, 1, &val); } } // config values have changed, so reset wlan_reset(); // set current time and date (needed to validate certificates) wlan_set_current_time (pyb_rtc_get_seconds()); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_ifconfig_obj, 1, wlan_ifconfig); STATIC mp_obj_t wlan_mode (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { return mp_obj_new_int(self->mode); } else { uint mode = mp_obj_get_int(args[1]); wlan_validate_mode(mode); wlan_set_mode(mode); wlan_reset(); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode); STATIC mp_obj_t wlan_ssid (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false); } else { mp_uint_t len; const char *ssid = mp_obj_str_get_data(args[1], &len); wlan_validate_ssid_len(len); wlan_set_ssid(ssid, len, false); wlan_reset(); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_ssid_obj, 1, 2, wlan_ssid); STATIC mp_obj_t wlan_auth (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { if (self->auth == SL_SEC_TYPE_OPEN) { return mp_const_none; } else { mp_obj_t security[2]; security[0] = mp_obj_new_int(self->auth); security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false); return mp_obj_new_tuple(2, security); } } else { // get the auth config uint8_t auth = SL_SEC_TYPE_OPEN; mp_uint_t key_len = 0; const char *key = NULL; if (args[1] != mp_const_none) { mp_obj_t *sec; mp_obj_get_array_fixed_n(args[1], 2, &sec); auth = mp_obj_get_int(sec[0]); key = mp_obj_str_get_data(sec[1], &key_len); wlan_validate_security(auth, key, key_len); } wlan_set_security(auth, key, key_len); wlan_reset(); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_auth_obj, 1, 2, wlan_auth); STATIC mp_obj_t wlan_channel (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { return mp_obj_new_int(self->channel); } else { uint8_t channel = mp_obj_get_int(args[1]); wlan_validate_channel(channel); wlan_set_channel(channel); wlan_reset(); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_channel_obj, 1, 2, wlan_channel); STATIC mp_obj_t wlan_antenna (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { return mp_obj_new_int(self->antenna); } else { #if MICROPY_HW_ANTENNA_DIVERSITY uint8_t antenna = mp_obj_get_int(args[1]); wlan_validate_antenna(antenna); wlan_set_antenna(antenna); #endif return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_antenna_obj, 1, 2, wlan_antenna); STATIC mp_obj_t wlan_mac (mp_uint_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { return mp_obj_new_bytes((const byte *)self->mac, SL_BSSID_LENGTH); } else { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { mp_raise_ValueError(mpexception_value_invalid_arguments); } memcpy(self->mac, bufinfo.buf, SL_MAC_ADDR_LEN); sl_NetCfgSet(SL_MAC_ADDRESS_SET, 1, SL_MAC_ADDR_LEN, (_u8 *)self->mac); wlan_reset(); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mac_obj, 1, 2, wlan_mac); STATIC mp_obj_t wlan_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_arg_val_t args[mp_irq_INIT_NUM_ARGS]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args); wlan_obj_t *self = pos_args[0]; // check the trigger, only one type is supported if (mp_obj_get_int(args[0].u_obj) != MODWLAN_WIFI_EVENT_ANY) { goto invalid_args; } // check the power mode if (mp_obj_get_int(args[3].u_obj) != PYB_PWR_MODE_LPDS) { goto invalid_args; } // create the callback mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &wlan_irq_methods); self->irq_obj = _irq; // enable the irq just before leaving wlan_lpds_irq_enable(self); return _irq; invalid_args: mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); //STATIC mp_obj_t wlan_connections (mp_obj_t self_in) { // mp_obj_t device[2]; // mp_obj_t connections = mp_obj_new_list(0, NULL); // // if (wlan_is_connected()) { // device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false); // device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH); // // add the device to the list // mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device)); // } // return connections; //} //STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_connections_obj, wlan_connections); //STATIC mp_obj_t wlan_urn (uint n_args, const mp_obj_t *args) { // char urn[MAX_DEVICE_URN_LEN]; // uint8_t len = MAX_DEVICE_URN_LEN; // // // an URN is given, so set it // if (n_args == 2) { // const char *p = mp_obj_str_get_str(args[1]); // uint8_t len = strlen(p); // // // the call to sl_NetAppSet corrupts the input string URN=args[1], so we copy into a local buffer // if (len > MAX_DEVICE_URN_LEN) { // mp_raise_ValueError(mpexception_value_invalid_arguments); // } // strcpy(urn, p); // // if (sl_NetAppSet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, len, (unsigned char *)urn) < 0) { // mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // } // else { // // get the URN // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { // mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // return mp_obj_new_str(urn, (len - 1), false); // } // // return mp_const_none; //} //STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_urn_obj, 1, 2, wlan_urn); STATIC const mp_map_elem_t wlan_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&wlan_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&wlan_scan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&wlan_connect_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_ifconfig), (mp_obj_t)&wlan_ifconfig_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mode), (mp_obj_t)&wlan_mode_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ssid), (mp_obj_t)&wlan_ssid_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_auth), (mp_obj_t)&wlan_auth_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&wlan_channel_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_antenna), (mp_obj_t)&wlan_antenna_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mac), (mp_obj_t)&wlan_mac_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&wlan_irq_obj }, // { MP_OBJ_NEW_QSTR(MP_QSTR_connections), (mp_obj_t)&wlan_connections_obj }, // { MP_OBJ_NEW_QSTR(MP_QSTR_urn), (mp_obj_t)&wlan_urn_obj }, // class constants { 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_WEP), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WEP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WPA), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(SL_SEC_TYPE_WPA_WPA2) }, { MP_OBJ_NEW_QSTR(MP_QSTR_INT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_INTERNAL) }, { MP_OBJ_NEW_QSTR(MP_QSTR_EXT_ANT), MP_OBJ_NEW_SMALL_INT(ANTENNA_TYPE_EXTERNAL) }, { MP_OBJ_NEW_QSTR(MP_QSTR_ANY_EVENT), MP_OBJ_NEW_SMALL_INT(MODWLAN_WIFI_EVENT_ANY) }, }; STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table); const mod_network_nic_type_t mod_network_nic_type_wlan = { .base = { { &mp_type_type }, .name = MP_QSTR_WLAN, .make_new = wlan_make_new, .locals_dict = (mp_obj_t)&wlan_locals_dict, }, }; STATIC const mp_irq_methods_t wlan_irq_methods = { .init = wlan_irq, .enable = wlan_lpds_irq_enable, .disable = wlan_lpds_irq_disable, .flags = wlan_irq_flags, }; /******************************************************************************/ // Micro Python bindings; WLAN socket int wlan_gethostbyname(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; out_ip[1] = ip >> 8; out_ip[2] = ip >> 16; out_ip[3] = ip >> 24; return result; } int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) { int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto); if (sd < 0) { *_errno = sd; return -1; } s->sock_base.sd = sd; return 0; } void wlan_socket_close(mod_network_socket_obj_t *s) { // this is to prevent the finalizer to close a socket that failed when being created if (s->sock_base.sd >= 0) { modusocket_socket_delete(s->sock_base.sd); sl_Close(s->sock_base.sd); s->sock_base.sd = -1; } } 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->sock_base.sd, &addr, sizeof(addr)); if (ret != 0) { *_errno = ret; return -1; } return 0; } int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) { int ret = sl_Listen(s->sock_base.sd, backlog); if (ret != 0) { *_errno = ret; return -1; } return 0; } 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); sd = sl_Accept(s->sock_base.sd, &addr, &addr_len); // save the socket descriptor s2->sock_base.sd = sd; if (sd < 0) { *_errno = sd; return -1; } // return ip and port UNPACK_SOCKADDR(addr, ip, *port); return 0; } 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->sock_base.sd, &addr, sizeof(addr)); if (ret != 0) { *_errno = ret; return -1; } return 0; } int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) { mp_int_t bytes = 0; if (len > 0) { bytes = sl_Send(s->sock_base.sd, (const void *)buf, len, 0); } if (bytes <= 0) { *_errno = bytes; return -1; } return bytes; } int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) { int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0); if (ret < 0) { *_errno = ret; return -1; } return ret; } 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->sock_base.sd, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr)); if (ret < 0) { *_errno = ret; return -1; } return ret; } 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->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len); if (ret < 0) { *_errno = ret; return -1; } UNPACK_SOCKADDR(addr, ip, *port); return ret; } int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen); if (ret < 0) { *_errno = ret; return -1; } return 0; } int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) { int ret; bool has_timeout; if (timeout_s == 0 || timeout_s == -1) { SlSockNonblocking_t option; if (timeout_s == 0) { // set non-blocking mode option.NonblockingEnabled = 1; } else { // set blocking mode option.NonblockingEnabled = 0; } ret = sl_SetSockOpt(s->sock_base.sd, SOL_SOCKET, SO_NONBLOCKING, &option, sizeof(option)); has_timeout = false; } else { // set timeout struct SlTimeval_t timeVal; timeVal.tv_sec = timeout_s; // seconds timeVal.tv_usec = 0; // microseconds. 10000 microseconds resolution ret = sl_SetSockOpt(s->sock_base.sd, SOL_SOCKET, SO_RCVTIMEO, &timeVal, sizeof(timeVal)); has_timeout = true; } if (ret != 0) { *_errno = ret; return -1; } s->sock_base.has_timeout = has_timeout; return 0; } 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_STREAM_POLL) { mp_uint_t flags = arg; ret = 0; int32_t sd = s->sock_base.sd; // init fds fd_set rfds, wfds, xfds; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); // set fds if needed if (flags & MP_STREAM_POLL_RD) { FD_SET(sd, &rfds); } if (flags & MP_STREAM_POLL_WR) { FD_SET(sd, &wfds); } if (flags & MP_STREAM_POLL_HUP) { FD_SET(sd, &xfds); } // call simplelink's 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 errors if (nfds == -1) { *_errno = nfds; return -1; } // check return of select if (FD_ISSET(sd, &rfds)) { ret |= MP_STREAM_POLL_RD; } if (FD_ISSET(sd, &wfds)) { ret |= MP_STREAM_POLL_WR; } if (FD_ISSET(sd, &xfds)) { ret |= MP_STREAM_POLL_HUP; } } else { *_errno = EINVAL; ret = MP_STREAM_ERROR; } return ret; }