2025-12-17 15:55:25 +08:00

4575 lines
138 KiB
C

/* -----------------------------------------------------------------------------
* Copyright (c) 2019 Arm Limited (or its affiliates). All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* $Date: 12. November 2019
* $Revision: V1.0
*
* Project: ESP8266 WiFi Driver
* Driver: Driver_WiFin (n = WIFI_ESP8266_DRIVER_NUMBER value)
* -------------------------------------------------------------------------- */
/* History:
* Version 1.0
* Initial version based on AT command set version: 1.6.2.0
*/
#include "WiFi_ESP8266.h"
#include "WiFi_ESP8266_Os.h"
/* Driver version */
#define ARM_WIFI_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 0)
/* -------------------------------------------------------------------------- */
/* Number of supported simultaneus connections */
#define WIFI_SOCKET_NUM 5
/* Array of sockets */
static WIFI_SOCKET Socket[WIFI_SOCKET_NUM];
/* Driver control block */
static WIFI_CTRL WIFI_Ctrl;
#define pCtrl (&WIFI_Ctrl)
/* Driver capabilities */
static const ARM_WIFI_CAPABILITIES DriverCapabilities = {
1U, /* station */
1U, /* ap */
1U, /* station_ap */
0U, /* wps_station */
0U, /* wps_ap */
1U, /* event_ap_connect */
1U, /* event_ap_disconnect */
0U, /* event_eth_rx_frame */
0U, /* bypass_mode */
1U, /* ip */
0U, /* ip6 */
1U, /* ping */
0U /* reserved */
};
/**
AT parser notify callback function.
\param[in] event Callback event code
\param[in] arg Event argument
*/
void AT_Notify (uint32_t event, void *arg) {
static uint8_t rx_sock;
static uint32_t rx_num;
uint32_t *u32;
uint8_t mac[6];
int32_t ex;
uint8_t n;
uint32_t conn_id, len;
uint32_t addr;
AT_DATA_LINK_CONN conn;
WIFI_SOCKET *sock;
uint32_t stat;
if (event == AT_NOTIFY_EXECUTE) {
/* Communication on-going, execute parser */
osThreadFlagsSet (pCtrl->thread_id, WIFI_THREAD_RX_DATA);
}
else if (event == AT_NOTIFY_TX_DONE) {
/* Transmit completed */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_TX_DONE);
}
else if (event == AT_NOTIFY_RESPONSE_GENERIC) {
/* Received generic command response */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_RESP_GENERIC);
}
else if (event == AT_NOTIFY_CONNECTION_RX_INIT) {
/* Data packet incomming (+IPD received) */
u32 = (uint32_t *)arg;
/* Initialize number of bytes to receive */
*u32 = 0U;
/* Initialize receiving socket and number of bytes to receive */
rx_sock = SOCKET_INVALID;
rx_num = 0U;
ex = AT_Resp_IPD (&conn_id, &len, NULL, NULL);
if (ex == 0) {
/* Find socket */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_CONNECTED) {
if (Socket[n].conn_id == conn_id) {
/* This is our socket */
break;
}
}
}
if (n != WIFI_SOCKET_NUM) {
/* Found corresponding socket */
sock = &Socket[n];
/* Check if there is enough memory to receive incomming packet */
rx_num = BufGetFree(&sock->mem);
if (rx_num >= (len + 2U)) {
/* Enough space, remember receiving socket */
rx_sock = n;
/* Set packet header (16-bit size) */
BufWrite ((uint8_t *)&len, 2U, &sock->mem);
/* Return number of bytes to receive */
*u32 = len;
}
/* Set number of bytes to copy (or dump) */
rx_num = len;
}
}
}
else if (event == AT_NOTIFY_CONNECTION_RX_DATA) {
/* Read source buffer address */
u32 = (uint32_t *)arg;
addr = *u32;
/* Copy received data */
if (rx_sock != SOCKET_INVALID) {
sock = &Socket[rx_sock];
/* Copy data */
len = BufCopy (&sock->mem, (BUF_LIST *)addr, rx_num);
}
else {
len = BufFlush (rx_num, (BUF_LIST *)addr);
}
rx_num -= len;
/* Return number of bytes left to receive */
*u32 = rx_num;
if (rx_sock != SOCKET_INVALID) {
/* All data received? */
if (rx_num == 0U) {
/* Set event flag */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_RX_DONE(rx_sock));
}
}
}
else if (event == AT_NOTIFY_REQUEST_TO_SEND) {
/* Received '>' character, device waits for data to transmit */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_TX_REQUEST);
}
else if (event == AT_NOTIFY_CONNECTION_OPEN) {
/* Connection is open */
if ((pCtrl->flags & WIFI_FLAGS_CONN_INFO_POOLING) == 0U) {
/* Retrieve connection properties (+LINK_CONN received) */
ex = AT_Resp_LinkConn (&stat, &conn);
if (ex == 0) {
/* Set connection id as used */
ConnId_Accept (conn.link_id);
if (conn.c_s == 1U) {
/* Device works as a server, put connection on the backlog */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_SERVER) {
/* Set pointer to server socket */
sock = &Socket[n];
/* Find available backlog socket */
do {
n = Socket[n].backlog;
if (Socket[n].state == SOCKET_STATE_LISTEN) {
/* Set connection id and change state */
Socket[n].conn_id = conn.link_id;
Socket[n].state = SOCKET_STATE_CONNECTED;
/* Copy local and remote port number */
Socket[n].l_port = conn.local_port;
Socket[n].r_port = conn.remote_port;
/* Copy remote ip */
memcpy (Socket[n].r_ip, conn.remote_ip, 4);
break;
}
}
while (Socket[n].backlog != sock->backlog);
break;
}
}
if (n != WIFI_SOCKET_NUM) {
/* Set event */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_CONN_ACCEPT);
}
}
else {
/* Device works as a client, find socket that initiated connection open */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_CONNECTREQ) {
/* Check connection id */
if (Socket[n].conn_id == conn.link_id) {
/* Copy local and remote port number */
Socket[n].l_port = conn.local_port;
Socket[n].r_port = conn.remote_port;
/* Copy remote ip */
memcpy (Socket[n].r_ip, conn.remote_ip, 4);
/* Socket is now connected */
Socket[n].state = SOCKET_STATE_CONNECTED;
break;
}
}
}
if (n != WIFI_SOCKET_NUM) {
/* Set event */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_CONN_OPEN(n));
}
}
}
}
else {
ex = AT_Resp_CtrlConn (&conn_id);
if (ex == 0) {
/* Set connection id as used */
ConnId_Accept (conn_id);
conn.link_id = (uint8_t)conn_id;
/* Check client sockets for initiated connection open (<link_id>,CONNECT received) */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_CONNECTREQ) {
/* Check connection id */
if (Socket[n].conn_id == conn.link_id) {
/* Socket is now connected */
Socket[n].state = SOCKET_STATE_CONNECTED;
break;
}
}
}
if (n != WIFI_SOCKET_NUM) {
/* Set event */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_CONN_OPEN(n));
}
else {
/* Check server sockets and put connection on the backlog */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_SERVER) {
/* Set pointer to server socket */
sock = &Socket[n];
/* Find available backlog socket */
do {
n = Socket[n].backlog;
if (Socket[n].state == SOCKET_STATE_LISTEN) {
/* Set connection id and change state */
Socket[n].conn_id = conn.link_id;
Socket[n].state = SOCKET_STATE_CONNECTED;
break;
}
}
while (Socket[n].backlog != sock->backlog);
break;
}
}
if (n != WIFI_SOCKET_NUM) {
/* Set event */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_CONN_ACCEPT);
}
}
}
}
}
else if (event == AT_NOTIFY_CONNECTION_CLOSED) {
/* Network connection is closed */
ex = AT_Resp_CtrlConn (&conn_id);
if (ex == 0) {
/* Set connection id as free */
ConnId_Free (conn_id);
/* Find corresponding socket and change its state */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].conn_id == conn_id) {
/* Correct connection id found */
Socket[n].conn_id = CONN_ID_INVALID;
if (Socket[n].backlog == SOCKET_INVALID) {
/* This is client socket */
if (Socket[n].state == SOCKET_STATE_CLOSING) {
/* Connection close initiated in SocketClose */
Socket[n].state = SOCKET_STATE_FREE;
} else {
/* Remote peer closed the connection */
Socket[n].state = SOCKET_STATE_CLOSED;
}
} else {
/* Listening socket, set state back to listen */
Socket[n].state = SOCKET_STATE_LISTEN;
}
break;
}
}
if (n != WIFI_SOCKET_NUM) {
/* Set event */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_CONN_CLOSE(n));
}
}
}
else if (event == AT_NOTIFY_STATION_CONNECTED) {
/* Station connects to the local AP */
ex = AT_Resp_StaMac (mac);
pCtrl->cb_event (ARM_WIFI_EVENT_AP_CONNECT, mac);
}
else if (event == AT_NOTIFY_STATION_DISCONNECTED) {
/* Station disconnects from the local AP */
ex = AT_Resp_StaMac (mac);
pCtrl->cb_event (ARM_WIFI_EVENT_AP_DISCONNECT, mac);
}
else if (event == AT_NOTIFY_CONNECTED) {
/* Local station connected to an AP */
pCtrl->flags |= WIFI_FLAGS_STATION_CONNECTED;
}
else if (event == AT_NOTIFY_GOT_IP) {
/* Local station got IP address */
pCtrl->flags |= WIFI_FLAGS_STATION_GOT_IP;
}
else if (event == AT_NOTIFY_DISCONNECTED) {
/* Local station disconnected from an AP */
pCtrl->flags &= ~(WIFI_FLAGS_STATION_CONNECTED | WIFI_FLAGS_STATION_GOT_IP);
}
else if (event == AT_NOTIFY_READY) {
/* AT firmware is ready */
osEventFlagsSet (pCtrl->evflags_id, WIFI_WAIT_RESP_GENERIC);
}
else if (event == AT_NOTIFY_ERR_CODE) {
/* Error code received */
ex = AT_Resp_ErrCode (&stat);
}
else {
/* Out of memory? */
if (event == AT_NOTIFY_OUT_OF_MEMORY) {
if (arg == NULL) {
/* Receiving socket is out of memory */
pCtrl->packdump++;
}
else {
/* Serial parser is out of memory */
__BKPT(0);
}
}
}
}
/**
Wait for response with timeout.
\return -2: no response, error
-1: no response, timeout
0: response arrived
*/
static int32_t WiFi_Wait (uint32_t event, uint32_t timeout) {
int32_t rval;
uint32_t flags;
flags = osEventFlagsWait (pCtrl->evflags_id, event, osFlagsWaitAny, timeout);
if ((flags & osFlagsError) == 0) {
/* Got response */
rval = 0;
}
else {
if (flags == osFlagsErrorTimeout) {
/* Timeout */
rval = -1;
}
else {
/* Internal error */
rval = -2;
}
}
return (rval);
}
/**
WIFI thread.
*/
void WiFi_Thread (void *arg) {
uint32_t flags;
uint32_t tout;
(void)arg;
if (AT_Parser_Initialize() != 0) {
/* Parser initialization failed */
osThreadTerminate (osThreadGetId());
}
/* Set wait timeout */
//tout = WIFI_THREAD_POOLING_TIMEOUT*10;
tout = osWaitForever;
while (1) {
/* Wait for thread flags until timeout expires */
flags = osThreadFlagsWait (WIFI_THREAD_FLAGS, osFlagsWaitAny, tout);
//osThreadFlagsClear(flags);
if ((flags & osFlagsError) == 0) {
if (flags & WIFI_THREAD_TERMINATE) {
/* Uninitialize data parser (low level) */
AT_Parser_Uninitialize ();
/* Self-terminate */
osThreadTerminate (osThreadGetId());
}
}
AT_Parser_Execute();
}
}
static void WiFi_ThreadKick (void) {
osThreadFlagsSet (pCtrl->thread_id, WIFI_THREAD_KICK);
}
/**
Get driver version.
\return \ref ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION ARM_WIFI_GetVersion (void) {
ARM_DRIVER_VERSION ver = { ARM_WIFI_API_VERSION, ARM_WIFI_DRV_VERSION };
return (ver);
}
/**
Get driver capabilities.
\return \ref ARM_WIFI_CAPABILITIES
*/
static ARM_WIFI_CAPABILITIES ARM_WIFI_GetCapabilities (void) {
return (DriverCapabilities);
}
/**
Initialize WiFi Module.
\param[in] cb_event Pointer to \ref ARM_WIFI_SignalEvent_t
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
*/
static int32_t ARM_WIFI_Initialize (ARM_WIFI_SignalEvent_t cb_event) {
int32_t rval;
osThreadAttr_t th_attr;
osEventFlagsAttr_t ef_attr;
osMutexAttr_t mtx_attr;
osMemoryPoolAttr_t mp_attr;
rval = ARM_DRIVER_OK;
/* Register callback event handler */
pCtrl->cb_event = cb_event;
if ((pCtrl->flags & WIFI_FLAGS_INIT) == 0U) {
/* Create required RTOS resources */
mp_attr = Socket_MemPool_Attr;
pCtrl->mempool_id = osMemoryPoolNew (SOCKET_BUFFER_BLOCK_COUNT, SOCKET_BUFFER_BLOCK_SIZE, &mp_attr);
/* Create event flags object */
ef_attr = WiFi_EventFlags_Attr;
pCtrl->evflags_id = osEventFlagsNew (&ef_attr);
/* Create socket access mutex */
mtx_attr = Socket_Mutex_Attr;
pCtrl->mutex_id = osMutexNew (&mtx_attr);
/* Create buffer access mutex */
mtx_attr = BufList_Mutex_Attr;
pCtrl->memmtx_id = osMutexNew (&mtx_attr);
if ((pCtrl->mempool_id == NULL) ||
(pCtrl->evflags_id == NULL) ||
(pCtrl->mutex_id == NULL) ||
(pCtrl->memmtx_id == NULL)) {
/* Failed to create all RTOS resources */
rval = ARM_DRIVER_ERROR;
}
if (rval == ARM_DRIVER_OK) {
/* Create WiFi thread */
th_attr = WiFi_Thread_Attr;
pCtrl->thread_id = osThreadNew (WiFi_Thread, NULL, &th_attr);
/* Thread should execute, initialize communication interface and wait blocked until waken-up */
if (osThreadGetState(pCtrl->thread_id) != osThreadBlocked) {
/* Incorrect thread state */
rval = ARM_DRIVER_ERROR;
}
}
if (rval != ARM_DRIVER_OK) {
/* Failed to initialize RTOS resources */
if (pCtrl->thread_id != NULL) {
/* Send termination flag */
osThreadFlagsSet (pCtrl->thread_id, WIFI_THREAD_TERMINATE);
}
/* Clean up */
if (pCtrl->mempool_id != NULL) {
(void)osMemoryPoolDelete (pCtrl->mempool_id);
}
if (pCtrl->evflags_id != NULL) {
(void)osEventFlagsDelete (pCtrl->evflags_id);
}
if (pCtrl->mutex_id != NULL) {
(void)osMutexDelete (pCtrl->mutex_id);
}
if (pCtrl->memmtx_id != NULL) {
(void)osMutexDelete (pCtrl->memmtx_id);
}
}
else {
/* Successfully initialized */
pCtrl->flags = WIFI_FLAGS_INIT;
}
}
return (rval);
}
/**
De-initialize WiFi Module.
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
*/
static int32_t ARM_WIFI_Uninitialize (void) {
int32_t rval;
uint32_t flags;
rval = ARM_DRIVER_OK;
if (pCtrl->thread_id != NULL) {
flags = osThreadFlagsSet (pCtrl->thread_id, WIFI_THREAD_TERMINATE);
if ((flags & osFlagsError) != 0U) {
/* Should never happen */
rval = ARM_DRIVER_ERROR;
}
}
if (pCtrl->evflags_id != NULL) {
if (osEventFlagsDelete (pCtrl->evflags_id) != osOK) {
/* Event flags delete failed */
rval = ARM_DRIVER_ERROR;
}
}
if (pCtrl->mutex_id != NULL) {
if (osMutexDelete (pCtrl->mutex_id) != osOK) {
/* Mutex delete failed */
rval = ARM_DRIVER_ERROR;
}
}
if (pCtrl->memmtx_id != NULL) {
if (osMutexDelete (pCtrl->memmtx_id) != osOK) {
/* Mutex delete failed */
rval = ARM_DRIVER_ERROR;
}
}
if (pCtrl->mempool_id != NULL) {
if (osMemoryPoolDelete (pCtrl->mempool_id) != osOK) {
/* Memory pool delete failed */
rval = ARM_DRIVER_ERROR;
}
}
if (rval == ARM_DRIVER_OK) {
/* Clear resource variables */
pCtrl->flags = 0U;
pCtrl->cb_event = NULL;
pCtrl->thread_id = NULL;
pCtrl->mutex_id = NULL;
}
return (rval);
}
/**
Control WiFi Module Power.
\param[in] state Power state
- \ref ARM_POWER_OFF : Power off: no operation possible
- \ref ARM_POWER_LOW : Low-power mode: sleep or deep-sleep depending on \ref ARM_WIFI_LP_TIMER option set
- \ref ARM_POWER_FULL : Power on: full operation at maximum performance
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid state)
*/
static int32_t ARM_WIFI_PowerControl (ARM_POWER_STATE state) {
int32_t rval, ex;
uint32_t n;
osThreadId_t id;
if ((state != ARM_POWER_OFF) && (state != ARM_POWER_FULL) && (state != ARM_POWER_LOW)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
switch (state) {
case ARM_POWER_OFF:
if ((pCtrl->flags & WIFI_FLAGS_INIT) == 0U) {
/* Not initialized */
rval = ARM_DRIVER_ERROR;
}
else {
/* Clear power flag */
pCtrl->flags &= ~WIFI_FLAGS_POWER;
rval = ARM_DRIVER_OK;
/* Check if we need to unlock socket mutex */
id = osMutexGetOwner(pCtrl->mutex_id);
if (id != NULL) {
/* Mutex is locked */
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* If we can't release the mutex, will recreate it */
if (osMutexDelete (pCtrl->mutex_id) != osOK) {
/* Mutex delete failed */
rval = ARM_DRIVER_ERROR;
}
else {
pCtrl->mutex_id = osMutexNew (&Socket_Mutex_Attr);
if (pCtrl->mutex_id == NULL) {
rval = ARM_DRIVER_ERROR;
}
}
}
}
/* Clear socket structures */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
Socket[n].state = SOCKET_STATE_FREE;
}
}
break;
case ARM_POWER_LOW:
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_POWER_FULL:
if ((pCtrl->flags & WIFI_FLAGS_INIT) == 0) {
/* Not initialized */
rval = ARM_DRIVER_ERROR-1;
}
else if ((pCtrl->flags & WIFI_FLAGS_POWER) != 0U) {
/* Already powered */
rval = ARM_DRIVER_OK;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR-2;
}
else {
/* Configure communication channel */
ex = SetupCommunication();
if (ex == 0) {
ex = ResetModule();
}
ex = SetupCommunication();
if (ex == 0) {
/* Enable station and AP */
ex = AT_Cmd_CurrentMode (AT_CMODE_SET, 3U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
}
}
}
if (ex == 0) {
/* Load current configuration */
ex = LoadOptions();
}
if (ex == 0) {
/* Enable station only */
ex = AT_Cmd_CurrentMode (AT_CMODE_SET, 1U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
}
}
}
if (ex == 0) {
/* Configure system messages */
ex = AT_Cmd_SysMessages (3U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
if (ex != 0) {
/* Reset error indicator */
ex = 0;
/* Enable connection info pooling (instead of +LINK_CONN info) */
pCtrl->flags |= WIFI_FLAGS_CONN_INFO_POOLING;
} else {
pCtrl->flags &= ~WIFI_FLAGS_CONN_INFO_POOLING;
}
}
}
}
if (ex == 0) {
/* Disable sleep */
ex = AT_Cmd_Sleep (AT_CMODE_SET, 0U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
if (ex == 0) {
/* Wait a bit before the next command is sent out */
osDelay(500);
}
}
}
}
if (ex == 0) {
/* Enable multiple connections */
ex = AT_Cmd_ConnectionMux (AT_CMODE_SET, 1U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
}
}
}
if (ex == 0) {
/* Command echo disable/enable */
ex = AT_Cmd_Echo (WIFI_AT_ECHO);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
}
}
}
if (ex == 0) {
/* Driver is powered */
pCtrl->flags |= WIFI_FLAGS_POWER;
/* No active connections */
pCtrl->conn_id = 0U;
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR-3;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR-4;
}
}
break;
}
}
return (rval);
}
/**
Get Module information.
\param[out] module_info Pointer to character buffer were info string will be returned
\param[in] max_len Maximum length of string to return (including null terminator)
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (NULL module_info pointer or max_len equals to 0)
*/
static int32_t ARM_WIFI_GetModuleInfo (char *module_info, uint32_t max_len) {
int32_t rval, ex;
if ((module_info == NULL) || (max_len == 0U)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
rval = ARM_DRIVER_OK;
ex = AT_Cmd_GetVersion();
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
ex = AT_Resp_GetVersion ((uint8_t *)module_info, max_len);
/* Add string terminator */
module_info[max_len-1] = '\0';
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Set WiFi Module Options.
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] option Option to set
\param[in] data Pointer to data relevant to selected option
\param[in] len Length of data (in bytes)
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface, NULL data pointer or len less than option specifies)
*/
static int32_t ARM_WIFI_SetOption (uint32_t interface, uint32_t option, const void *data, uint32_t len) {
int32_t rval, ex;
uint32_t u32;
uint8_t ip_0[4], ip_1[4];
if ((interface > 1U) || (data == NULL) || (len < 4U)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (pCtrl->flags == 0U) {
/* No init */
rval = ARM_DRIVER_ERROR;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
rval = ARM_DRIVER_ERROR;
ex = -1;
switch (option) {
default:
case ARM_WIFI_IP6_GLOBAL: // Station/AP Set/Get IPv6 global address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_LINK_LOCAL: // Station/AP Set/Get IPv6 link local address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_SUBNET_PREFIX_LEN: // Station/AP Set/Get IPv6 subnet prefix length; data = &len, len = 4, uint32_t: 1 .. 127
case ARM_WIFI_IP6_GATEWAY: // Station/AP Set/Get IPv6 gateway address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DNS1: // Station/AP Set/Get IPv6 primary DNS address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DNS2: // Station/AP Set/Get IPv6 secondary DNS address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DHCP_MODE: // Station/AP Set/Get IPv6 DHCPv6 client mode; data = &mode, len = 4, uint32_t: ARM_WIFI_IP6_DHCP_xxx (default Off)
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_BSSID: // Station/AP Set/Get BSSID of AP to connect or of AP; data = &bssid, len = 6, uint8_t[6]
if (len < 6) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
if (interface == WIFI_INTERFACE_STATION) {
/* Set BSSID of the AP to connect to */
memcpy (pCtrl->options.st_bssid, data, 6);
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
}
break;
case ARM_WIFI_TX_POWER: // Station/AP Set/Get transmit power; data = &power, len = 4, uint32_t: 0 .. 20 [dBm]
#if (AT_VARIANT == AT_VARIANT_WIZ)
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
#else
u32 = *(const uint32_t *)data;
/* Store value (see GetOption) */
pCtrl->tx_power = (uint8_t)u32;
/* Send command */
#if (AT_VARIANT == AT_VARIANT_ESP32) && (AT_VERSION < AT_VERSION_2_0_0_0)
ex = AT_Cmd_TxPower (10 - (u32/2U)); /* ESP32 */
#else
ex = AT_Cmd_TxPower (u32 * 4U);/* ESP8266, ESP32 V2.0.0 */
#endif
#endif
break;
case ARM_WIFI_LP_TIMER: // Station Set/Get low-power deep-sleep time; data = &time, len = 4, uint32_t [seconds]: 0 = disable (default)
if (interface != WIFI_INTERFACE_STATION) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else {
u32 = *(const uint32_t *)data;
pCtrl->lp_timer = u32;
rval = ARM_DRIVER_OK;
}
break;
case ARM_WIFI_DTIM: // Station/AP Set/Get DTIM interval; data = &dtim, len = 4, uint32_t [beacons]
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_BEACON: // AP Set/Get beacon interval; data = &interval, len = 4, uint32_t [ms]
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_MAC: // Station/AP Set/Get MAC; data = &mac, len = 6, uint8_t[6]
if (len < 6) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
if (interface == WIFI_INTERFACE_STATION) {
/* Set station MAC */
ex = AT_Cmd_StationMAC (AT_CMODE_SET, (const uint8_t *)data);
} else {
/* Set AP MAC */
memcpy (pCtrl->options.ap_mac, data, 6);
rval = ARM_DRIVER_OK;
}
}
break;
case ARM_WIFI_IP: // Station/AP Set/Get IPv4 static/assigned address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_SUBNET_MASK: // Station/AP Set/Get IPv4 subnet mask; data = &mask, len = 4, uint8_t[4]
case ARM_WIFI_IP_GATEWAY: // Station/AP Set/Get IPv4 gateway address; data = &ip, len = 4, uint8_t[4]
if (interface == WIFI_INTERFACE_STATION) {
if (option == ARM_WIFI_IP) { memcpy (pCtrl->options.st_ip, data, 4); }
else if (option == ARM_WIFI_IP_SUBNET_MASK) { memcpy (pCtrl->options.st_netmask, data, 4); }
else if (option == ARM_WIFI_IP_GATEWAY) { memcpy (pCtrl->options.st_gateway, data, 4); }
}
else {
if (option == ARM_WIFI_IP) { memcpy (pCtrl->options.ap_ip, data, 4); }
else if (option == ARM_WIFI_IP_SUBNET_MASK) { memcpy (pCtrl->options.ap_netmask, data, 4); }
else if (option == ARM_WIFI_IP_GATEWAY) { memcpy (pCtrl->options.ap_gateway, data, 4); }
}
rval = ARM_DRIVER_OK;
break;
case ARM_WIFI_IP_DNS1: // Station/AP Set/Get IPv4 primary DNS address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DNS2: // Station/AP Set/Get IPv4 secondary DNS address; data = &ip, len = 4, uint8_t[4]
ex = GetCurrentDnsAddr (interface, ip_0, ip_1);
if (ex == 0) {
if (option == ARM_WIFI_IP_DNS1) { memcpy (ip_0, data, 4); }
else { memcpy (ip_1, data, 4); }
ex = AT_Cmd_DNS (AT_CMODE_SET, 1, ip_0, ip_1);
}
break;
case ARM_WIFI_IP_DHCP: // Station/AP Set/Get IPv4 DHCP client/server enable/disable; data = &dhcp, len = 4, uint32_t: 0 = disable, non-zero = enable (default)
u32 = *(const uint32_t *)data;
if (interface == WIFI_INTERFACE_STATION) {
if (u32 == 0) {
/* Disable DHCP and use static IP configuration */
pCtrl->flags |= WIFI_FLAGS_STATION_STATIC_IP;
} else {
pCtrl->flags &= ~WIFI_FLAGS_STATION_STATIC_IP;
}
#if (AT_VARIANT == AT_VARIANT_ESP32)
ex = AT_Cmd_DHCP (AT_CMODE_SET, u32 != 0U, 1U);
#else
ex = AT_Cmd_DHCP (AT_CMODE_SET, 1U, u32 != 0U);
#endif
} else {
/* Set/Clear MSB bit as state flag in lease time */
if (u32 == 0) {
/* Disable DHCP */
pCtrl->flags |= WIFI_FLAGS_AP_STATIC_IP;
} else {
/* Enable DHCP */
pCtrl->flags &= ~WIFI_FLAGS_AP_STATIC_IP;
}
rval = ARM_DRIVER_OK;
}
break;
case ARM_WIFI_IP_DHCP_POOL_BEGIN: // AP Set/Get IPv4 DHCP pool begin address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_POOL_END: // AP Set/Get IPv4 DHCP pool end address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_LEASE_TIME: // AP Set/Get IPv4 DHCP lease time; data = &time, len = 4, uint32_t [seconds]
if (interface == WIFI_INTERFACE_STATION) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else {
if (option == ARM_WIFI_IP_DHCP_POOL_BEGIN) {
memcpy (pCtrl->options.ap_dhcp_pool_start, data, 4);
}
else if (option == ARM_WIFI_IP_DHCP_POOL_END) {
memcpy (pCtrl->options.ap_dhcp_pool_end, data, 4);
}
else /* option == ARM_WIFI_IP_DHCP_LEASE_TIME */ {
u32 = *(const uint32_t *)data;
pCtrl->options.ap_dhcp_lease = u32;
}
rval = ARM_DRIVER_OK;
}
break;
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
/* Operation completed successfully */
rval = ARM_DRIVER_OK;
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Get WiFi Module Options.
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] option Option to get
\param[out] data Pointer to memory where data for selected option will be returned
\param[in,out] len Pointer to length of data (input/output)
- input: maximum length of data that can be returned (in bytes)
- output: length of returned data (in bytes)
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface, NULL data or len pointer, or *len less than option specifies)
*/
static int32_t ARM_WIFI_GetOption (uint32_t interface, uint32_t option, void *data, uint32_t *len) {
uint32_t *pu32, u32;
uint8_t *pu8;
int32_t rval, ex;
uint8_t ip_0[4], ip_1[4];
if ((interface > 1U) || (data == NULL) || (*len < 4U)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (pCtrl->flags == 0U) {
/* No power */
rval = ARM_DRIVER_ERROR;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
rval = ARM_DRIVER_ERROR;
ex = -1;
switch (option) {
default:
case ARM_WIFI_IP6_GLOBAL: // Station/AP Set/Get IPv6 global address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_LINK_LOCAL: // Station/AP Set/Get IPv6 link local address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_SUBNET_PREFIX_LEN: // Station/AP Set/Get IPv6 subnet prefix length; data = &len, len = 4, uint32_t: 1 .. 127
case ARM_WIFI_IP6_GATEWAY: // Station/AP Set/Get IPv6 gateway address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DNS1: // Station/AP Set/Get IPv6 primary DNS address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DNS2: // Station/AP Set/Get IPv6 secondary DNS address; data = &ip6, len = 16, uint8_t[16]
case ARM_WIFI_IP6_DHCP_MODE: // Station/AP Set/Get IPv6 DHCPv6 client mode; data = &mode, len = 4, uint32_t: ARM_WIFI_IP6_DHCP_xxx (default Off)
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_BSSID: // Station/AP Set/Get BSSID of AP to connect or of AP; data = &bssid, len = 6, uint8_t[6]
if (*len < 6U) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
if (interface == WIFI_INTERFACE_STATION) {
pu8 = (uint8_t *)data;
/* Load output value */
memcpy (pu8, pCtrl->options.st_bssid, 6U);
*len = 6U;
/* Update return value */
rval = ARM_DRIVER_OK;
}
else {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
}
break;
case ARM_WIFI_TX_POWER: // Station/AP Set/Get transmit power; data = &power, len = 4, uint32_t: 0 .. 20 [dBm]
pu32 = (uint32_t *)data;
/* Load value from the control block */
*pu32 = pCtrl->tx_power;
*len = 4U;
/* Update return value */
rval = ARM_DRIVER_OK;
break;
case ARM_WIFI_LP_TIMER: // Station Set/Get low-power deep-sleep time; data = &time, len = 4, uint32_t [seconds]: 0 = disable (default)
if (interface != WIFI_INTERFACE_STATION) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else {
pu32 = (uint32_t *)data;
/* Load value from the control block */
*pu32 = pCtrl->lp_timer;
*len = 4U;
/* Update return value */
rval = ARM_DRIVER_OK;
}
break;
case ARM_WIFI_DTIM: // Station/AP Set/Get DTIM interval; data = &dtim, len = 4, uint32_t [beacons]
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_BEACON: // AP Set/Get beacon interval; data = &interval, len = 4, uint32_t [ms]
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
case ARM_WIFI_MAC: // Station/AP Set/Get MAC; data = &mac, len = 6, uint8_t[6]
if (*len < 6U) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
*len = 6U;
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Cmd_StationMAC (AT_CMODE_QUERY, NULL);
} else {
memcpy (data, pCtrl->options.ap_mac, 6U);
rval = ARM_DRIVER_OK;
}
}
break;
case ARM_WIFI_IP: // Station/AP Set/Get IPv4 static/assigned address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_SUBNET_MASK: // Station/AP Set/Get IPv4 subnet mask; data = &mask, len = 4, uint8_t[4]
case ARM_WIFI_IP_GATEWAY: // Station/AP Set/Get IPv4 gateway address; data = &ip, len = 4, uint8_t[4]
if (interface == WIFI_INTERFACE_STATION) {
pu8 = (uint8_t *)data;
if (option == ARM_WIFI_IP) { memcpy (data, pCtrl->options.st_ip, 4); }
else if (option == ARM_WIFI_IP_SUBNET_MASK) { memcpy (data, pCtrl->options.st_netmask, 4); }
else if (option == ARM_WIFI_IP_GATEWAY) { memcpy (data, pCtrl->options.st_gateway, 4); }
}
else {
pu8 = (uint8_t *)data;
if (option == ARM_WIFI_IP) { memcpy (pu8, pCtrl->options.ap_ip, 4); }
else if (option == ARM_WIFI_IP_GATEWAY) { memcpy (pu8, pCtrl->options.ap_gateway, 4); }
else { memcpy (pu8, pCtrl->options.ap_netmask, 4); }
}
/* Skip reading response */
ex = -1;
rval = ARM_DRIVER_OK;
break;
case ARM_WIFI_IP_DNS1: // Station/AP Set/Get IPv4 primary DNS address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DNS2: // Station/AP Set/Get IPv4 secondary DNS address; data = &ip, len = 4, uint8_t[4]
*len = 4U;
ex = GetCurrentDnsAddr (interface, ip_0, ip_1);
if (ex == 0) {
if (option == ARM_WIFI_IP_DNS1) { memcpy (data, ip_0, 4); }
else { memcpy (data, ip_1, 4); }
/* Skip reading response */
ex = -1;
rval = ARM_DRIVER_OK;
}
break;
case ARM_WIFI_IP_DHCP: // Station/AP Set/Get IPv4 DHCP client/server enable/disable; data = &dhcp, len = 4, uint32_t: 0 = disable, non-zero = enable (default)
*len = 4U;
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Cmd_DHCP (AT_CMODE_QUERY, 0U, 0U);
} else {
pu32 = (uint32_t *)data;
if ((pCtrl->flags & WIFI_FLAGS_AP_STATIC_IP) != 0U) {
/* Static IP flag is set, DHCP is disabled */
*pu32 = 0U;
} else {
/* DHCP is enabled */
*pu32 = 1U;
}
/* Skip reading response */
ex = -1;
rval = ARM_DRIVER_OK;
}
break;
case ARM_WIFI_IP_DHCP_POOL_BEGIN: // AP Set/Get IPv4 DHCP pool begin address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_POOL_END: // AP Set/Get IPv4 DHCP pool end address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_LEASE_TIME: // AP Set/Get IPv4 DHCP lease time; data = &time, len = 4, uint32_t [seconds]
*len = 4U;
if (interface == WIFI_INTERFACE_STATION) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else {
if (option == ARM_WIFI_IP_DHCP_POOL_BEGIN) {
memcpy (data, pCtrl->options.ap_dhcp_pool_start, 4);
}
else if (option == ARM_WIFI_IP_DHCP_POOL_END) {
memcpy (data, pCtrl->options.ap_dhcp_pool_end, 4);
}
else /* option == ARM_WIFI_IP_DHCP_LEASE_TIME */ {
pu32 = (uint32_t *)data;
*pu32 = pCtrl->options.ap_dhcp_lease;
}
/* Skip reading response */
ex = -1;
rval = ARM_DRIVER_OK;
}
break;
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
switch (option) {
default:
rval = ARM_DRIVER_ERROR;
break;
case ARM_WIFI_BSSID: // Station/AP Set/Get BSSID of AP to connect or of AP; data = &bssid, len = 6, uint8_t[6]
/* Read AP BSSID */
pu8 = (uint8_t *)data;
ex = AT_Resp_AccessPointMAC (pu8);
break;
case ARM_WIFI_MAC: // Station/AP Set/Get MAC; data = &mac, len = 6, uint8_t[6]
pu8 = (uint8_t *)data;
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Resp_StationMAC (pu8);
} else {
ex = AT_Resp_AccessPointMAC (pu8);
}
break;
case ARM_WIFI_IP_DHCP: // Station/AP Set/Get IPv4 DHCP client/server enable/disable; data = &dhcp, len = 4, uint32_t: 0 = disable, non-zero = enable (default)
pu32 = (uint32_t *)data;
ex = AT_Resp_DHCP (&u32);
if (ex == 0) {
#if (AT_VARIANT == AT_VARIANT_ESP32)
/* Keep bit 0 when station and bit 1 when AP (bit value 0=disabled, 1=enabled) */
if (interface == WIFI_INTERFACE_STATION) { u32 &= 1U; }
else { u32 >>= 1U; }
#else
/* Keep bit 0 when AP and bit 1 when station (bit value 0=disabled, 1=enabled) */
if (interface == WIFI_INTERFACE_STATION) { u32 >>= 1U; }
else { u32 &= 1U; }
#endif
*pu32 = u32;
}
break;
case ARM_WIFI_IP_DHCP_POOL_BEGIN: // AP Set/Get IPv4 DHCP pool begin address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_POOL_END: // AP Set/Get IPv4 DHCP pool end address; data = &ip, len = 4, uint8_t[4]
case ARM_WIFI_IP_DHCP_LEASE_TIME: // AP Set/Get IPv4 DHCP lease time; data = &time, len = 4, uint32_t [seconds]
pu8 = (uint8_t *)data;
pu32 = (uint32_t *)data;
if (interface == WIFI_INTERFACE_STATION) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else {
ex = AT_Resp_RangeDHCP (&u32, ip_0, ip_1);
if (ex == 0) {
if (option == ARM_WIFI_IP_DHCP_POOL_BEGIN) { memcpy (pu8, ip_0, 4); }
else if (option == ARM_WIFI_IP_DHCP_POOL_END) { memcpy (pu8, ip_1, 4); }
else /*option == ARM_WIFI_IP_DHCP_LEASE_TIME*/{ *pu32 = u32; }
}
}
break;
}
if (ex == 0) {
/* Operation completed successfully */
rval = ARM_DRIVER_OK;
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Scan for available networks in range.
\param[out] scan_info Pointer to array of ARM_WIFI_SCAN_INFO_t structures where available Scan Information will be returned
\param[in] max_num Maximum number of Network Information structures to return
\return number of ARM_WIFI_SCAN_INFO_t structures returned or error code
- value >= 0 : Number of ARM_WIFI_SCAN_INFO_t structures returned
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (NULL scan_info pointer or max_num equal to 0)
*/
static int32_t ARM_WIFI_Scan (ARM_WIFI_SCAN_INFO_t scan_info[], uint32_t max_num) {
int32_t rval, ex;
AT_DATA_CWLAP ap;
uint32_t i;
uint8_t ecn;
if ((scan_info == NULL) || (max_num == 0U)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
i = 0U;
/* Get the list of available access points */
ex = AT_Cmd_ListAP();
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 5*WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
do {
/* Response arrived */
ex = AT_Resp_ListAP (&ap);
if (ex >= 0) {
/* Return only requested number of structures (but all of them are read out) */
if (i < max_num) {
/* Extract info from CWLAP structure */
strcpy (scan_info[i].ssid, ap.ssid);
memcpy (scan_info[i].bssid, ap.mac, 6);
/* Translate encryption info */
switch (ap.ecn) {
case AT_DATA_ECN_OPEN: ecn = ARM_WIFI_SECURITY_OPEN; break;
case AT_DATA_ECN_WEP: ecn = ARM_WIFI_SECURITY_WEP; break;
case AT_DATA_ECN_WPA_PSK: ecn = ARM_WIFI_SECURITY_WPA; break;
case AT_DATA_ECN_WPA2_PSK:
case AT_DATA_ECN_WPA_WPA2_PSK: ecn = ARM_WIFI_SECURITY_WPA2; break;
default:
case AT_DATA_ECN_WPA2_E: ecn = ARM_WIFI_SECURITY_UNKNOWN; break;
}
scan_info[i].security = ecn;
scan_info[i].ch = ap.ch;
scan_info[i].rssi = (uint8_t)ap.rssi;
i++;
}
}
}
while (ex > 0);
}
}
if (ex == 0) {
/* Set the number of APs returned */
rval = (int32_t)i;
} else {
rval = ARM_DRIVER_ERROR;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Activate interface (Connect for Station interface or Start Access Point for Access Point interface).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] config Pointer to ARM_WIFI_CONFIG_t structure where Configuration parameters are located
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_TIMEOUT : Timeout occurred
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface, security type or NULL config pointer)
*/
static int32_t ARM_WIFI_Activate (uint32_t interface, const ARM_WIFI_CONFIG_t *config) {
int32_t ex, rval, state;
uint32_t mode;
AT_DATA_CWSAP ap_cfg;
uint8_t *ip_0, *ip_1, *ip_2;
if ((interface > 1U) || (config == NULL)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (config->wps_method != ARM_WIFI_WPS_METHOD_NONE) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else if ((config->ssid == NULL) || (config->pass == NULL)) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (config->security == ARM_WIFI_SECURITY_UNKNOWN) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (config->ch == 255U) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
rval = ARM_DRIVER_ERROR;
ex = -1;
if (interface == WIFI_INTERFACE_STATION) {
/* Copy relevant arguments */
/* Store AP password (can't retrieve it later on) */
memcpy (pCtrl->ap_pass, config->pass, 33);
/* Store encryption type */
pCtrl->ap_ecn = config->security;
if ((pCtrl->flags & WIFI_FLAGS_STATION_STATIC_IP) != 0) {
/* DHCP is disabled */
state = 0U;
}
else {
/* DHCP is enabled */
state = 1U;
}
/* Configure station DHCP */
ex = AT_Cmd_DHCP (AT_CMODE_SET, 1U, state);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
if (ex != AT_RESP_OK) {
state = 2U;
}
}
}
do {
switch(state) {
case 0:
/* Set ip, gateway and netmask */
ip_0 = pCtrl->options.st_ip;
ip_1 = pCtrl->options.st_gateway;
ip_2 = pCtrl->options.st_netmask;
ex = AT_Cmd_StationIP (AT_CMODE_SET, ip_0, ip_1, ip_2);
break;
case 1:
/* Connect to AP */
ex = AT_Cmd_ConnectAP (AT_CMODE_SET, config->ssid, config->pass, NULL);
break;
}
if (ex != AT_RESP_OK) {
/* Failed to send the command */
break;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 10*WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if ((ex != AT_RESP_OK) && (state == 1)) {
/* Find out the reason for error */
ex = AT_Resp_ConnectAP (NULL);
if (ex == 1) {
/* Connection timeout */
rval = ARM_DRIVER_ERROR_TIMEOUT;
}
else if (ex == 2) {
/* Wrong password */
rval = ARM_DRIVER_ERROR;
}
else if (ex == 3) {
/* Cannot find the target AP */
/* Wrong SSID? Is AP down? */
rval = ARM_DRIVER_ERROR;
}
else {
/* Invalid SSID? General error? */
rval = ARM_DRIVER_ERROR;
}
}
}
}
state++;
}
while (state < 2);
if (ex == AT_RESP_OK) {
pCtrl->flags |= WIFI_FLAGS_STATION_ACTIVE;
/* Check if auto connect to AP enabled */
ex = AT_Cmd_AutoConnectAP (AT_CMODE_QUERY, 0U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
/* Check enable status */
ex = AT_Resp_AutoConnectAP (&mode);
if (ex == 0) {
if (mode != 0U) {
/* Disable auto connect of local station to AP */
ex = AT_Cmd_AutoConnectAP(AT_CMODE_SET, 0U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Response arrived */
ex = AT_Resp_Generic();
}
}
}
}
}
}
}
if (ex == AT_RESP_OK) {
if ((pCtrl->flags & WIFI_FLAGS_STATION_STATIC_IP) == 0) {
/* DHCP is enabled */
ex = GetCurrentIpAddr (WIFI_INTERFACE_STATION, pCtrl->options.st_ip,
pCtrl->options.st_gateway,
pCtrl->options.st_netmask);
}
}
}
}
else /* interface == WIFI_INTERFACE_AP */ {
if (config->security == ARM_WIFI_SECURITY_WEP) {
/* WEP encryption method is not supported */
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else {
state = 0;
do {
switch (state) {
case 0:
/* Enable AP */
if ((pCtrl->flags & WIFI_FLAGS_STATION_ACTIVE) == 0) {
/* SoftAP + station */
mode = 2U;
} else {
/* SoftAP only */
mode = 3U;
}
ex = AT_Cmd_CurrentMode(AT_CMODE_SET, mode);
break;
case 1:
/* Setup parameters */
ap_cfg.ssid = (char *)(uint32_t)config->ssid;
ap_cfg.pwd = (char *)(uint32_t)config->pass;
if (config->ch != 0) {
/* Use specified channel */
ap_cfg.ch = config->ch;
} else {
/* Channel not specified, use default (must be nonzero) */
ap_cfg.ch = WIFI_AP_CHANNEL;
}
ap_cfg.ecn = config->security;
/* Optional parameters, set default values */
ap_cfg.max_conn = 8; //Set maximum supported
ap_cfg.ssid_hide = 0; //(0:default)
ex = AT_Cmd_ConfigureAP (AT_CMODE_SET, &ap_cfg);
break;
case 2:
/* Set access point MAC (must be different from station) */
ex = AT_Cmd_AccessPointMAC (AT_CMODE_SET, pCtrl->options.ap_mac);
break;
case 3:
/* Set network parameters (ip, netmask, gateway) */
ip_0 = pCtrl->options.ap_ip;
ip_1 = pCtrl->options.ap_gateway;
ip_2 = pCtrl->options.ap_netmask;
ex = AT_Cmd_AccessPointIP (AT_CMODE_SET, ip_0, ip_1, ip_2);
break;
case 4:
/* Configure DHCP pool */
if ((pCtrl->flags & WIFI_FLAGS_AP_STATIC_IP) == 0U) {
/* DHCP is enabled */
mode = 1U;
} else {
/* DHCP is disabled */
mode = 0U;
}
#if (AT_VARIANT == AT_VARIANT_ESP32)
ex = AT_Cmd_DHCP (AT_CMODE_SET, mode, 2U);
#else
ex = AT_Cmd_DHCP (AT_CMODE_SET, 0U, mode);
#endif
break;
case 5:
if ((pCtrl->flags & WIFI_FLAGS_AP_STATIC_IP) == 0U) {
/* Set DHCP pool lease time and pool start/end address */
mode = pCtrl->options.ap_dhcp_lease;
if (mode > 2880) {
/* Max lease time for AP is 2880 */
mode = 2880;
}
mode |= (1U << 16);
ip_0 = pCtrl->options.ap_dhcp_pool_start;
ip_1 = pCtrl->options.ap_dhcp_pool_end;
}
else {
/* Use default IP range */
mode = 0;
ip_0 = NULL;
ip_1 = NULL;
}
/* Set AP IP address range for the DHCP server */
/* (must be in the same network segment as IP of AP) */
ex = AT_Cmd_RangeDHCP (AT_CMODE_SET, mode, ip_0, ip_1);
break;
}
/* Check response */
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
}
}
/* Increment state to apply next option */
state++;
}
while (state < 6);
}
}
if (ex == AT_RESP_OK) {
/* Operation completed successfully */
rval = ARM_DRIVER_OK;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Deactivate interface (Disconnect for Station interface or Stop Access Point for Access Point interface).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface)
*/
static int32_t ARM_WIFI_Deactivate (uint32_t interface) {
int32_t rval, ex;
if (interface > 1U) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (pCtrl->flags == 0U) {
/* No power */
rval = ARM_DRIVER_ERROR;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
if (interface == WIFI_INTERFACE_STATION) {
/* Disconnect from current access point */
ex = AT_Cmd_DisconnectAP();
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == 0) {
/* OK, station disconnected */
pCtrl->flags &= ~WIFI_FLAGS_STATION_ACTIVE;
}
}
}
}
else /* interface == WIFI_INTERFACE_AP */ {
/* Set current mode, 1:station active */
ex = AT_Cmd_CurrentMode(AT_CMODE_SET, 1U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == 0) {
/* OK, access point stopped */
pCtrl->flags &= ~WIFI_FLAGS_AP_ACTIVE;
}
}
}
}
if (ex == 0) {
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/**
Get station connection status.
\return station connection status
- value != 0: Station connected
- value = 0: Station not connected
*/
static uint32_t ARM_WIFI_IsConnected (void) {
uint32_t conn;
uint32_t flags;
flags = pCtrl->flags & (WIFI_FLAGS_STATION_ACTIVE | WIFI_FLAGS_STATION_CONNECTED);
if (flags == (WIFI_FLAGS_STATION_ACTIVE | WIFI_FLAGS_STATION_CONNECTED)) {
conn = 1U;
} else {
conn = 0U;
}
return (conn);
}
/**
Get station Network Information.
\param[out] net_info Pointer to ARM_WIFI_NET_INFO_t structure where station Network Information will be returned
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed (station not connected)
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface or NULL net_info pointer)
*/
static int32_t ARM_WIFI_GetNetInfo (ARM_WIFI_NET_INFO_t *net_info) {
int32_t ex, rval;
AT_DATA_CWJAP ap;
if (net_info == NULL) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (pCtrl->flags == 0U) {
/* No power */
rval = ARM_DRIVER_ERROR;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
ex = AT_Cmd_ConnectAP(AT_CMODE_QUERY, NULL, NULL, NULL);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_ConnectAP (&ap);
if (ex == 0) {
/* Ensure that string is terminated */
ap.ssid[32] = '\0';
/* Copy ssid */
strcpy (net_info->ssid, ap.ssid);
/* Password is stored in control block */
pCtrl->ap_pass[32] = '\0';
strcpy (net_info->pass, pCtrl->ap_pass);
/* Encryption method is stored in control block */
net_info->security = pCtrl->ap_ecn;
/* Copy channel */
net_info->ch = ap.ch;
/* Convert rssi */
net_info->rssi = ap.rssi;
}
}
}
if (ex == 0) {
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
#if 0
/**
Enable or disable bypass (pass-through) mode. Transmit and receive Ethernet frames (IP layer bypassed and WiFi/Ethernet translation).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] mode
- value = 1: all packets bypass internal IP stack
- value = 0: all packets processed by internal IP stack
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface or mode)
*/
static int32_t ARM_WIFI_BypassControl (uint32_t interface, uint32_t mode) {
(void)interface;
(void)mode;
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
/**
Send Ethernet frame (in bypass mode only).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] frame Pointer to frame buffer with data to send
\param[in] len Frame buffer length in bytes
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_BUSY : Driver is busy
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface or NULL frame pointer)
*/
static int32_t ARM_WIFI_EthSendFrame (uint32_t interface, const uint8_t *frame, uint32_t len) {
(void)interface;
(void)frame;
(void)len;
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
/**
Read data of received Ethernet frame (in bypass mode only).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\param[in] frame Pointer to frame buffer for data to read into
\param[in] len Frame buffer length in bytes
\return number of data bytes read or error code
- value >= 0 : Number of data bytes read
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (invalid interface or NULL frame pointer)
*/
static int32_t ARM_WIFI_EthReadFrame (uint32_t interface, uint8_t *frame, uint32_t len) {
(void)interface;
(void)frame;
(void)len;
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
/**
Get size of received Ethernet frame (in bypass mode only).
\param[in] interface Interface (0 = Station, 1 = Access Point)
\return number of bytes in received frame
*/
static uint32_t ARM_WIFI_EthGetRxFrameSize (uint32_t interface) {
(void)interface;
return 0U;
}
#endif
/**
Create a communication socket.
\param[in] af Address family
\param[in] type Socket type
\param[in] protocol Socket protocol
\return status information
- Socket identification number (>=0)
- \ref ARM_SOCKET_EINVAL : Invalid argument
- \ref ARM_SOCKET_ENOTSUP : Operation not supported
- \ref ARM_SOCKET_ENOMEM : Not enough memory
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketCreate (int32_t af, int32_t type, int32_t protocol) {
int32_t rval;
int32_t n;
rval = 0;
/* Check Address Family */
if (af != ARM_SOCKET_AF_INET) {
if (af == ARM_SOCKET_AF_INET6) {
/* IPv6 socket in not supported */
rval = ARM_SOCKET_ENOTSUP;
} else {
rval = ARM_SOCKET_EINVAL;
}
}
else {
/* Check socket type and protocol */
if (type == ARM_SOCKET_SOCK_STREAM) {
/* TCP */
if (protocol != ARM_SOCKET_IPPROTO_TCP) {
rval = ARM_SOCKET_EINVAL;
}
}
else if (type == ARM_SOCKET_SOCK_DGRAM) {
/* UDP */
if (protocol != ARM_SOCKET_IPPROTO_UDP) {
rval = ARM_SOCKET_EINVAL;
}
}
else {
rval = ARM_SOCKET_EINVAL;
}
}
if (rval == 0) {
if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
/* Allocate socket (control block) */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_FREE) {
/* Found free socket, clear the socket structure */
memset (&Socket[n], 0x00, sizeof(WIFI_SOCKET));
/* Set initial state */
Socket[n].state = SOCKET_STATE_CREATED;
/* Set socket default parameters */
Socket[n].type = type;
Socket[n].protocol = protocol;
Socket[n].server = SOCKET_INVALID;
Socket[n].backlog = SOCKET_INVALID;
Socket[n].conn_id = CONN_ID_INVALID;
Socket[n].tout_rx = WIFI_SOCKET_RX_TIMEOUT;
Socket[n].tout_tx = WIFI_SOCKET_TX_TIMEOUT;
/* Setup socket memory */
BufInit (pCtrl->mempool_id, pCtrl->memmtx_id, &Socket[n].mem);
break;
}
}
if (n == WIFI_SOCKET_NUM) {
/* Not enough memory */
rval = ARM_SOCKET_ENOMEM;
}
else {
/* Return socket number */
rval = n;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
}
return (rval);
}
/**
Assign a local address to a socket.
\param[in] socket Socket identification number
\param[in] ip Pointer to local IP address
\param[in] ip_len Length of 'ip' address in bytes
\param[in] port Local port number
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (address or socket already bound)
- \ref ARM_SOCKET_EADDRINUSE : Address already in use
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketBind (int32_t socket, const uint8_t *ip, uint32_t ip_len, uint16_t port) {
int32_t rval;
uint32_t n;
uint32_t i;
WIFI_SOCKET *sock;
const uint8_t *ip_addr = ip;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((ip == NULL) || ((ip_len != 4U) && (ip_len != 16U))) {
/* Invalid IP address specification */
rval = ARM_SOCKET_EINVAL;
}
else if (port == 0U) {
/* Port zero is not allowed (no autobound) */
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
/* Socket is not created */
rval = ARM_SOCKET_ESOCK;
}
else if (sock->state == SOCKET_STATE_CONNECTED) {
/* Socket already connected */
rval = ARM_SOCKET_EISCONN;
}
else if (sock->state == SOCKET_STATE_BOUND) {
/* Socket already bound */
rval = ARM_SOCKET_EINVAL;
}
else {
/* Check if port already in use */
for (n = 0; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state >= SOCKET_STATE_BOUND) {
if (Socket[n].l_port == port) {
/* Port is already in use */
break;
}
}
}
if (n != WIFI_SOCKET_NUM) {
/* Port already used */
rval = ARM_SOCKET_EADDRINUSE;
}
else {
/* Copy local IP address */
for (i = 0U; i < ip_len; i++) {
sock->l_ip[i] = ip_addr[i];
}
/* Set local port and change state */
sock->l_port = port;
sock->state = SOCKET_STATE_BOUND;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Listen for socket connections.
\param[in] socket Socket identification number
\param[in] backlog Number of connection requests that can be queued
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (socket not bound)
- \ref ARM_SOCKET_ENOTSUP : Operation not supported
- \ref ARM_SOCKET_EISCONN : Socket is already connected
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketListen (int32_t socket, int32_t backlog) {
int32_t ex, rval;
uint8_t n;
WIFI_SOCKET *sock;
int32_t p, cnt;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((backlog <= 0) || (backlog >= WIFI_SOCKET_NUM)) {
/* Invalid backlog number (zero is not allowed) */
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->type != ARM_SOCKET_SOCK_STREAM) {
/* Not stream socket */
rval = ARM_SOCKET_ENOTSUP;
}
else if (sock->state == SOCKET_STATE_FREE) {
/* Socket not created */
rval = ARM_SOCKET_ESOCK;
}
else if (sock->state == SOCKET_STATE_SERVER) {
/* Socket already in server state */
rval = ARM_SOCKET_EINVAL;
}
else if (sock->state != SOCKET_STATE_BOUND) {
/* Not bound */
rval = ARM_SOCKET_EINVAL;
}
else {
/* Check if backlog can be created */
cnt = 0U;
/* Count number of free sockets */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_FREE) {
cnt++;
}
}
if (cnt < backlog) {
/* Backlog too large, not supported */
rval = ARM_SOCKET_ENOTSUP;
}
else {
/* Backlog can be created */
/* Limit number of TCP server connections */
ex = AT_Cmd_TcpServerMaxConn (AT_CMODE_SET, (uint32_t)backlog);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
}
}
if (ex == 0) {
/* Start TCP server */
ex = AT_Cmd_TcpServer (AT_CMODE_SET, 1U, sock->l_port);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
}
}
}
if (ex != 0) {
/* Unable to create TCP server */
rval = ARM_SOCKET_ERROR;
}
else {
/* Server successfully created */
sock->state = SOCKET_STATE_SERVER;
/* Create backlog */
cnt = backlog;
p = socket;
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].state == SOCKET_STATE_FREE) {
/* Connect socket to previous in backlog chain */
Socket[p].backlog = n;
/* Copy server socket structure */
memcpy (&Socket[n], sock, sizeof(WIFI_SOCKET));
/* Set socket state */
Socket[n].state = SOCKET_STATE_LISTEN;
/* Set server socket and backlog socket chain */
Socket[n].server = (uint8_t)socket;
Socket[n].backlog = sock->backlog;
p = n;
cnt--;
if (cnt == 0) {
break;
}
}
}
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Accept a new connection on a socket.
\param[in] socket Socket identification number
\param[out] ip Pointer to buffer where address of connecting socket shall be returned (NULL for none)
\param[in,out] ip_len Pointer to length of 'ip' (or NULL if 'ip' is NULL)
- length of supplied 'ip' on input
- length of stored 'ip' on output
\param[out] port Pointer to buffer where port of connecting socket shall be returned (NULL for none)
\return status information
- socket identification number of accepted socket (>=0)
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (socket not in listen mode)
- \ref ARM_SOCKET_ENOTSUP : Operation not supported (socket type does not support accepting connections)
- \ref ARM_SOCKET_ECONNRESET : Connection reset by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EAGAIN : Operation would block or timed out (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketAccept (int32_t socket, uint8_t *ip, uint32_t *ip_len, uint16_t *port) {
int32_t ex, rval;
int32_t n;
WIFI_SOCKET *sock;
AT_DATA_LINK_CONN conn;
WiFi_ThreadKick();
rval = ARM_SOCKET_ERROR;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((ip != NULL) && (ip_len == NULL)) {
/* IP is specified, but no length given */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip == NULL) && (ip_len != NULL)) {
/* IP not specified, but length is given */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (ip_len != NULL) && (*ip_len < 4U)) {
/* Specified IP is invalid */
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
/* Accept is not supported for UDP sockets */
rval = ARM_SOCKET_ENOTSUP;
}
else if (sock->state != SOCKET_STATE_SERVER) {
/* Socket is not server socket */
rval = ARM_SOCKET_ESOCK;
}
else {
do {
/* Check backlog for open connections */
n = sock->backlog;
if (Socket[n].state == SOCKET_STATE_CONNECTED) {
/* We have connection active */
if ((pCtrl->flags & WIFI_FLAGS_CONN_INFO_POOLING) != 0U) {
/* Pool for connection status, +LINK_CONN is not available */
ex = AT_Cmd_GetStatus (AT_CMODE_EXEC);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
do {
/* Response arrived */
ex = AT_Resp_GetStatus (&conn);
if (ex >= 0) {
/* Check if structure contains information relevant for current link id */
if (conn.link_id == Socket[n].conn_id) {
/* Copy remote ip */
memcpy (Socket[n].r_ip, conn.remote_ip, 4);
/* Set remote port */
Socket[n].r_port = conn.remote_port;
/* Set local port */
Socket[n].l_port = conn.local_port;
}
}
}
while (ex > 0);
}
}
}
if (ip != NULL) {
/* Copy remote ip */
*ip_len = 4U;
memcpy (ip, Socket[n].r_ip, 4);
}
if (port != NULL) {
/* Copy remote port */
*port = Socket[n].r_port;
}
/* Return socket number */
rval = n;
/* Update backlog, put current socket to the end of list */
while (Socket[n].backlog != sock->backlog) {
n = Socket[n].backlog;
}
Socket[n].backlog = (uint8_t)rval;
Socket[rval].backlog = sock->backlog;
}
else {
/* No connection to accept */
if (sock->flags & SOCKET_FLAGS_NONBLOCK) {
rval = ARM_SOCKET_EAGAIN;
}
else {
/* Wait until someone connects */
ex = WiFi_Wait (WIFI_WAIT_CONN_ACCEPT, WIFI_SOCKET_ACCEPT_TIMEOUT);
if (ex != 0) {
if (ex == -1) {
/* Timeout */
rval = ARM_SOCKET_EAGAIN;
}
else if (ex == -2) {
/* Error */
rval = ARM_SOCKET_ERROR;
}
break;
}
}
}
}
while (rval == ARM_SOCKET_ERROR);
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Connect a socket to a remote host.
\param[in] socket Socket identification number
\param[in] ip Pointer to remote IP address
\param[in] ip_len Length of 'ip' address in bytes
\param[in] port Remote port number
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument
- \ref ARM_SOCKET_EALREADY : Connection already in progress
- \ref ARM_SOCKET_EINPROGRESS : Operation in progress
- \ref ARM_SOCKET_EISCONN : Socket is connected
- \ref ARM_SOCKET_ECONNREFUSED : Connection rejected by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EADDRINUSE : Address already in use
- \ref ARM_SOCKET_ETIMEDOUT : Operation timed out
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketConnect (int32_t socket, const uint8_t *ip, uint32_t ip_len, uint16_t port,uint32_t mode) {
int32_t ex, rval;
WIFI_SOCKET *sock;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((ip == NULL) || ((ip_len != 4U) && (ip_len != 16U))) {
rval = ARM_SOCKET_EINVAL;
}
else if (port == 0U) {
/* Port zero is not allowed (no autobound) */
rval = ARM_SOCKET_EINVAL;
}
else if (ip_len != 4U) {
/* Only IPv4 is supported */
rval = ARM_SOCKET_ENOTSUP;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
/* Check if socket state is correct */
switch (sock->state) {
case SOCKET_STATE_FREE:
rval = ARM_SOCKET_ESOCK;
break;
case SOCKET_STATE_LISTEN:
case SOCKET_STATE_SERVER:
/* Invalid state */
rval = ARM_SOCKET_EINVAL;
break;
case SOCKET_STATE_CREATED:
case SOCKET_STATE_BOUND:
break;
case SOCKET_STATE_CONNECTREQ:
/* Connecting */
rval = ARM_SOCKET_EALREADY;
break;
case SOCKET_STATE_CONNECTED:
/* Already connected */
rval = ARM_SOCKET_EISCONN;
break;
case SOCKET_STATE_CLOSED:
/* Closed */
rval = ARM_SOCKET_ETIMEDOUT;
break;
default:
rval = ARM_SOCKET_ERROR;
break;
}
if (rval == 0) {
/* Copy remote ip and port */
memcpy (sock->r_ip, ip, 4);
sock->r_port = port;
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
/* Complete binding */
sock->state = SOCKET_STATE_BOUND;
}
else {
if (IsUnspecifiedIP (ip) != 0U) {
/* Uspecified address is not allowed */
rval = ARM_SOCKET_EINVAL;
}
else {
/* Initiate new TCP connection */
sock->state = SOCKET_STATE_CONNECTREQ;
/* Get free connection id */
sock->conn_id = ConnId_Alloc();
/* Open connection */
ex = AT_Cmd_ConnOpenTCP (AT_CMODE_SET, sock->conn_id, sock->r_ip, sock->r_port, 0U,mode);
if (ex != 0) {
/* Should not happen normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_CONNOPEN_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
rval = 0;
}
else if (ex == AT_RESP_ALREADY_CONNECTED) {
rval = ARM_SOCKET_EALREADY;
}
else {
if (ex == AT_RESP_ERROR) {
rval = ARM_SOCKET_ETIMEDOUT;
}
}
}
else {
rval = ARM_SOCKET_ERROR;
}
}
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
\fn int32_t ARM_WIFI_SocketRecv (int32_t socket, void *buf, uint32_t len)
\brief Receive data on a connected socket.
\param[in] socket Socket identification number
\param[out] buf Pointer to buffer where data should be stored
\param[in] len Length of buffer (in bytes)
\return status information
- number of bytes received (>0)
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ENOTCONN : Socket is not connected
- \ref ARM_SOCKET_ECONNRESET : Connection reset by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EAGAIN : Operation would block or timed out (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketRecv (int32_t socket, void *buf, uint32_t len) {
int32_t rval;
rval = ARM_WIFI_SocketRecvFrom (socket, buf, len, NULL, NULL, NULL);
return (rval);
}
/**
Receive data on a socket.
\param[in] socket Socket identification number
\param[out] buf Pointer to buffer where data should be stored
\param[in] len Length of buffer (in bytes)
\param[out] ip Pointer to buffer where remote source address shall be returned (NULL for none)
\param[in,out] ip_len Pointer to length of 'ip' (or NULL if 'ip' is NULL)
- length of supplied 'ip' on input
- length of stored 'ip' on output
\param[out] port Pointer to buffer where remote source port shall be returned (NULL for none)
\return status information
- number of bytes received (>0)
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ENOTCONN : Socket is not connected
- \ref ARM_SOCKET_ECONNRESET : Connection reset by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EAGAIN : Operation would block or timed out (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketRecvFrom (int32_t socket, void *buf, uint32_t len, uint8_t *ip, uint32_t *ip_len, uint16_t *port) {
int32_t ex, rval;
WIFI_SOCKET *sock;
uint8_t *pu8 = (uint8_t *)buf;
uint32_t n, cnt, num;
WiFi_ThreadKick();
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((buf == NULL) && (len != 0U)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (*ip_len < 4U)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
/* Check socket state */
switch (sock->state) {
case SOCKET_STATE_FREE:
rval = ARM_SOCKET_ESOCK;
break;
case SOCKET_STATE_CLOSING:
rval = ARM_SOCKET_EINVAL;
break;
case SOCKET_STATE_BOUND:
/* DGRAM socket must be bound */
if (sock->type != ARM_SOCKET_SOCK_DGRAM) {
/* Stream socket must be connected */
rval = ARM_SOCKET_ENOTCONN;
}
break;
case SOCKET_STATE_SERVER:
case SOCKET_STATE_CREATED:
case SOCKET_STATE_CONNECTREQ:
/* Connecting */
rval = ARM_SOCKET_ENOTCONN;
break;
case SOCKET_STATE_CONNECTED:
/* Connected */
break;
case SOCKET_STATE_CLOSED:
/* Closed */
if (BufGetCount(&sock->mem) > 0) {
break;
}
else {
rval = ARM_SOCKET_ECONNRESET;
}
break;
case SOCKET_STATE_LISTEN:
/* Listening */
if (BufGetCount(&sock->mem) > 0) {
break;
}
else {
rval = ARM_SOCKET_ENOTCONN;
}
break;
default:
rval = ARM_SOCKET_ERROR;
break;
}
if (rval == 0) {
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
/* Copy remote ip and port */
if (ip != NULL) {
memcpy (ip, sock->r_ip, 4); *ip_len = 4U;
}
if (port != NULL) {
*port = sock->r_port;
}
if (sock->state == SOCKET_STATE_BOUND) {
/* Start connection request */
sock->state = SOCKET_STATE_CONNECTREQ;
/* Get free connection id */
sock->conn_id = ConnId_Alloc();
/* Establish UDP connection */
ex = AT_Cmd_ConnOpenUDP (AT_CMODE_SET, sock->conn_id, sock->r_ip,
sock->r_port,
sock->l_port,
0U);
if (ex != 0) {
/* Should not happen normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex != 0) {
/* Response should arrive normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
rval = 0;
}
else if (ex == AT_RESP_ALREADY_CONNECTED) {
rval = ARM_SOCKET_EALREADY;
}
else {
rval = ARM_SOCKET_ERROR;
}
}
}
}
}
}
/* Initialize number of bytes read */
n = 0;
while (rval == 0) {
/* Read socket buffer */
if (sock->rx_len == 0) {
/* Read packet header */
if (BufGetCount (&sock->mem) >= 2U) {
/* Header is in the buffer */
if (BufRead ((uint8_t *)&sock->rx_len, 2U, &sock->mem) != 2U) {
/* Buffer error */
rval = ARM_SOCKET_ERROR;
}
}
}
if (sock->rx_len == 0) {
/* No data received */
if (sock->flags & SOCKET_FLAGS_NONBLOCK) {
/* Operation would block */
rval = ARM_SOCKET_EAGAIN;
}
else {
if (n != 0U) {
/* Received less than specified buffer length */
rval = (int32_t)n;
}
else {
/* Wait for socket data until timeout */
osMutexRelease (pCtrl->mutex_id);
ex = WiFi_Wait(WIFI_WAIT_RX_DONE(socket) | WIFI_WAIT_CONN_CLOSE(socket), sock->tout_rx);
osMutexAcquire (pCtrl->mutex_id, osWaitForever);
if (ex != 0) {
if (ex == -1) {
/* Timeout expired */
rval = ARM_SOCKET_EAGAIN;
}
else {
rval = ARM_SOCKET_ERROR;
}
}
if (sock->state != SOCKET_STATE_CONNECTED) {
rval = ARM_SOCKET_ECONNRESET;
}
}
}
}
else if ((sock->rx_len != 0) && (len == 0)) {
break;
}
else {
/* Receive data */
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
/* Datagram socket reads messages. If message is to large to fit into */
/* specified buffer, buffer is filled and the rest is flushed. */
if (len < sock->rx_len) {
cnt = len;
} else {
cnt = sock->rx_len;
}
/* Reduce cnt for number of bytes already read */
num = cnt - n;
n += (uint32_t)BufRead (&pu8[n], num, &sock->mem);
if (n != cnt) {
/* Message incomplete, wait for more data */
}
else {
/* Message read out, flush any leftovers */
if (n < sock->rx_len) {
BufFlush (sock->rx_len - n, &sock->mem);
}
/* Reload packet header */
sock->rx_len = 0U;
/* Return number of bytes read */
rval = (int32_t)n;
}
}
else {
/* Stream socket reads data continuously up to the buffer length or */
/* less if not enough data. */
cnt = len - n;
if (cnt > sock->rx_len) {
cnt = sock->rx_len;
}
cnt = (uint32_t)BufRead (&pu8[n], cnt, &sock->mem);
sock->rx_len -= cnt;
n += cnt;
if (n == len) {
/* Return number of bytes read */
rval = (int32_t)n;
}
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Send data on a connected socket.
\param[in] socket Socket identification number
\param[in] buf Pointer to buffer containing data to send
\param[in] len Length of data (in bytes)
\return status information
- number of bytes sent (>0)
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ENOTCONN : Socket is not connected
- \ref ARM_SOCKET_ECONNRESET : Connection reset by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EAGAIN : Operation would block or timed out (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketSend (int32_t socket, const void *buf, uint32_t len) {
int32_t rval;
rval = ARM_WIFI_SocketSendTo (socket, buf, len, NULL, 0U, 0U);
return (rval);
}
/**
Send data on a socket.
\param[in] socket Socket identification number
\param[in] buf Pointer to buffer containing data to send
\param[in] len Length of data (in bytes)
\param[in] ip Pointer to remote destination IP address
\param[in] ip_len Length of 'ip' address in bytes
\param[in] port Remote destination port number
\return status information
- number of bytes sent (>0)
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ENOTCONN : Socket is not connected
- \ref ARM_SOCKET_ECONNRESET : Connection reset by the peer
- \ref ARM_SOCKET_ECONNABORTED : Connection aborted locally
- \ref ARM_SOCKET_EAGAIN : Operation would block or timed out (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketSendTo (int32_t socket, const void *buf, uint32_t len, const uint8_t *ip, uint32_t ip_len, uint16_t port) {
int32_t ex, rval;
uint32_t num, cnt, n;
WIFI_SOCKET *sock;
const uint8_t *pu8 = (const uint8_t *)buf;
const uint8_t *r_ip = NULL;
uint16_t r_port = 0U;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((buf == NULL) && (len != 0U)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (ip_len > 4)) {
/* Invalid parameters */
rval = ARM_SOCKET_ENOTSUP;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
/* Socket not created */
rval = ARM_SOCKET_ESOCK;
}
else {
if (sock->type == ARM_SOCKET_SOCK_STREAM) {
/* Stream socket, ignore remote IP and port */
/* Check socket state */
switch (sock->state) {
case SOCKET_STATE_FREE:
rval = ARM_SOCKET_ESOCK;
break;
case SOCKET_STATE_CREATED:
case SOCKET_STATE_BOUND:
case SOCKET_STATE_LISTEN:
case SOCKET_STATE_CONNECTREQ:
case SOCKET_STATE_CLOSING:
case SOCKET_STATE_SERVER:
/* Socket is not connected */
rval = ARM_SOCKET_ENOTCONN;
break;
case SOCKET_STATE_CONNECTED:
/* Connected */
break;
case SOCKET_STATE_CLOSED:
/* Closed */
rval = ARM_SOCKET_ECONNRESET;
break;
default:
rval = ARM_SOCKET_ERROR;
break;
}
if (rval == 0) {
r_ip = NULL;
r_port = 0U;
}
}
else {
/* Datagram socket */
if (ip != NULL) {
/* Check if ip length is valid and correctly specified */
if (ip_len != 4U) {
rval = ARM_SOCKET_EINVAL;
}
else if (IsUnspecifiedIP (ip) != 0U) {
/* Unspecified address */
rval = ARM_SOCKET_EINVAL;
}
else if (port == 0) {
/* Invalid port number */
rval = ARM_SOCKET_EINVAL;
}
else {
/* Send UDP packet using specified IP address */
r_ip = ip;
r_port = port;
}
}
else {
/* IP is not provided */
/* Send UDP packet using IP address provided at SocketConnect */
r_ip = sock->r_ip;
r_port = sock->r_port;
if (sock->state != SOCKET_STATE_CONNECTED) {
/* If not already connected, check if connect was called previously */
if (sock->state != SOCKET_STATE_BOUND) {
/* Socket is "not connected" */
rval = ARM_SOCKET_ENOTCONN;
}
}
}
if (len >= 2048) {
/* If the message is too long to pass atomically through the underlying */
/* protocol, the error is returned and the message is not transmitted. */
rval = ARM_SOCKET_ENOMEM;
}
if (len > AT_Send_GetFree()) {
/* Message does not fit into buffer */
if (sock->flags & SOCKET_FLAGS_NONBLOCK) {
/* Nonblocking socket returns with error, message is not sent */
rval = ARM_SOCKET_EAGAIN;
}
}
if (rval == 0) {
if (sock->state != SOCKET_STATE_CONNECTED) {
/* Get free connection id */
sock->conn_id = ConnId_Alloc();
sock->state = SOCKET_STATE_CONNECTREQ;
/* Open connection */
ex = AT_Cmd_ConnOpenUDP (AT_CMODE_SET, sock->conn_id, r_ip,
r_port,
sock->l_port,
0U);
if (ex != 0) {
/* Should not happen normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex != 0) {
/* Response should arrive normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
rval = 0;
}
else if (ex == AT_RESP_ALREADY_CONNECTED) {
rval = ARM_SOCKET_EALREADY;
}
else {
rval = ARM_SOCKET_ERROR;
}
}
}
}
}
}
}
if (rval == 0) {
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
/* 1. Message length is less than MAX (2048 bytes) */
/* 2. For non-blocking socket, message can fit into buffer */
/* 3. For blocking socket, message might need to be sent using multiple AT_Send_Data calls */
if (len != 0) {
/* Initiate send operation */
ex = AT_Cmd_SendData (AT_CMODE_SET, sock->conn_id, len, r_ip, r_port);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_TX_REQUEST, WIFI_RESP_TIMEOUT);
}
if (ex != 0) {
/* Serial driver error or device not accepting data */
rval = ARM_SOCKET_ERROR;
}
else {
/* Start sending actual data to device */
/* Set number of bytes sent */
num = 0U;
while (num < len) {
/* Determine amount of data to send */
cnt = AT_Send_GetFree();
if (cnt == 0U) {
/* Tx buffer full, wait until tx buffer available */
ex = WiFi_Wait (WIFI_WAIT_TX_DONE, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Data transfer completed */
cnt = AT_Send_GetFree();
}
else {
/* Device internal error */
rval = ARM_SOCKET_ERROR;
break;
}
}
if (cnt > (len - num)) {
cnt = (len - num);
}
osEventFlagsClear (pCtrl->evflags_id, WIFI_WAIT_TX_DONE);
num += AT_Send_Data (&pu8[num], cnt);
}
/* Data sent, wait for SEND OK or SEND FAIL responses */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_SEND_OK) {
/* Packet sent, return number of bytes sent */
rval = (int32_t)num;
}
else if (ex == AT_RESP_SEND_FAIL) {
/* Send failed */
rval = ARM_SOCKET_ERROR;
}
else {
/* Should not happend */
rval = ARM_SOCKET_ERROR;
}
}
else {
/* No response? */
rval = ARM_SOCKET_ERROR;
}
}
}
}
else {
/* Stream socket */
/* 1. For non-blocking socket, we can send number of bytes that fit into tx buffer */
/* 2. For blocking socket, we can send 2048 in one pass, but fill tx buffer multiple times */
/* Set number of bytes sent */
num = 0U;
while (rval == 0) {
if ((len == 0) && (AT_Send_GetFree() != 0)) {
break;
}
/* Determine the amount of data to send */
else if (sock->flags & SOCKET_FLAGS_NONBLOCK) {
/* Non-blocking socket sends as much as fits into tx buffer */
cnt = AT_Send_GetFree();
}
else {
/* Blocking socket can send max 2048 bytes with one send command */
cnt = 2048;
}
if (cnt > len) {
cnt = len;
}
/* Initiate send operation */
ex = AT_Cmd_SendData (AT_CMODE_SET, sock->conn_id, cnt, r_ip, r_port);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_TX_REQUEST, WIFI_RESP_TIMEOUT);
}
if (ex != 0) {
/* Serial driver error or device not accepting data */
rval = ARM_SOCKET_ERROR;
}
else {
/* Start sending actual data to device */
while (cnt != 0) {
/* Determine amount of data to put into tx buffer */
n = AT_Send_GetFree();
if (n == 0U) {
/* Tx buffer full, wait until tx buffer available */
ex = WiFi_Wait (WIFI_WAIT_TX_DONE, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Data transfer completed */
n = AT_Send_GetFree();
}
else {
/* Device internal error */
rval = ARM_SOCKET_ERROR;
break;
}
}
if (n > cnt) {
n = cnt;
}
osEventFlagsClear (pCtrl->evflags_id, WIFI_WAIT_TX_DONE);
n = AT_Send_Data (&pu8[num], n);
num += n;
cnt -= n;
}
/* Data sent, wait for SEND OK or SEND FAIL responses */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_SEND_OK) {
/* Packet sent, return number of bytes sent */
if (sock->flags & SOCKET_FLAGS_NONBLOCK) {
rval = (int32_t)num;
}
else {
if (num == len) {
rval = (int32_t)num;
}
}
}
else if (ex == AT_RESP_SEND_FAIL) {
/* Send failed */
rval = ARM_SOCKET_ERROR;
}
else {
/* Should not happen */
rval = ARM_SOCKET_ERROR;
}
}
else {
/* No response? */
rval = ARM_SOCKET_ERROR;
}
}
}
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Retrieve local IP address and port of a socket.
\param[in] socket Socket identification number
\param[out] ip Pointer to buffer where local address shall be returned (NULL for none)
\param[in,out] ip_len Pointer to length of 'ip' (or NULL if 'ip' is NULL)
- length of supplied 'ip' on input
- length of stored 'ip' on output
\param[out] port Pointer to buffer where local port shall be returned (NULL for none)
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketGetSockName (int32_t socket, uint8_t *ip, uint32_t *ip_len, uint16_t *port) {
int32_t ex, rval;
WIFI_SOCKET *sock;
AT_DATA_LINK_CONN conn;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((ip != NULL) && (ip_len == NULL)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip_len != NULL) && (*ip_len < 4U)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (*ip_len >= 16U)) {
/* Only IPv4 is supported */
rval = ARM_SOCKET_ENOTSUP;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
rval = ARM_SOCKET_ESOCK;
}
else if (sock->state < SOCKET_STATE_BOUND) {
rval = ARM_SOCKET_EINVAL;
}
else {
if (sock->type == ARM_SOCKET_SOCK_DGRAM) {
if (sock->state == SOCKET_STATE_BOUND) {
/* Start connection request */
sock->state = SOCKET_STATE_CONNECTREQ;
/* Get free connection id */
sock->conn_id = ConnId_Alloc();
/* Establish UDP connection */
ex = AT_Cmd_ConnOpenUDP (AT_CMODE_SET, sock->conn_id, sock->r_ip,
sock->r_port,
sock->l_port,
0U);
if (ex != 0) {
/* Should not happen normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex != 0) {
/* Response should arrive normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Check response */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
rval = 0;
}
else if (ex == AT_RESP_ALREADY_CONNECTED) {
rval = ARM_SOCKET_EALREADY;
}
else {
rval = ARM_SOCKET_ERROR;
}
}
}
}
}
if (sock->state == SOCKET_STATE_CONNECTED) {
/* We have connection active */
if ((pCtrl->flags & WIFI_FLAGS_CONN_INFO_POOLING) != 0U) {
/* Pool for connection status, +LINK_CONN is not available */
ex = AT_Cmd_GetStatus (AT_CMODE_EXEC);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
do {
/* Response arrived */
ex = AT_Resp_GetStatus (&conn);
if (ex >= 0) {
/* Check if structure contains information relevant for current link id */
if (conn.link_id == sock->conn_id) {
/* Copy remote ip */
memcpy (sock->r_ip, conn.remote_ip, 4);
/* Set remote port */
sock->r_port = conn.remote_port;
/* Set local port */
sock->l_port = conn.local_port;
}
}
}
while (ex > 0);
}
}
}
}
if (ip != NULL) {
/* Set the length of the returned IP */
*ip_len = 4U;
/* Return socket local ip */
memcpy (ip, sock->l_ip, 4U);
}
if (port != NULL) {
/* Return socket local port */
*port = sock->l_port;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Retrieve remote IP address and port of a socket.
\param[in] socket Socket identification number
\param[out] ip Pointer to buffer where remote address shall be returned (NULL for none)
\param[in,out] ip_len Pointer to length of 'ip' (or NULL if 'ip' is NULL)
- length of supplied 'ip' on input
- length of stored 'ip' on output
\param[out] port Pointer to buffer where remote port shall be returned (NULL for none)
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument (pointer to buffer or length)
- \ref ARM_SOCKET_ENOTCONN : Socket is not connected
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketGetPeerName (int32_t socket, uint8_t *ip, uint32_t *ip_len, uint16_t *port) {
int32_t rval;
WIFI_SOCKET *sock;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((ip == NULL) && (ip_len != NULL)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (*ip_len < 4U)) {
/* Invalid parameters */
rval = ARM_SOCKET_EINVAL;
}
else if ((ip != NULL) && (*ip_len >= 16U)) {
/* Only IPv4 is supported */
rval = ARM_SOCKET_ENOTSUP;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->type == ARM_SOCKET_SOCK_STREAM) {
if (sock->state == SOCKET_STATE_FREE) {
rval = ARM_SOCKET_ESOCK;
}
else {
/* Stream socket must be connected */
if (sock->state != SOCKET_STATE_CONNECTED) {
/* Socket is not connected */
rval = ARM_SOCKET_ENOTCONN;
}
}
}
else {
/* Datagram socket should have r_ip and r_port set in SocketConnect */
if (sock->state == SOCKET_STATE_FREE) {
rval = ARM_SOCKET_ESOCK;
}
else if (sock->state != SOCKET_STATE_BOUND) {
rval = ARM_SOCKET_ENOTCONN;
}
else if (sock->r_port == 0) {
/* Port zero is not allowed (connect not called) */
rval = ARM_SOCKET_ENOTCONN;
}
else if (IsUnspecifiedIP (sock->r_ip) != 0U) {
/* Remote ip was not set (connect not called) */
rval = ARM_SOCKET_ENOTCONN;
}
}
if (rval == 0) {
/* Copy remote ip and port number */
if (ip != NULL) {
/* Set the length of the returned IP */
*ip_len = 4;
/* Return socket remote ip */
memcpy (ip, sock->r_ip, 4);
}
if (port != NULL) {
/* Return socket local port */
*port = sock->r_port;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Get socket option.
\param[in] socket Socket identification number
\param[in] opt_id Option identifier
\param[out] opt_val Pointer to the buffer that will receive the option value
\param[in,out] opt_len Pointer to length of the option value
- length of buffer on input
- length of data on output
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument
- \ref ARM_SOCKET_ENOTSUP : Operation not supported
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketGetOpt (int32_t socket, int32_t opt_id, void *opt_val, uint32_t *opt_len) {
int32_t rval;
WIFI_SOCKET *sock;
uint32_t val;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((opt_val == NULL) || (opt_len == NULL) || (*opt_len < 4U)) {
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
/* Invalid state */
rval = ARM_SOCKET_ESOCK;
}
else {
val = 0U;
switch (opt_id) {
case ARM_SOCKET_IO_FIONBIO:
/* Only set is allowed */
rval = ARM_SOCKET_EINVAL;
break;
case ARM_SOCKET_SO_RCVTIMEO:
/* Set receive timeout (in ms) */
val = sock->tout_rx;
break;
case ARM_SOCKET_SO_SNDTIMEO:
/* Set send timeout (in ms) */
val = sock->tout_tx;
break;
case ARM_SOCKET_SO_KEEPALIVE:
if ((sock->flags & SOCKET_FLAGS_KEEPALIVE) != 0) {
/* Keep-alive messages enabled */
val = 1U;
} else {
/* Keep-alive messages disabled */
val = 0U;
}
break;
case ARM_SOCKET_SO_TYPE:
/* Set socket type */
val = (uint32_t)sock->type;
break;
default:
rval = ARM_SOCKET_EINVAL;
break;
}
if (rval == 0) {
*opt_len = SetOpt (opt_val, val, 4);
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Set socket option.
\param[in] socket Socket identification number
\param[in] opt_id Option identifier
\param[in] opt_val Pointer to the option value
\param[in] opt_len Length of the option value in bytes
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EINVAL : Invalid argument
- \ref ARM_SOCKET_ENOTSUP : Operation not supported
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketSetOpt (int32_t socket, int32_t opt_id, const void *opt_val, uint32_t opt_len) {
int32_t rval;
WIFI_SOCKET *sock;
uint32_t val;
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if ((opt_val == NULL) || (opt_len == NULL) || (opt_len != 4U)) {
rval = ARM_SOCKET_EINVAL;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
/* Invalid state */
rval = ARM_SOCKET_ESOCK;
}
else {
/* Extract option value */
val = GetOpt (opt_val, opt_len);
switch (opt_id) {
case ARM_SOCKET_IO_FIONBIO:
if (val == 0U) {
/* Disable non-blocking mode */
sock->flags &= ~SOCKET_FLAGS_NONBLOCK;
} else {
/* Enable non-blocking mode */
sock->flags |= SOCKET_FLAGS_NONBLOCK;
}
break;
case ARM_SOCKET_SO_RCVTIMEO:
/* Set receive timeout (in ms) */
sock->tout_rx = val;
break;
case ARM_SOCKET_SO_SNDTIMEO:
/* Set send timeout (in ms) */
sock->tout_tx = val;
break;
case ARM_SOCKET_SO_KEEPALIVE:
if (val == 0U) {
/* Disable keep-alive messages */
sock->flags &=~ SOCKET_FLAGS_KEEPALIVE;
} else {
/* Enable keep-alive messages */
sock->flags |= SOCKET_FLAGS_KEEPALIVE;
}
break;
default:
rval = ARM_SOCKET_EINVAL;
break;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Close and release a socket.
\param[in] socket Socket identification number
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_ESOCK : Invalid socket
- \ref ARM_SOCKET_EAGAIN : Operation would block (may be called again)
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketClose (int32_t socket) {
int32_t ex, rval;
uint32_t n;
WIFI_SOCKET *sock;
WiFi_ThreadKick();
rval = 0;
if ((socket < 0) || (socket >= WIFI_SOCKET_NUM)) {
/* Invalid socket identification number */
rval = ARM_SOCKET_ESOCK;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
/* Check if close event already waiting in rx buffer */
WiFi_Wait (WIFI_WAIT_CONN_CLOSE(socket), 25);
sock = &Socket[socket];
if (sock->state == SOCKET_STATE_FREE) {
rval = ARM_SOCKET_ESOCK;
}
else if (sock->state == SOCKET_STATE_SERVER) {
/* Parent server socket, close all child sockets and disable server */
ex = AT_Cmd_TcpServer (AT_CMODE_SET, 0U, 0U);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
/* Connection closed */
sock->state = SOCKET_STATE_FREE;
}
}
}
if (ex == 0) {
/* Close all child sockets (backlog) */
for (n = 0U; n < WIFI_SOCKET_NUM; n++) {
if (Socket[n].server != SOCKET_INVALID) {
Socket[n].state = SOCKET_STATE_FREE;
Socket[n].server = SOCKET_INVALID;
Socket[n].backlog = SOCKET_INVALID;
}
}
}
}
else if ((sock->state == SOCKET_STATE_CLOSED) || (sock->state == SOCKET_STATE_CONNECTREQ)) {
/* Socket already closed or connect in progress */
if (sock->backlog == SOCKET_INVALID) {
/* Client socket, state is closed */
sock->state = SOCKET_STATE_FREE;
} else {
/* Listening socket, set state back to listen */
sock->state = SOCKET_STATE_LISTEN;
}
/* Free socket memory */
BufUninit (&sock->mem);
}
else {
/* Close client socket */
if ((sock->state > SOCKET_STATE_LISTEN) && (sock->state < SOCKET_STATE_CLOSING)) {
/* Set state to close initiated */
sock->state = SOCKET_STATE_CLOSING;
/* Close active connection */
ex = AT_Cmd_ConnectionClose (AT_CMODE_SET, sock->conn_id);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
/* Connection closed */
/* Free socket memory */
BufUninit (&sock->mem);
}
}
else {
/* No response */
rval = ARM_SOCKET_ERROR;
}
}
}
else {
/* Non-connected socket, just mark it as free */
sock->state = SOCKET_STATE_FREE;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Retrieve host IP address from host name.
\param[in] name Host name
\param[in] af Address family
\param[out] ip Pointer to buffer where resolved IP address shall be returned
\param[in,out] ip_len Pointer to length of 'ip'
- length of supplied 'ip' on input
- length of stored 'ip' on output
\return status information
- 0 : Operation successful
- \ref ARM_SOCKET_EINVAL : Invalid argument
- \ref ARM_SOCKET_ENOTSUP : Operation not supported
- \ref ARM_SOCKET_ETIMEDOUT : Operation timed out
- \ref ARM_SOCKET_EHOSTNOTFOUND : Host not found
- \ref ARM_SOCKET_ERROR : Unspecified error
*/
static int32_t ARM_WIFI_SocketGetHostByName (const char *name, int32_t af, uint8_t *ip, uint32_t *ip_len) {
int32_t ex, rval;
rval = 0;
if ((name == NULL) || (ip == NULL) || (ip_len == NULL) || (*ip_len < 4U)) {
rval = ARM_SOCKET_EINVAL;
}
else if ((af != ARM_SOCKET_AF_INET) && (af != ARM_SOCKET_AF_INET6)) {
rval = ARM_SOCKET_EINVAL;
}
else if (af == ARM_SOCKET_AF_INET6) {
rval = ARM_SOCKET_ENOTSUP;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_SOCKET_ERROR;
}
else {
ex = AT_Cmd_DnsFunction (AT_CMODE_SET, name);
if (ex != 0) {
/* Should not happend normally */
rval = ARM_SOCKET_ERROR;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 10*WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Generic ();
if (ex == AT_RESP_OK) {
*ip_len = 4U;
(void)AT_Resp_DnsFunction (ip);
}
else {
rval = ARM_SOCKET_EHOSTNOTFOUND;
}
}
else {
/* NOTE: need a proper way to handle timeout response */
rval = ARM_SOCKET_EHOSTNOTFOUND;
}
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_SOCKET_ERROR;
}
}
return (rval);
}
/**
Probe remote host with Ping command.
\param[in] ip Pointer to remote host IP address
\param[in] ip_len Length of 'ip' address in bytes
\return execution status
- \ref ARM_DRIVER_OK : Operation successful
- \ref ARM_DRIVER_ERROR : Operation failed
- \ref ARM_DRIVER_ERROR_TIMEOUT : Timeout occurred
- \ref ARM_DRIVER_ERROR_UNSUPPORTED : Operation not supported
- \ref ARM_DRIVER_ERROR_PARAMETER : Parameter error (NULL ip pointer or ip_len different than 4 or 16)
*/
static int32_t ARM_WIFI_Ping (const uint8_t *ip, uint32_t ip_len) {
int32_t ex, rval;
uint32_t val;
rval = ARM_DRIVER_OK;
if ((ip == NULL) || ((ip_len != 4U) && (ip_len != 16U))) {
rval = ARM_DRIVER_ERROR_PARAMETER;
}
else if (ip_len == 16U) {
rval = ARM_DRIVER_ERROR_UNSUPPORTED;
}
else if (osMutexAcquire (pCtrl->mutex_id, osWaitForever) != osOK) {
/* Mutex error */
rval = ARM_DRIVER_ERROR;
}
else {
ex = AT_Cmd_Ping (AT_CMODE_SET, ip, NULL);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_Ping (&val);
if (ex == 0) {
if ((val & 0x80000000) != 0) {
/* Ping timeout */
rval = ARM_DRIVER_ERROR_TIMEOUT;
}
}
}
}
if (ex != 0) {
rval = ARM_DRIVER_ERROR;
}
if (osMutexRelease (pCtrl->mutex_id) != osOK) {
/* Mutex error, override previous return value */
rval = ARM_DRIVER_ERROR;
}
}
return (rval);
}
/* Exported Driver_WiFi# */
ARM_DRIVER_WIFI ARM_Driver_WiFi_(WIFI_DRIVER_NUMBER) = {
ARM_WIFI_GetVersion,
ARM_WIFI_GetCapabilities,
ARM_WIFI_Initialize,
ARM_WIFI_Uninitialize,
ARM_WIFI_PowerControl,
ARM_WIFI_GetModuleInfo,
ARM_WIFI_SetOption,
ARM_WIFI_GetOption,
ARM_WIFI_Scan,
ARM_WIFI_Activate,
ARM_WIFI_Deactivate,
ARM_WIFI_IsConnected,
ARM_WIFI_GetNetInfo,
// ARM_WIFI_BypassControl,
// ARM_WIFI_EthSendFrame,
// ARM_WIFI_EthReadFrame,
// ARM_WIFI_EthGetRxFrameSize,
ARM_WIFI_SocketCreate,
ARM_WIFI_SocketBind,
ARM_WIFI_SocketListen,
ARM_WIFI_SocketAccept,
ARM_WIFI_SocketConnect,
ARM_WIFI_SocketRecv,
ARM_WIFI_SocketRecvFrom,
ARM_WIFI_SocketSend,
ARM_WIFI_SocketSendTo,
ARM_WIFI_SocketGetSockName,
ARM_WIFI_SocketGetPeerName,
ARM_WIFI_SocketGetOpt,
ARM_WIFI_SocketSetOpt,
ARM_WIFI_SocketClose,
ARM_WIFI_SocketGetHostByName,
ARM_WIFI_Ping
};
static int32_t ResetModule (void) {
int32_t rval, ex;
ex = AT_Cmd_Reset();
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 5000);
if (ex == 0) {
/* Response received */
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
/* Wait until response arrives */
/* Reset generates second response */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 5000);
if (ex == 0) {
/* Response received */
ex = AT_Resp_Generic();
if (ex == AT_RESP_READY) {
/* Successfully reset */
ex = 0;
}
}
}
}
}
if (ex == 0) {
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR;
}
return (rval);
}
static int32_t SetupCommunication (void) {
int32_t rval, ex;
int32_t state;
const uint32_t br[] = {WIFI_SERIAL_BAUDRATE, 115200, 57600, 38400, 19200, 9600};
const uint32_t set_br[] = {BAUD_115200, BAUD_115200, BAUD_57600, BAUD_38400, BAUD_19200, BAUD_9600};
uint32_t k;
ex = -1;
k = 0;
state = 0;
while (state < 4) {
switch (state) {
case 0:
case 3:
/* Select baudrate and reconfigure serial interface */
if(k == 0)
ex = AT_Parser_SetBaudrate (set_br[k]);
if (ex != 0) {
/* Error */
break;
}
/* Send test command (check if we will get a response) */
ex = AT_Cmd_TestAT();
break;
case 1:
/* Command echo disable/enable */
ex = AT_Cmd_Echo (WIFI_AT_ECHO);
break;
case 2:
/* Reconfigure UART */
ex = AT_Cmd_ConfigUART (AT_CMODE_SET, br[k], 8, (1<<4)|(0<<2)|(0));
break;
default:
ex = -1;
break;
}
if (ex != 0) {
/* Error, exit loop */
state = 4;
}
else {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, 1000);
if (ex != 0) {
/* No response, reconfigure and try again */
AT_Parser_Reset();
/* Try again */
state = 0;
/* Change baudrate */
k++;
if (k == (sizeof(br)/sizeof(br[0]))) {
/* Tried all baud rates, no response, exit loop */
state = 4;
}
}
else {
#if 1
/* Response received */
if (state != 0) {
ex = AT_Resp_Generic();
if (ex == AT_RESP_OK) {
if (state == 1) {
if (k != 0) {
/* Select configured baudrate */
k = 0;
}
else {
/* Already using high baud rate, skip reconfiguration */
state = 3;
}
}
}
}
#endif
/* Next step */
state++;
}
}
}
if (ex == 0) {
rval = ARM_DRIVER_OK;
} else {
rval = ARM_DRIVER_ERROR;
}
return (rval);
}
static int32_t LoadOptions (void) {
int32_t ex;
int32_t state;
int32_t n;
/* Set number of different states */
n = 4;
/* Set initial state */
ex = -1;
state = 0;
while (state < n) {
switch (state) {
case 0:
ex = GetCurrentIpAddr (WIFI_INTERFACE_STATION, pCtrl->options.st_ip,
pCtrl->options.st_gateway,
pCtrl->options.st_netmask);
break;
case 1:
ex = GetCurrentIpAddr (WIFI_INTERFACE_AP, pCtrl->options.ap_ip,
pCtrl->options.ap_gateway,
pCtrl->options.ap_netmask);
break;
case 2:
ex = GetCurrentMAC (WIFI_INTERFACE_AP, pCtrl->options.ap_mac);
break;
case 3:
ex = GetCurrentDhcpPool (&pCtrl->options.ap_dhcp_lease, pCtrl->options.ap_dhcp_pool_start,
pCtrl->options.ap_dhcp_pool_end);
break;
default:
ex = -1;
break;
}
if (ex != 0) {
/* Error, exit loop */
state = n;
}
else {
/* Load next option */
state++;
}
}
return (ex);
}
static int32_t IsUnspecifiedIP (const uint8_t ip[]) {
int32_t rval;
if ((ip[0] == 0U) && (ip[1] == 0U) && (ip[2] == 0U) && (ip[3] == 0U)) {
/* Unspecified IP address */
rval = 1U;
} else {
rval = 0U;
}
return (rval);
}
static int32_t GetCurrentMAC (uint32_t interface, uint8_t mac[]) {
int32_t ex;
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Cmd_StationMAC (AT_CMODE_QUERY, NULL);
} else {
ex = AT_Cmd_AccessPointMAC (AT_CMODE_QUERY, NULL);
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Resp_StationMAC (mac);
} else {
ex = AT_Resp_AccessPointMAC (mac);
}
}
}
return (ex);
}
static int32_t GetCurrentIpAddr (uint32_t interface, uint8_t ip[], uint8_t gw[], uint8_t mask[]) {
int32_t ex;
uint8_t *p;
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Cmd_StationIP (AT_CMODE_QUERY, NULL, NULL, NULL);
} else {
ex = AT_Cmd_AccessPointIP (AT_CMODE_QUERY, NULL, NULL, NULL);
}
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
p = ip;
do {
if (interface == WIFI_INTERFACE_STATION) {
ex = AT_Resp_StationIP (p);
} else {
ex = AT_Resp_AccessPointIP (p);
}
/* Set appropriate IP array */
if (p == ip) { p = gw; }
else { p = mask; }
}
while (ex == 1);
}
}
return (ex);
}
static int32_t GetCurrentDhcpPool (uint32_t *t_lease, uint8_t ip_start[], uint8_t ip_end[]) {
int32_t ex;
ex = AT_Cmd_RangeDHCP(AT_CMODE_QUERY, 0U, NULL, NULL);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
ex = AT_Resp_RangeDHCP (t_lease, ip_start, ip_end);
}
}
return (ex);
}
static int32_t GetCurrentDnsAddr (uint32_t interface, uint8_t dns0[], uint8_t dns1[]) {
int32_t ex;
uint8_t *p;
(void)interface; /* The same DNS is used for both interfaces */
ex = AT_Cmd_DNS (AT_CMODE_QUERY, 0, NULL, NULL);
if (ex == 0) {
/* Wait until response arrives */
ex = WiFi_Wait (WIFI_WAIT_RESP_GENERIC, WIFI_RESP_TIMEOUT);
if (ex == 0) {
/* Check response */
p = dns0;
#if (AT_VARIANT == AT_VARIANT_ESP32) && (AT_VERSION >= AT_VERSION_2_0_0_0)
ex = AT_Resp_DNS (NULL, p, dns1);
#else
do {
ex = AT_Resp_DNS (p);
/* Set appropriate IP array */
if (p == dns0) { p = dns1; }
else { p = NULL; }
}
while (ex == 1);
#endif
}
}
return (ex);
}
/*
Extract option value from specified address and with given length
opt_val: address of option value argument
opt_len: length of option value argument in bytes (max 4 bytes)
return: extracted value as uint32_t
*/
static uint32_t GetOpt (const void *opt_val, uint32_t opt_len) {
uint32_t val;
#ifdef __UNALIGNED_UINT32_READ
(void)opt_len;
val = __UNALIGNED_UINT32_READ(opt_val);
#else
uint32_t i, pos;
const uint8_t *p = opt_val;
pos = 0U;
val = 0U;
for (i = 0U; i < opt_len; i++) {
val |= (p[i] & 0xFFU) << pos;
pos += 8U;
}
#endif
return (val);
}
/*
Assign option value to variable at specified address
opt_val: address of option value variable
val: option value
opt_len: length of option value in bytes (max 4 bytes)
return: length of assigned value in bytes
*/
static uint32_t SetOpt (void *opt_val, uint32_t val, uint32_t opt_len) {
uint32_t len;
#ifdef __UNALIGNED_UINT32_WRITE
/* Write val into opt_val */
__UNALIGNED_UINT32_WRITE (opt_val, val);
len = opt_len;
#else
uint32_t pos;
uint8_t *p = opt_val;
pos = 0U;
for (len = 0U; len < opt_len; len++) {
p[len] = (val >> pos) & 0xFFU;
pos += 8U;
}
#endif
return (len);
}
/* Return free connection id */
static uint32_t ConnId_Alloc (void) {
uint32_t bit;
for (bit = 0; bit < CONN_ID_INVALID; bit++) {
if ((pCtrl->conn_id & (1U << bit)) == 0) {
break;
}
}
return (bit);
}
/* Clear flag, connection id is free to use */
static void ConnId_Free (uint32_t conn_id) {
pCtrl->conn_id &= ~(1U << conn_id);
}
/* Set flag, connection id is taken */
static void ConnId_Accept (uint32_t conn_id) {
pCtrl->conn_id |= (1U << conn_id);
}