1514 lines
54 KiB
C
1514 lines
54 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "std.h"
|
|
|
|
#include "simplelink.h"
|
|
#include "py/ioctl.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_IOCTL_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_IOCTL_POLL_RD) {
|
|
FD_SET(sd, &rfds);
|
|
}
|
|
if (flags & MP_IOCTL_POLL_WR) {
|
|
FD_SET(sd, &wfds);
|
|
}
|
|
if (flags & MP_IOCTL_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_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 = MP_STREAM_ERROR;
|
|
}
|
|
return ret;
|
|
}
|