1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/atwinc15x0: support network scanning and dynamic connection

There are new pseudomodules for this driver:

- atwinc15x0_static_connect: Should behave as before, by trying to connect to an AP
by specified WIFI_SSIS and WIFI_PASS

- atwinc15x0_dynamic_connect: takes connection request via NETOPT_CONNECT
and provides the connection result via callback

- atwinc15x0_dynamic_scan: takes network scan requests via NETOPT_SCAN
and provides the scan result as a sorted list via callback
This commit is contained in:
Fabian Hüßler 2023-03-14 10:42:08 +01:00 committed by Fabian Hüßler
parent 7f2b214e47
commit 814d718d7b
6 changed files with 927 additions and 143 deletions

View File

@ -1,6 +1,18 @@
USEMODULE += netdev_eth
USEMODULE += ztimer_msec
USEMODULE += netdev_legacy_api
ifeq (,$(filter atwinc15x0_dynamic_%,$(USEMODULE)))
# use static connect by default when no dynamic module is loaded
USEMODULE += atwinc15x0_static_connect
endif
ifneq (,$(filter atwinc15x0_dynamic_scan,$(USEMODULE)))
USEMODULE += wifi_scan_list
endif
ifneq (,$(filter atwinc15x0_static_connect,$(USEMODULE)))
USEMODULE += ztimer
endif
USEPKG += driver_atwinc15x0
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_gpio_irq

View File

