4575 lines
138 KiB
C
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);
|
|
}
|