@ -1,2 +1,9 @@
USEMODULE_INCLUDES_atwinc15x0 := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_atwinc15x0)
# Try to connect to a preknown AP (WIFI_SSID, WIFI_PASS)
PSEUDOMODULES += atwinc15x0_static_connect
# Accept connection requests (NETOPT_CONNECT)
PSEUDOMODULES += atwinc15x0_dynamic_connect
# Accept scan requests (NETOPT_SCAN)
PSEUDOMODULES += atwinc15x0_dynamic_scan

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2020 Gunar Schorcht
* 2023 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -14,6 +15,7 @@
* @brief Netdev driver for the ATWINC15x0 WiFi module
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @author Fabian Hüßler <fabian.huessler@ml-pa.com>
*
* @}
*/
@ -29,11 +31,19 @@
#include "driver/source/m2m_hif.h"
#include "driver/include/m2m_wifi.h"
#include "thread.h"
#include "compiler_hints.h"
#include "assert.h"
#include "log.h"
#include "net/netopt.h"
#include "net/wifi.h"
#include "net/netdev/eth.h"
#include "net/netdev/wifi.h"
#include "net/wifi_scan_list.h"
#include "od.h"
#include "ztimer.h"
#include "string_utils.h"
#include "net/netif.h"
#define ENABLE_DEBUG 0
#define ENABLE_DEBUG_DUMP 0
@ -47,20 +57,20 @@
#define ATWINC15X0_WAIT_RECONNECT_MS (5000)
/**
* @brief Don't perform operations that would wake the device from sleep
* @brief Maximum number of scan list entries to deliver
*/
#define _CHECK_SLEEP_STATE(dev) do { \
if (dev->state != NETOPT_STATE_IDLE) { \
return -EBUSY; \
} \
} while (0)
#define ATWINC15X0_SCAN_LIST_NUMOF CONFIG_ATWINC15X0_SCAN_LIST_NUMOF
/* Forward function declarations */
static void _atwinc15x0_wifi_cb(uint8_t event, void *msg);
static void _atwinc15x0_eth_cb(uint8_t type, void *msg, void *ctrl);
static int _atwinc15x0_connect(void);
static int _atwinc15x0_connect(const wifi_connect_request_t *req);
static int _atwinc15x0_disconnect(const wifi_disconnect_request_t *req);
static int _atwinc15x0_scan(const wifi_scan_request_t *req);
static int _atwinc15x0_init(netdev_t *netdev);
static int _set_state(atwinc15x0_t *dev, netopt_state_t state);
static netopt_state_t _get_state(const atwinc15x0_t *dev);
static void _atwinc15x0_isr(netdev_t *netdev);
/**
* The following buffer is required by the ATWINC15x0 vendor driver to store
@ -104,6 +114,175 @@ static tstrWifiInitParam atwinc15x0_wifi_params = {
*/
atwinc15x0_t *atwinc15x0 = NULL;
MAYBE_UNUSED
static struct {
wifi_scan_list_t head;
wifi_scan_list_node_t array[ATWINC15X0_SCAN_LIST_NUMOF];
} _atwinc15x0_scan_list;
static inline void _wifi_scan_list_empty(void)
{
#if IS_USED(MODULE_WIFI_SCAN_LIST)
wifi_scan_list_empty(&_atwinc15x0_scan_list.head,
_atwinc15x0_scan_list.array,
ARRAY_SIZE(_atwinc15x0_scan_list.array));
#endif
}
static inline void _wifi_scan_list_insert(const wifi_scan_result_t *result)
{
(void)result;
#if IS_USED(MODULE_WIFI_SCAN_LIST)
wifi_scan_list_insert(&_atwinc15x0_scan_list.head,
_atwinc15x0_scan_list.array,
ARRAY_SIZE(_atwinc15x0_scan_list.array),
result);
#endif
}
MAYBE_UNUSED
static wifi_scan_request_t _atwinc15x0_scan_req;
static inline void _wifi_scan_result_callback(const wifi_scan_list_t *scan_list)
{
if (_atwinc15x0_scan_req.base.scan_cb) {
void *netif = netif_get_by_id(thread_getpid());
((wifi_on_scan_result_t)_atwinc15x0_scan_req.base.scan_cb)(netif,
scan_list);
}
_atwinc15x0_scan_req.base.scan_cb = NULL;
}
/**
* @brief Internal next timeout type
*/
typedef enum {
/**
* @brief No / clear timeout
*/
ATWINC15X0_WIFI_STA_TIMEOUT_NONE = 0,
/**
* @brief Timeout to reconnect to
*/
ATWINC15X0_WIFI_STA_TIMEOUT_RECONNECT,
} atwinc15x0_wifi_sta_timeout_t;
MAYBE_UNUSED
static union {
wifi_disconnect_request_t disconn_req;
wifi_connect_request_t conn_req;
} _atwinc15x0_connect_req;
static inline void _wifi_connect_result_callback(const wifi_connect_result_t *result)
{
if (_atwinc15x0_connect_req.conn_req.base.conn_cb) {
void *netif = netif_get_by_id(thread_getpid());
((wifi_on_connect_result_t)_atwinc15x0_connect_req.conn_req.base.conn_cb)(netif,
result);
}
_atwinc15x0_connect_req.conn_req.base.conn_cb = NULL;
/* _atwinc15x0_connect_req.conn_req.base.disconn_cb is called when connection is lost */
}
static inline void _wifi_disconnect_result_callback(const wifi_disconnect_result_t *result)
{
if (_atwinc15x0_connect_req.conn_req.base.disconn_cb) {
void *netif = netif_get_by_id(thread_getpid());
((wifi_on_disconnect_result_t)_atwinc15x0_connect_req.conn_req.base.disconn_cb)(netif,
result);
}
_atwinc15x0_connect_req.conn_req.base.conn_cb = NULL;
_atwinc15x0_connect_req.conn_req.base.disconn_cb = NULL;
}
MAYBE_UNUSED
static struct {
atwinc15x0_wifi_sta_timeout_t timeout;
ztimer_t timer;
} _atwinc15x0_timer;
static void _atwinc15x0_reconnect_timer(void *arg)
{
(void)arg;
_atwinc15x0_timer.timeout = ATWINC15X0_WIFI_STA_TIMEOUT_RECONNECT;
_atwinc15x0_timer.timer.callback = NULL;
atwinc15x0_irq();
}
static void _atwinc15x0_set_timer(void *arg, ztimer_callback_t cb, uint32_t timeout)
{
ztimer_remove(ZTIMER_MSEC, &_atwinc15x0_timer.timer);
_atwinc15x0_timer.timer.arg = arg;
_atwinc15x0_timer.timer.callback = cb;
ztimer_set(ZTIMER_MSEC, &_atwinc15x0_timer.timer, timeout);
}
static inline void _atwinc15x0_set_reconnect_timer(void)
{
_atwinc15x0_set_timer(NULL, _atwinc15x0_reconnect_timer, ATWINC15X0_WAIT_RECONNECT_MS);
}
static int _atwinc15x0_static_connect(void)
{
if (!IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
return 0;
}
tuniM2MWifiAuth auth_info;
tenuM2mSecType auth_type = M2M_WIFI_SEC_OPEN;
if (_atwinc15x0_is_busy(atwinc15x0)) {
return -EBUSY;
}
if (_atwinc15x0_is_connected(atwinc15x0)) {
return -EALREADY;
}
if (_atwinc15x0_is_sleeping(atwinc15x0)) {
return -ECANCELED;
}
#if !defined(MODULE_WIFI_ENTERPRISE) && defined(WIFI_PASS)
strncpy((char *)auth_info.au8PSK, WIFI_PASS, M2M_MAX_PSK_LEN);
auth_type = M2M_WIFI_SEC_WPA_PSK;
#elif defined(MODULE_WIFI_ENTERPRISE)
#if defined(WIFI_USER) && defined(WIFI_PASS)
strncpy((char *)&auth_info.strCred1x.au8UserName, WIFI_USER, M2M_1X_USR_NAME_MAX);
strncpy((char *)&auth_info.strCred1x.au8Passwd, WIFI_PASS, M2M_1X_PWD_MAX);
auth_type = M2M_WIFI_SEC_802_1X;
#else /* defined(WIFI_USER) && defined(WIFI_PASS) */
#error WIFI_EAP_USER and WIFI_EAP_PASS have to define the user name \
and the password for EAP phase 2 authentication in wifi_enterprise
#endif /* defined(WIFI_USER) && defined(WIFI_PASS) */
#endif /* defined(MODULE_WIFI_ENTERPRISE) */
/* connect */
int8_t res;
if ((res = m2m_wifi_connect(WIFI_SSID, sizeof(WIFI_SSID),
auth_type, &auth_info,
M2M_WIFI_CH_ALL)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi connect failed with %d\n", res);
return -EIO;
}
_atwinc15x0_set_connecting(atwinc15x0);
return 0;
}
static inline int _atwinc15x0_get_sec_mode(tenuM2mSecType mode)
{
switch (mode) {
case M2M_WIFI_SEC_OPEN:
return WIFI_SECURITY_MODE_OPEN;
case M2M_WIFI_SEC_WPA_PSK:
return WIFI_SECURITY_MODE_WPA2_PERSONAL;
case M2M_WIFI_SEC_WEP:
return WIFI_SECURITY_MODE_WEP_PSK;
case M2M_WIFI_SEC_802_1X:
return WIFI_SECURITY_MODE_WPA2_ENTERPRISE;
default:
return -1;
}
}
static void _atwinc15x0_eth_cb(uint8_t type, void *msg, void *ctrl_buf)
{
assert(atwinc15x0);
@ -115,7 +294,7 @@ static void _atwinc15x0_eth_cb(uint8_t type, void *msg, void *ctrl_buf)
DEBUG("%s type=%u msg=%p len=%d remaining=%d\n", __func__,
type, msg, ctrl->u16DataSize, ctrl->u16RemainigDataSize);
if (IS_ACTIVE(ENABLE_DEBUG) && IS_USED(MODULE_OD)) {
if (IS_ACTIVE(ENABLE_DEBUG_DUMP) && IS_USED(MODULE_OD)) {
od_hex_dump(msg, ctrl->u16DataSize, 16);
}
@ -144,6 +323,181 @@ typedef union {
static bool _rssi_info_ready = false;
static void _atwinc15x0_handle_resp_scan_done(const tstrM2mScanDone* scan_done)
{
DEBUG("%s scan done, %d APs found\n", __func__, scan_done->u8NumofCh);
if (scan_done->u8NumofCh > 0) {
/* read the first scan result record */
m2m_wifi_req_scan_result(0);
}
else {
/* no results */
_atwinc15x0_set_idle(atwinc15x0);
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_SCAN)) {
_wifi_scan_result_callback(&_atwinc15x0_scan_list.head);
}
}
}
static void _atwinc15x0_handle_resp_scan_result(const tstrM2mWifiscanResult* scan_result)
{
LOG_DEBUG("[atwinc15x0] %s: rssi %d, auth %d, ch %d, bssid "
ATWINC15X0_MAC_STR "\n",
scan_result->au8SSID,
scan_result->s8rssi,
scan_result->u8AuthType,
scan_result->u8ch,
ATWINC15X0_MAC_STR_ARG(scan_result->au8BSSID));
if (_atwinc15x0_is_connected(atwinc15x0)) {
if (!memcmp(scan_result->au8BSSID, &atwinc15x0->ap, ETHERNET_ADDR_LEN)) {
/* use the results for current AP to set the current channel */
atwinc15x0->channel = scan_result->u8ch;
}
}
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_SCAN)) {
int sec;
if ((sec = _atwinc15x0_get_sec_mode(scan_result->u8AuthType)) != -1) {
wifi_scan_result_t result = WIFI_SCAN_RESULT_INITIALIZER(scan_result->u8ch,
scan_result->s8rssi, sec);
memcpy(result.bssid, scan_result->au8BSSID, sizeof(result.bssid));
strncpy(result.ssid, (const char *)scan_result->au8SSID, sizeof(result.ssid) - 1);
_wifi_scan_list_insert(&result);
}
}
if (scan_result->u8index < m2m_wifi_get_num_ap_found() - 1) {
/* read the next scan result record */
m2m_wifi_req_scan_result(scan_result->u8index + 1);
}
else {
_atwinc15x0_set_idle(atwinc15x0);
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_SCAN)) {
_wifi_scan_result_callback(&_atwinc15x0_scan_list.head);
}
}
}
static void _atwinc15x0_handle_resp_con_state_changed(const tstrM2mWifiStateChanged *state_changed)
{
/**
* The logic here can be tested with the following test cases:
* 1. connect when disconnected
* 2. connect to another AP when connected
* 3. disconnect when connected
* 4. go to sleep when connected
*/
switch (state_changed->u8CurrState) {
case M2M_WIFI_DISCONNECTED:
LOG_INFO("[atwinc15x0] WiFi disconnected\n");
/* We disconnect before we connect, so we will first get a disconnect event when we
were connected. After that when connection to the new AP fails we are already in a
disconnected state. */
bool was_connected = _atwinc15x0_is_connected(atwinc15x0);
bool is_connecting = _atwinc15x0_is_connecting(atwinc15x0);
bool is_disconnecting = _atwinc15x0_is_disconnecting(atwinc15x0);
bool is_sleeping;
if (!(is_sleeping = _atwinc15x0_is_sleeping(atwinc15x0))) {
/* We requested to disconnect before sleep.
Don´t override the sleep state when the disconnect event is received. */
_atwinc15x0_set_disconnected(atwinc15x0);
}
if (was_connected || is_disconnecting || is_sleeping) {
/* notify when connection state changed or when we disconnected due to sleep */
DEBUG("atwinc15x0: notify upper layer about disconnect\n");
atwinc15x0->netdev.event_callback(&atwinc15x0->netdev, NETDEV_EVENT_LINK_DOWN);
}
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
if (!was_connected && !is_disconnecting && !is_sleeping) {
/* connection failed */
DEBUG("atwinc15x0: notify about connection failure\n");
wifi_disconnect_result_t disconn
= WIFI_DISCONNECT_RESULT_INITIALIZER(
_atwinc15x0_connect_req.conn_req.base.channel,
_atwinc15x0_connect_req.conn_req.ssid);
_wifi_disconnect_result_callback(&disconn);
}
else if ((was_connected || is_disconnecting || is_sleeping) && !is_connecting) {
/* disconnect from previous connection */
DEBUG("atwinc15x0: notify about disconnect\n");
wifi_disconnect_result_t disconn
= WIFI_DISCONNECT_RESULT_INITIALIZER(
atwinc15x0->channel,
_atwinc15x0_sta_get_current_ssid(atwinc15x0));
_wifi_disconnect_result_callback(&disconn);
}
}
if (IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
/* do not reconnect on sleep */
if (!_atwinc15x0_is_sleeping(atwinc15x0)) {
/* schedule reconnect timer:
Not trying to reconnect immediately allows
other connect requests to get through. */
_atwinc15x0_set_reconnect_timer();
}
}
break;
case M2M_WIFI_CONNECTED:
LOG_INFO("[atwinc15x0] WiFi connected\n");
_atwinc15x0_set_connected(atwinc15x0);
atwinc15x0->netdev.event_callback(&atwinc15x0->netdev, NETDEV_EVENT_LINK_UP);
/* get information about the current AP */
m2m_wifi_get_connection_info();
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
_atwinc15x0_sta_set_current_ssid(atwinc15x0,
_atwinc15x0_connect_req.conn_req.ssid);
atwinc15x0->channel = _atwinc15x0_connect_req.conn_req.base.channel;
wifi_connect_result_t conn
= WIFI_CONNECT_RESULT_INITIALIZER(
atwinc15x0->channel,
_atwinc15x0_sta_get_current_ssid(atwinc15x0));
if (_atwinc15x0_connect_req.conn_req.cred) {
if (*_atwinc15x0_connect_req.conn_req.cred == WIFI_SECURITY_MODE_WEP_PSK) {
conn.credentials.wep = *((const wifi_security_wep_psk_t *)
_atwinc15x0_connect_req.conn_req.cred);
}
else if (*_atwinc15x0_connect_req.conn_req.cred == WIFI_SECURITY_MODE_WPA2_PERSONAL) {
conn.credentials.wpa_psk = *((const wifi_security_wpa_psk_t *)
_atwinc15x0_connect_req.conn_req.cred);
}
else if (*_atwinc15x0_connect_req.conn_req.cred == WIFI_SECURITY_MODE_WPA2_ENTERPRISE) {
conn.credentials.wpa_enterprise = *((const wifi_security_wpa_enterprise_t *)
_atwinc15x0_connect_req.conn_req.cred);
}
}
_wifi_connect_result_callback(&conn);
}
if (IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
/* start a scan for additional info, e.g. used channel */
m2m_wifi_request_scan(M2M_WIFI_CH_ALL);
}
break;
}
}
static void _atwinc15x0_handle_resp_conn_info(const tstrM2MConnInfo *conn_info)
{
DEBUG("%s conn info %s, rssi %d, sec %u, bssid "
ATWINC15X0_MAC_STR "\n", __func__,
conn_info->acSSID,
conn_info->s8RSSI,
conn_info->u8SecType,
ATWINC15X0_MAC_STR_ARG(conn_info->au8MACAddress));
/* set the RSSI and BSSID of the current AP */
atwinc15x0->rssi = conn_info->s8RSSI;
memcpy(atwinc15x0->ap, conn_info->au8MACAddress, ETHERNET_ADDR_LEN);
if (IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
_atwinc15x0_sta_set_current_ssid(atwinc15x0, conn_info->acSSID);
}
}
static void _atwinc15x0_handle_resp_current_rssi(int8_t rssi)
{
DEBUG("%s current rssi %d\n", __func__, rssi);
/* set the RSSI */
atwinc15x0->rssi = rssi;
_rssi_info_ready = true;
}
static void _atwinc15x0_wifi_cb(uint8_t type, void *msg)
{
/**
@ -157,85 +511,19 @@ static void _atwinc15x0_wifi_cb(uint8_t type, void *msg)
switch (type) {
case M2M_WIFI_RESP_SCAN_DONE:
DEBUG("%s scan done, %d APs found\n", __func__,
event->scan_done.u8NumofCh);
/* read the first scan result record */
m2m_wifi_req_scan_result(0);
_atwinc15x0_handle_resp_scan_done(&event->scan_done);
break;
case M2M_WIFI_RESP_SCAN_RESULT:
LOG_DEBUG("[atwinc15x0] %s: rssi %d, auth %d, ch %d, bssid "
ATWINC15X0_MAC_STR "\n",
event->scan_result.au8SSID,
event->scan_result.s8rssi,
event->scan_result.u8AuthType,
event->scan_result.u8ch,
ATWINC15X0_MAC_STR_ARG(event->scan_result.au8BSSID));
if (memcmp(&event->scan_result.au8BSSID,
&atwinc15x0->ap, ETHERNET_ADDR_LEN) == 0) {
/* use the results for current AP to set the current channel */
atwinc15x0->channel = event->scan_result.u8ch;
}
if (event->scan_result.u8index < m2m_wifi_get_num_ap_found()) {
/* read the next scan result record */
m2m_wifi_req_scan_result(event->scan_result.u8index + 1);
}
_atwinc15x0_handle_resp_scan_result(&event->scan_result);
break;
case M2M_WIFI_RESP_CON_STATE_CHANGED:
switch (event->state_changed.u8CurrState) {
case M2M_WIFI_DISCONNECTED:
LOG_INFO("[atwinc15x0] WiFi disconnected\n");
atwinc15x0->connected = false;
atwinc15x0->netdev.event_callback(&atwinc15x0->netdev,
NETDEV_EVENT_LINK_DOWN);
/* do not reconnect on standby or sleep */
if (atwinc15x0->state == NETOPT_STATE_STANDBY ||
atwinc15x0->state == NETOPT_STATE_SLEEP) {
break;
}
/* wait and try to reconnect */
ztimer_sleep(ZTIMER_MSEC, ATWINC15X0_WAIT_RECONNECT_MS);
_atwinc15x0_connect();
break;
case M2M_WIFI_CONNECTED:
LOG_INFO("[atwinc15x0] WiFi connected\n");
atwinc15x0->connected = true;
atwinc15x0->netdev.event_callback(&atwinc15x0->netdev,
NETDEV_EVENT_LINK_UP);
/* get information about the current AP */
m2m_wifi_get_connection_info();
/* start a scan for additional info, e.g. used channel */
m2m_wifi_request_scan(M2M_WIFI_CH_ALL);
break;
default:
break;
}
_atwinc15x0_handle_resp_con_state_changed(&event->state_changed);
break;
case M2M_WIFI_RESP_CONN_INFO:
DEBUG("%s conn info %s, rssi %d, sec %u, bssid "
ATWINC15X0_MAC_STR "\n", __func__,
event->conn_info.acSSID,
event->conn_info.s8RSSI,
event->conn_info.u8SecType,
ATWINC15X0_MAC_STR_ARG(event->conn_info.au8MACAddress));
/* set the RSSI and BSSID of the current AP */
atwinc15x0->rssi = event->conn_info.s8RSSI;
memcpy(atwinc15x0->ap,
event->conn_info.au8MACAddress, ETHERNET_ADDR_LEN);
_atwinc15x0_handle_resp_conn_info(&event->conn_info);
break;
case M2M_WIFI_RESP_CURRENT_RSSI:
DEBUG("%s current rssi %d\n", __func__, event->rssi);
/* set the RSSI */
atwinc15x0->rssi = event->rssi;
_rssi_info_ready = true;
break;
default:
_atwinc15x0_handle_resp_current_rssi(event->rssi);
break;
}
}
@ -248,20 +536,15 @@ static int _atwinc15x0_send(netdev_t *netdev, const iolist_t *iolist)
assert(dev == atwinc15x0);
assert(iolist);
if (!dev->connected) {
DEBUG("%s WiFi is still not connected to AP, cannot send\n", __func__);
return -ENODEV;
}
/* send wakes from standby but not from sleep */
if (dev->state == NETOPT_STATE_SLEEP) {
if (_atwinc15x0_is_sleeping(dev)) {
DEBUG("%s WiFi is in SLEEP state, cannot send\n", __func__);
return -ENODEV;
}
if (dev->state == NETOPT_STATE_STANDBY) {
_set_state(dev, NETOPT_STATE_IDLE);
if (!_atwinc15x0_is_connected(dev)) {
DEBUG("%s WiFi is still not connected to AP, cannot send\n", __func__);
return -ENODEV;
}
/* atwinc15x0_eth_buf should not be used for incoming packets here */
assert(dev->rx_buf == NULL);
@ -350,15 +633,7 @@ static int _atwinc15x0_recv(netdev_t *netdev, void *buf, size_t len, void *info)
static netopt_enable_t _get_link_state(atwinc15x0_t *dev)
{
if (dev->state != NETOPT_STATE_IDLE) {
return NETOPT_DISABLE;
}
if (dev->connected) {
return NETOPT_ENABLE;
}
return NETOPT_DISABLE;
return _atwinc15x0_is_connected(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
}
static int _atwinc15x0_get(netdev_t *netdev, netopt_t opt, void *val,
@ -367,7 +642,6 @@ static int _atwinc15x0_get(netdev_t *netdev, netopt_t opt, void *val,
atwinc15x0_t *dev = (atwinc15x0_t *)netdev;
(void)max_len;
assert(val);
assert(dev);
assert(dev == atwinc15x0);
@ -396,13 +670,15 @@ static int _atwinc15x0_get(netdev_t *netdev, netopt_t opt, void *val,
case NETOPT_STATE:
assert(max_len >= sizeof(netopt_state_t));
*((netopt_state_t *)val) = dev->state;
*((netopt_state_t *)val) = _get_state(dev);
return sizeof(netopt_state_t);
case NETOPT_RSSI:
assert(max_len == sizeof(int16_t));
_rssi_info_ready = false;
_CHECK_SLEEP_STATE(dev);
if (!_atwinc15x0_is_connected(dev)) {
return -ECANCELED;
}
/* trigger the request current RSSI (asynchronous function) */
if (m2m_wifi_req_curr_rssi() != M2M_SUCCESS) {
return 0;
@ -423,28 +699,39 @@ static int _atwinc15x0_get(netdev_t *netdev, netopt_t opt, void *val,
static int _set_state(atwinc15x0_t *dev, netopt_state_t state)
{
if (_atwinc15x0_is_busy(dev)) {
return -EBUSY;
}
switch (state) {
case NETOPT_STATE_SLEEP:
case NETOPT_STATE_STANDBY:
dev->state = state;
_atwinc15x0_set_sleeping(dev);
m2m_wifi_disconnect();
m2m_wifi_set_sleep_mode(M2M_PS_MANUAL, CONFIG_ATWINC15X0_RECV_BCAST);
m2m_wifi_request_sleep(UINT32_MAX);
if (gpio_is_valid(atwinc15x0->params.wake_pin)) {
gpio_clear(atwinc15x0->params.wake_pin);
}
return sizeof(netopt_state_t);
return sizeof(netopt_state_t);
case NETOPT_STATE_IDLE:
if (gpio_is_valid(atwinc15x0->params.wake_pin)) {
gpio_set(atwinc15x0->params.wake_pin);
if (_atwinc15x0_is_sleeping(dev)) {
if (gpio_is_valid(atwinc15x0->params.wake_pin)) {
gpio_set(atwinc15x0->params.wake_pin);
}
m2m_wifi_set_sleep_mode(M2M_PS_DEEP_AUTOMATIC, CONFIG_ATWINC15X0_RECV_BCAST);
_atwinc15x0_set_disconnected(dev);
if (IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
_atwinc15x0_set_reconnect_timer();
}
}
m2m_wifi_set_sleep_mode(M2M_PS_DEEP_AUTOMATIC, CONFIG_ATWINC15X0_RECV_BCAST);
dev->state = state;
_atwinc15x0_connect();
return sizeof(netopt_state_t);
case NETOPT_STATE_RESET:
if (_atwinc15x0_is_sleeping(dev)) {
_set_state(dev, NETOPT_STATE_IDLE);
}
else if (_atwinc15x0_is_connected(dev)) {
m2m_wifi_disconnect();
}
_atwinc15x0_init(&dev->netdev);
dev->state = NETOPT_STATE_IDLE;
return sizeof(netopt_state_t);
default:
break;
@ -453,15 +740,25 @@ static int _set_state(atwinc15x0_t *dev, netopt_state_t state)
return -ENOTSUP;
}
static netopt_state_t _get_state(const atwinc15x0_t *dev)
{
if (dev->state == ATWINC15X0_STATE_SLEEP) {
return NETOPT_STATE_SLEEP;
}
else {
return NETOPT_STATE_IDLE;
}
}
static int _atwinc15x0_set(netdev_t *netdev, netopt_t opt, const void *val,
size_t max_len)
{
atwinc15x0_t *dev = (atwinc15x0_t *)netdev;
assert(val);
DEBUG("%s dev=%p opt=%u val=%p max_len=%u\n", __func__,
(void *)netdev, opt, val, max_len);
int ret;
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len == ETHERNET_ADDR_LEN);
@ -482,9 +779,53 @@ static int _atwinc15x0_set(netdev_t *netdev, netopt_t opt, const void *val,
} else {
return max_len;
}
case NETOPT_SCAN:
if (!IS_USED(MODULE_ATWINC15X0_DYNAMIC_SCAN)) {
break;
}
if (max_len < sizeof(wifi_scan_request_t)) {
return -EINVAL;
}
if ((ret = _atwinc15x0_scan((const wifi_scan_request_t *)val)) != 0) {
return ret;
}
return sizeof(wifi_scan_request_t);
case NETOPT_CONNECT:
if (!IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
break;
}
if (max_len < sizeof(wifi_connect_request_t)) {
return -EINVAL;
}
if ((ret = _atwinc15x0_connect((const wifi_connect_request_t *)val)) != 0) {
return ret;
}
return sizeof(wifi_connect_request_t);
case NETOPT_DISCONNECT:
if (!IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
break;
}
if (max_len < sizeof(wifi_disconnect_request_t)) {
return -EINVAL;
}
if ((ret = _atwinc15x0_disconnect((const wifi_disconnect_request_t *)val)) != 0) {
return ret;
}
return sizeof(wifi_disconnect_request_t);
default:
return netdev_eth_set(netdev, opt, val, max_len);
break;
}
return netdev_eth_set(netdev, opt, val, max_len);
}
static void _print_firmware_version(const tstrM2mRev *info)
{
LOG_DEBUG("[atwinc15x0] CHIP ID: %lu\n",
info->u32Chipid);
LOG_DEBUG("[atwinc15x0] FIRMWARE: %u.%u.%u\n",
info->u8FirmwareMajor, info->u8FirmwareMinor, info->u8FirmwarePatch);
LOG_DEBUG("[atwinc15x0] DRIVER: %u.%u.%u\n",
info->u8DriverMajor, info->u8DriverMinor, info->u8DriverPatch);
}
static int _atwinc15x0_init(netdev_t *netdev)
@ -499,15 +840,13 @@ static int _atwinc15x0_init(netdev_t *netdev)
atwinc15x0->bsp_isr = NULL;
atwinc15x0->bsp_irq_enabled = true;
atwinc15x0->connected = false;
atwinc15x0->state = NETOPT_STATE_IDLE;
atwinc15x0->state = ATWINC15X0_STATE_DISCONNECTED;
atwinc15x0->rx_len = 0;
atwinc15x0->rx_buf = NULL;
nm_bsp_init();
int8_t res;
int res;
/* initialize the WINC Driver*/
if ((res = m2m_wifi_init(&atwinc15x0_wifi_params)) != M2M_SUCCESS) {
DEBUG("m2m_wifi_init failed with code %d\n", res);
@ -521,6 +860,29 @@ static int _atwinc15x0_init(netdev_t *netdev)
}
}
/* get firmware version */
if (IS_ACTIVE(ENABLE_DEBUG)) {
tstrM2mRev fw_ver;
if ((res = m2m_wifi_get_firmware_version(&fw_ver)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] Could not read firmware version\n");
}
else {
_print_firmware_version(&fw_ver);
}
}
/* set Wi-Fi region */
if (WIFI_REGION == WIFI_REGION_EUROPE) {
res = m2m_wifi_set_scan_region(EUROPE);
}
else if (WIFI_REGION == WIFI_REGION_NORTH_AMERICA) {
res = m2m_wifi_set_scan_region(NORTH_AMERICA);
}
else if (WIFI_REGION == WIFI_REGION_ASIA ) {
res = m2m_wifi_set_scan_region(ASIA);
}
if (res != M2M_SUCCESS) {
return -ENOTSUP;
}
/* disable the built-in DHCP client */
if ((res = m2m_wifi_enable_dhcp(false)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] m2m_wifi_enable_dhcp failed with %d\n", res);
@ -530,42 +892,145 @@ static int _atwinc15x0_init(netdev_t *netdev)
/* enable automatic power saving */
m2m_wifi_set_sleep_mode(M2M_PS_DEEP_AUTOMATIC, CONFIG_ATWINC15X0_RECV_BCAST);
/* try to connect and return */
return _atwinc15x0_connect();
res = 0;
if (IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
/* try to connect and return */
res = _atwinc15x0_static_connect();
}
return res;
}
static int _atwinc15x0_connect(void)
static int _atwinc15x0_scan(const wifi_scan_request_t *req)
{
assert(req);
(void)req;
if (!IS_USED(MODULE_ATWINC15X0_DYNAMIC_SCAN)) {
return 0;
}
if (_atwinc15x0_is_busy(atwinc15x0)) {
return -EBUSY;
}
if (req->base.channel != NETOPT_SCAN_REQ_ALL_CH) {
if (req->base.channel < WIFI_2_4_CH_MIN ||
req->base.channel > WIFI_2_4_CH_MAX) {
return -EINVAL;
}
}
if (_atwinc15x0_is_sleeping(atwinc15x0)) {
_set_state(atwinc15x0, NETOPT_STATE_IDLE);
}
tstrM2MScanOption opt = {
.u8NumOfSlot = ATWINC1510_SCAN_SLOTS_DEF,
.u8ProbesPerSlot = ATWINC1510_SCAN_PROBES_NUMOF_DEF,
.u8SlotTime = ATWINC1510_SCAN_SLOT_TIME_MS_DEF,
.s8RssiThresh = ATWINC1510_SCAN_THRESHOLD_DBM_DEF,
};
if (req->timeout_ms_per_ch) {
uint16_t ch_time_max = ATWINC1510_SCAN_SLOT_TIME_MS_MAX * opt.u8NumOfSlot;
if (req->timeout_ms_per_ch > ch_time_max) {
opt.u8SlotTime = ATWINC1510_SCAN_SLOT_TIME_MS_MAX;
}
else {
opt.u8SlotTime = req->timeout_ms_per_ch / opt.u8NumOfSlot;
}
}
int ret;
if ((ret = m2m_wifi_set_scan_options(&opt)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi setting scan options failed with %d\n", ret);
return -EIO;
}
if ((ret = m2m_wifi_request_scan(req->base.channel == NETOPT_SCAN_REQ_ALL_CH
? M2M_WIFI_CH_ALL
: req->base.channel)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi scan failed with %d\n", ret);
return -EIO;
}
_atwinc15x0_set_scanning(atwinc15x0);
_atwinc15x0_scan_req = *req;
_wifi_scan_list_empty();
return 0;
}
static int _atwinc15x0_disconnect(const wifi_disconnect_request_t *req)
{
assert(req);
if (_atwinc15x0_is_busy(atwinc15x0)) {
return -EBUSY;
}
if (!_atwinc15x0_is_connected(atwinc15x0)) {
/* also when sleeping */
return -EALREADY;
}
int ret;
if ((ret = m2m_wifi_disconnect()) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi disconnect failed with %d\n", ret);
return -EIO;
}
_atwinc15x0_set_disconnecting(atwinc15x0);
_atwinc15x0_connect_req.disconn_req = *req;
return 0;
}
static int _atwinc15x0_connect(const wifi_connect_request_t *req)
{
assert(req);
if (!IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)) {
return 0;
}
tuniM2MWifiAuth auth_info;
tenuM2mSecType auth_type = M2M_WIFI_SEC_OPEN;
#if !defined(MODULE_WIFI_ENTERPRISE) && defined(WIFI_PASS)
strncpy((char *)auth_info.au8PSK, WIFI_PASS, M2M_MAX_PSK_LEN);
auth_type = M2M_WIFI_SEC_WPA_PSK;
#elif defined(MODULE_WIFI_ENTERPRISE)
#if defined(WIFI_USER) && defined(WIFI_PASS)
strncpy((char *)&auth_info.strCred1x.au8UserName, WIFI_USER, M2M_1X_USR_NAME_MAX);
strncpy((char *)&auth_info.strCred1x.au8Passwd, WIFI_PASS, M2M_1X_PWD_MAX);
auth_type = M2M_WIFI_SEC_802_1X;
#else /* defined(WIFI_EAP_USER) && defined(WIFI_EAP_PASS) */
#error WIFI_EAP_USER and WIFI_EAP_PASS have to define the user name \
and the password for EAP phase 2 authentication in wifi_enterprise
#endif /* defined(WIFI_EAP_USER) && defined(WIFI_EAP_PASS) */
#endif /* defined(MODULE_ESP_WIFI_ENTERPRISE) */
/* connect */
if (_atwinc15x0_is_busy(atwinc15x0)) {
return -EBUSY;
}
if (_atwinc15x0_is_connected(atwinc15x0)) {
if (!strcmp(req->ssid, _atwinc15x0_sta_get_current_ssid(atwinc15x0))) {
return -EALREADY;
}
}
else if (_atwinc15x0_is_sleeping(atwinc15x0)) {
_set_state(atwinc15x0, NETOPT_STATE_IDLE);
}
if (req->cred && *(req->cred) != WIFI_SECURITY_MODE_OPEN) {
if (*(req->cred) == WIFI_SECURITY_MODE_WEP_PSK) {
auth_type = M2M_WIFI_SEC_WEP;
const wifi_security_wep_psk_t *cred = (const wifi_security_wep_psk_t *)req->cred;
strscpy((char *)auth_info.au8PSK, cred->psk, sizeof(auth_info.au8PSK));
}
else if (*(req->cred) == WIFI_SECURITY_MODE_WPA2_PERSONAL) {
auth_type = M2M_WIFI_SEC_WPA_PSK;
const wifi_security_wpa_psk_t *cred = (const wifi_security_wpa_psk_t *)req->cred;
strscpy((char *)auth_info.au8PSK, cred->psk, sizeof(auth_info.au8PSK));
}
else if (*(req->cred) == WIFI_SECURITY_MODE_WPA2_ENTERPRISE) {
auth_type = M2M_WIFI_SEC_802_1X;
const wifi_security_wpa_enterprise_t *cred
= (const wifi_security_wpa_enterprise_t *)req->cred;
strscpy((char *)auth_info.strCred1x.au8UserName, cred->user,
sizeof(auth_info.strCred1x.au8UserName));
strscpy((char *)auth_info.strCred1x.au8Passwd, cred->pwd,
sizeof(auth_info.strCred1x.au8Passwd));
}
else {
return -ENOTSUP;
}
}
int8_t res;
if ((res = m2m_wifi_connect(WIFI_SSID, sizeof(WIFI_SSID),
if (_atwinc15x0_is_connected(atwinc15x0)) {
/* late disconnect to not interrupt connection on errors before */
if ((res = m2m_wifi_disconnect()) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi disconnect failed with %d\n", res);
return -EIO;
}
}
/* connect */
if ((res = m2m_wifi_connect((char *)req->ssid, strlen(req->ssid),
auth_type, &auth_info,
M2M_WIFI_CH_ALL)) != M2M_SUCCESS) {
LOG_ERROR("[atwinc15x0] WiFi connect failed with %d\n", res);
return res;
}
_atwinc15x0_set_connecting(atwinc15x0);
_atwinc15x0_connect_req.conn_req = *req;
return 0;
}
@ -583,6 +1048,18 @@ static void _atwinc15x0_isr(netdev_t *netdev)
DEBUG("%s handle events failed, reset device\n", __func__);
_atwinc15x0_init(netdev);
}
int err;
if (IS_USED(MODULE_ATWINC15X0_STATIC_CONNECT)) {
if (_atwinc15x0_timer.timeout == ATWINC15X0_WIFI_STA_TIMEOUT_RECONNECT) {
if (!_atwinc15x0_is_connected(atwinc15x0)) {
/* try again if device is busy or the Atmel firmware throws an error */
if ((err = _atwinc15x0_static_connect()) == -EBUSY || err == -EIO) {
_atwinc15x0_set_reconnect_timer();
}
}
_atwinc15x0_timer.timeout = ATWINC15X0_WIFI_STA_TIMEOUT_NONE;
}
}
}
const netdev_driver_t atwinc15x0_netdev_driver = {

View File

@ -19,6 +19,10 @@
#ifndef ATWINC15X0_INTERNAL_H
#define ATWINC15X0_INTERNAL_H
#include <stdbool.h>
#include <string.h>
#include "driver/include/m2m_types.h"
#include "atwinc15x0.h"
#ifdef __cplusplus
@ -34,6 +38,264 @@ extern "C" {
*/
extern atwinc15x0_t *atwinc15x0;
/**
* @brief Minimum number of slots to scan a channel
*/
#define ATWINC1510_SCAN_SLOTS_MIN 2
/**
* @brief Default number of slots to scan a channel
*/
#define ATWINC1510_SCAN_SLOTS_DEF M2M_SCAN_DEFAULT_NUM_SLOTS
/**
* @brief Maximum number of slots to scan a channel
*/
#define ATWINC1510_SCAN_SLOTS_MAX 255
/**
* @brief Time in ms to scan a slot in a channel
*/
#define ATWINC1510_SCAN_SLOT_TIME_MS_MIN 10
/**
* @brief Default time in ms to scan a slot in a channel
*/
#define ATWINC1510_SCAN_SLOT_TIME_MS_DEF M2M_SCAN_DEFAULT_SLOT_TIME
/**
* @brief Maximum time in ms to scan a slot in a channel
*/
#define ATWINC1510_SCAN_SLOT_TIME_MS_MAX 250
/**
* @brief Default number of probes to send to scan a channel
*/
#define ATWINC1510_SCAN_PROBES_NUMOF_DEF M2M_SCAN_DEFAULT_NUM_PROBE
/**
* @brief Default threshold in dbm for an AP to pass
*/
#define ATWINC1510_SCAN_THRESHOLD_DBM_DEF (-99)
/**
* @brief Check if @p dev is scanning
*
* @param[in] dev ATWINC15x0 device
*
* @returns true if @p dev is scanning
* @returns false if @p dev is not scanning
*/
static inline bool _atwinc15x0_is_scanning(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_CONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_SCANNING;
}
/**
* @brief Set state to indicate that @p dev is scanning
*
* @param[in, out] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_scanning(atwinc15x0_t *dev) {
if (dev->state == ATWINC15X0_STATE_CONNECTED) {
dev->state = ATWINC15X0_STATE_CONNECTED_SCANNING;
}
else if (dev->state == ATWINC15X0_STATE_DISCONNECTED) {
dev->state = ATWINC15X0_STATE_DISCONNECTED_SCANNING;
}
else {
assert(false);
}
}
/**
* @brief Check if @p dev is connecting to an AP
*
* @param[in] dev ATWINC15x0 device
*
* @returns true if @p dev is connecting
* @returns false if @p dev is not connecting
*/
static inline bool _atwinc15x0_is_connecting(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_CONNECTED_CONNECTING ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_CONNECTING;
}
/**
* @brief Set state to indicate that @p dev is connecting
* to an AP
*
* @param[in, out] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_connecting(atwinc15x0_t *dev) {
if (dev->state == ATWINC15X0_STATE_CONNECTED) {
dev->state = ATWINC15X0_STATE_CONNECTED_CONNECTING;
}
else if (dev->state == ATWINC15X0_STATE_DISCONNECTED) {
dev->state = ATWINC15X0_STATE_DISCONNECTED_CONNECTING;
}
else {
assert(false);
}
}
/**
* @brief Check if @p dev is disconnecting from an AP
*
* @param[in] dev ATWINC15x0 device
*
* @returns true if @p dev is disconnecting
* @returns false if @p dev is not disconnecting
*/
static inline bool _atwinc15x0_is_disconnecting(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_DISCONNECTING;
}
/**
* @brief Set state to indicate that @p dev is disconnecting
* from an AP
*
* @param[in, out] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_disconnecting(atwinc15x0_t *dev) {
if (dev->state == ATWINC15X0_STATE_CONNECTED) {
dev->state = ATWINC15X0_STATE_DISCONNECTING;
}
}
/**
* @brief Check if @p dev is connected to an AP
*
* @param[in] dev ATWINC15x0 device
*
* @returns true if @p dev is connected
* @returns false if @p dev is not connected
*/
static inline bool _atwinc15x0_is_connected(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_CONNECTED ||
dev->state == ATWINC15X0_STATE_CONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_CONNECTED_CONNECTING;
}
/**
* @brief Set state to indicate that @p dev is connected
* to an AP
*
* @param[in, out] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_connected(atwinc15x0_t *dev) {
assert(dev->state == ATWINC15X0_STATE_DISCONNECTED ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_CONNECTING ||
dev->state == ATWINC15X0_STATE_CONNECTED_SCANNING);
dev->state = ATWINC15X0_STATE_CONNECTED;
}
/**
* @brief Set state to indicate that @p dev is disconnected
*
* @param[in, out] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_disconnected(atwinc15x0_t *dev) {
dev->state = ATWINC15X0_STATE_DISCONNECTED;
}
/**
* @brief Check if @p dev is currently performing an asynchronous operation
*
* @param[in] dev ATWINC15x0 device
* @returns true if @p dev is busy
* @returns false if @p dev is not busy
*/
static inline bool _atwinc15x0_is_busy(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_DISCONNECTING ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_CONNECTING ||
dev->state == ATWINC15X0_STATE_CONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_CONNECTED_CONNECTING;
}
/**
* @brief Check is @p dev is currently not performing an asynchronous operation
*
* @param[in] dev ATWINC15x0 device
*
* @return true if @p dev is idle
* @return false if @p dev is not idle
*/
static inline bool _atwinc15x0_is_idle(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_CONNECTED ||
dev->state == ATWINC15X0_STATE_DISCONNECTED;
}
/**
* @brief Return from any busy state to corresponding idle state
*
* @param[in] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_idle(atwinc15x0_t *dev) {
if (dev->state == ATWINC15X0_STATE_CONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_CONNECTED_CONNECTING) {
_atwinc15x0_set_connected(dev);
}
else if (dev->state == ATWINC15X0_STATE_DISCONNECTED_SCANNING ||
dev->state == ATWINC15X0_STATE_DISCONNECTED_CONNECTING) {
_atwinc15x0_set_disconnected(dev);
}
}
/**
* @brief Set state to indicate that @p dev is sleeping
*
* @param[in] dev ATWINC15x0 device
*/
static inline void _atwinc15x0_set_sleeping(atwinc15x0_t *dev) {
assert(!_atwinc15x0_is_busy(dev));
dev->state = ATWINC15X0_STATE_SLEEP;
}
/**
* @brief Check if @p dev is currently sleeping
*
* @param[in] dev ATWINC15x0 device
* @return true if @p dev is sleeping
* @return false if @p dev is not sleeping
*/
static inline bool _atwinc15x0_is_sleeping(const atwinc15x0_t *dev) {
return dev->state == ATWINC15X0_STATE_SLEEP;
}
/**
* @brief Set member of currently connected AP SSID
*
* @pre Module atwinc15x0_dynamic_connect is used
*
* @param[in, out] dev ATWINC15x0 device
* @param[in] ssid SSID
*/
static inline void _atwinc15x0_sta_set_current_ssid(atwinc15x0_t *dev, const char *ssid) {
(void)dev; (void)ssid;
#if IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)
strcpy(atwinc15x0->ssid, ssid);
#endif
}
/**
* @brief Get member of currently connected AP
*
* @pre Module atwinc15x0_dynamic_connect is used
*
* @param[in] dev ATWINC15x0 device
*
* @returns SSID member
*/
static inline const char *_atwinc15x0_sta_get_current_ssid(const atwinc15x0_t *dev) {
(void)dev;
#if IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT)
return dev->ssid;
#endif
return NULL;
}
/**
* @brief ATWINC15x0 device driver ISR
*/

View File

@ -22,6 +22,7 @@
#include "bsp/include/nm_bsp.h"
#include "net/ethernet.h"
#include "net/wifi.h"
#include "net/netdev.h"
#include "periph/gpio.h"
#include "periph/spi.h"
@ -41,6 +42,14 @@ extern "C" {
#define CONFIG_ATWINC15X0_RECV_BCAST (1)
#endif
/**
* @brief Maximum number of supported entries in a scan result of
* an ATWINC15x0 transceiver
*/
#ifndef CONFIG_ATWINC15X0_SCAN_LIST_NUMOF
#define CONFIG_ATWINC15X0_SCAN_LIST_NUMOF (3)
#endif
/**
* @brief ATWINC15x0 hardware and global parameters
*/
@ -54,16 +63,32 @@ typedef struct {
gpio_t wake_pin; /**< WAKE pin */
} atwinc15x0_params_t;
/**
* @brief ATWINC15x0 internal states
*/
typedef enum {
ATWINC15X0_STATE_SLEEP, /**< Sleep state */
ATWINC15X0_STATE_DISCONNECTING, /**< Disconnect received when connected before */
ATWINC15X0_STATE_DISCONNECTED, /**< Disconnect state */
ATWINC15X0_STATE_DISCONNECTED_SCANNING, /**< Scanning state when disconnected */
ATWINC15X0_STATE_DISCONNECTED_CONNECTING, /**< Connecting state where disconnected before */
ATWINC15X0_STATE_CONNECTED, /**< Connected state */
ATWINC15X0_STATE_CONNECTED_SCANNING, /**< Scanning state when connected */
ATWINC15X0_STATE_CONNECTED_CONNECTING, /**< Connecting state where disconnect
event is not yet received */
} atwinc15x0_state_t;
/**
* @brief ATWINC15x0 device descriptor type
*/
typedef struct atwinc15x0 {
netdev_t netdev; /**< Pulls in the netdev fields */
atwinc15x0_params_t params; /**< Device initialization parameters */
bool connected; /**< Indicates whether connected to an AP */
netopt_state_t state; /**< Current interface state, only sleep or idle */
atwinc15x0_state_t state; /**< Device state */
char ap[ETHERNET_ADDR_LEN]; /**< BSSID of current AP */
#if IS_USED(MODULE_ATWINC15X0_DYNAMIC_CONNECT) || defined(DOXYGEN)
char ssid[WIFI_SSID_LEN_MAX + 1]; /**< SSID of current AP */
#endif
uint8_t channel; /**< Channel used for current AP */
int8_t rssi; /**< RSSI last measured by the WiFi module */

View File

@ -579,6 +579,7 @@ PSEUDOMODULES += vfs_auto_mount
PSEUDOMODULES += vfs_default
PSEUDOMODULES += wakaama_objects_%
PSEUDOMODULES += wifi_scan_list
PSEUDOMODULES += wifi_enterprise
PSEUDOMODULES += xtimer_on_ztimer
PSEUDOMODULES += xtimer_no_ztimer_default