driver: wifi: Add inventek es-WiFi driver

es-WiFi compatible modules use IWIN AT command set.
This driver is split into several layers:
- bus layer: interface to transmit AT commands (SPI, USB, UART...)
- core layer: es-WiFi module management (state, scan...)
- offload layer: TCP/IP offload operations (connect, listen...)

This driver has been tested with stm32l4 disco iot board
(disco_l475_iot1) and the wifi sample:

$ select wifi
$ scan
$ connect "CISCO" 5 password
$ select net
$ tcp connect 192.168.1.21 4242
$ tcp send HelloWorld!

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
This commit is contained in:
Loic Poulain 2018-10-09 17:49:44 +02:00 committed by Jukka Rissanen
commit 0b8fde39e4
9 changed files with 1451 additions and 0 deletions

View file

@ -1,2 +1,3 @@
add_subdirectory_ifdef(CONFIG_WIFI_WINC1500 winc1500)
add_subdirectory_ifdef(CONFIG_WIFI_SIMPLELINK simplelink)
add_subdirectory_ifdef(CONFIG_WIFI_ESWIFI eswifi)

View file

@ -35,5 +35,6 @@ config WIFI_OFFLOAD
source "drivers/wifi/winc1500/Kconfig.winc1500"
source "drivers/wifi/simplelink/Kconfig.simplelink"
source "drivers/wifi/eswifi/Kconfig.eswifi"
endif # WIFI

View file

@ -0,0 +1,14 @@
if(CONFIG_WIFI_ESWIFI)
zephyr_include_directories(./)
zephyr_library_include_directories(
# IP headers
${ZEPHYR_BASE}/subsys/net/ip
)
zephyr_sources(
eswifi_core.c
eswifi_bus_spi.c
eswifi_offload.c
)
endif()

View file

@ -0,0 +1,28 @@
# Kconfig - es-WiFi driver options
#
# Copyright (c) 2018 Linaro
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig WIFI_ESWIFI
bool "Inventek eS-WiFi support"
depends on WIFI
select NET_L2_WIFI_MGMT
select WIFI_OFFLOAD
if WIFI_ESWIFI
config WIFI_ESWIFI_NAME
string "Driver name"
default "ESWIFI"
config WIFI_ESWIFI_THREAD_PRIO
int "esWiFi threads priority"
default 2
help
This option sets the priority of the esWiFi threads.
Do not touch it unless you know what you are doing.
endif

View file

@ -0,0 +1,105 @@
/**
* Copyright (c) 2018 Linaro
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_WIFI_ESWIFI_ESWIFI_H_
#define ZEPHYR_DRIVERS_WIFI_ESWIFI_ESWIFI_H_
#include <zephyr.h>
#include <kernel.h>
#include <net/wifi_mgmt.h>
#include "eswifi_offload.h"
#define MAX_DATA_SIZE 1600
#define AT_OK_STR "\r\nOK\r\n> "
#define AT_OK_STR_LEN 8
#define AT_RSP_DELIMITER "\r\n"
#define AT_RSP_DELIMITER_LEN 2
struct device *uarthost;
struct eswifi_gpio {
struct device *dev;
unsigned int pin;
};
enum eswifi_security_type {
ESWIFI_SEC_OPEN,
ESWIFI_SEC_WEP,
ESWIFI_SEC_WPA,
ESWIFI_SEC_WPA2_AES,
ESWIFI_SEC_WPA2_MIXED,
ESWIFI_SEC_MAX
};
enum eswifi_request {
ESWIFI_REQ_SCAN,
ESWIFI_REQ_CONNECT,
ESWIFI_REQ_DISCONNECT,
ESWIFI_REQ_NONE
};
enum eswifi_role {
ESWIFI_ROLE_CLIENT,
ESWIFI_ROLE_AP,
};
struct eswifi_sta {
char ssid[WIFI_SSID_MAX_LEN + 1];
enum eswifi_security_type security;
char pass[65];
bool connected;
};
struct eswifi_bus_ops;
struct eswifi_dev {
struct net_if *iface;
struct eswifi_bus_ops *bus;
struct eswifi_gpio resetn;
struct eswifi_gpio wakeup;
scan_result_cb_t scan_cb;
struct k_work_q work_q;
struct k_work request_work;
struct eswifi_sta sta;
enum eswifi_request req;
enum eswifi_role role;
char buf[MAX_DATA_SIZE];
struct k_mutex mutex;
void *bus_data;
struct eswifi_off_socket socket[ESWIFI_OFFLOAD_MAX_SOCKETS];
};
struct eswifi_bus_ops {
int (*init)(struct eswifi_dev *eswifi);
int (*request)(struct eswifi_dev *eswifi, char *cmd, size_t clen,
char *rsp, size_t rlen);
};
static inline int eswifi_request(struct eswifi_dev *eswifi, char *cmd,
size_t clen, char *rsp, size_t rlen)
{
return eswifi->bus->request(eswifi, cmd, clen, rsp, rlen);
}
static inline void eswifi_lock(struct eswifi_dev *eswifi)
{
k_mutex_lock(&eswifi->mutex, K_FOREVER);
}
static inline void eswifi_unlock(struct eswifi_dev *eswifi)
{
k_mutex_unlock(&eswifi->mutex);
}
struct eswifi_bus_ops eswifi_bus_ops_spi;
int eswifi_offload_init(struct eswifi_dev *eswifi);
struct eswifi_dev *eswifi_by_iface_idx(u8_t iface);
bool eswifi_is_buf_at_ok(char *str);
#endif

View file

@ -0,0 +1,249 @@
/**
* Copyright (c) 2018 Linaro
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_WIFI_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(wifi_eswifi_bus_spi);
#include <zephyr.h>
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <errno.h>
#include <gpio.h>
#include <spi.h>
#include "eswifi.h"
#define ESWIFI_SPI_THREAD_STACK_SIZE 1024
K_THREAD_STACK_MEMBER(eswifi_spi_poll_stack, ESWIFI_SPI_THREAD_STACK_SIZE);
struct eswifi_spi_data {
struct device *spi_dev;
struct eswifi_gpio csn;
struct eswifi_gpio dr;
struct k_thread poll_thread;
struct spi_config spi_cfg;
struct spi_cs_control spi_cs;
};
static struct eswifi_spi_data eswifi_spi0; /* Static instance */
static bool eswifi_spi_cmddata_ready(struct eswifi_spi_data *spi)
{
int value;
gpio_pin_read(spi->dr.dev, spi->dr.pin, &value);
return value ? true : false;
}
static int eswifi_spi_wait_cmddata_ready(struct eswifi_spi_data *spi)
{
unsigned int max_retries = 60 * 1000; /* 1 minute */
do {
/* allow other threads to be scheduled */
k_sleep(1);
} while (!eswifi_spi_cmddata_ready(spi) && --max_retries);
return max_retries ? 0 : -ETIMEDOUT;
}
static int eswifi_spi_write(struct eswifi_dev *eswifi, char *data, size_t dlen)
{
struct eswifi_spi_data *spi = eswifi->bus_data;
struct spi_buf spi_tx_buf[1];
struct spi_buf_set spi_tx;
int status;
spi_tx_buf[0].buf = data;
spi_tx_buf[0].len = dlen / 2; /* 16-bit words */
spi_tx.buffers = spi_tx_buf;
spi_tx.count = ARRAY_SIZE(spi_tx_buf);
status = spi_write(spi->spi_dev, &spi->spi_cfg, &spi_tx);
if (status) {
LOG_ERR("SPI write error %d", status);
} else {
status = dlen;
}
return status;
}
static int eswifi_spi_read(struct eswifi_dev *eswifi, char *data, size_t dlen)
{
struct eswifi_spi_data *spi = eswifi->bus_data;
struct spi_buf spi_rx_buf[1];
struct spi_buf_set spi_rx;
int status;
spi_rx_buf[0].buf = data;
spi_rx_buf[0].len = dlen / 2; /* 16-bit words */
spi_rx.buffers = spi_rx_buf;
spi_rx.count = ARRAY_SIZE(spi_rx_buf);
status = spi_read(spi->spi_dev, &spi->spi_cfg, &spi_rx);
if (status) {
LOG_ERR("SPI read error %d", status);
} else {
status = dlen;
}
return status;
}
static int eswifi_spi_request(struct eswifi_dev *eswifi, char *cmd, size_t clen,
char *rsp, size_t rlen)
{
struct eswifi_spi_data *spi = eswifi->bus_data;
char tmp[2];
int err;
LOG_DBG("cmd=%p (%u byte), rsp=%p (%u byte)", cmd, clen, rsp, rlen);
/*
* CMD/DATA protocol:
* 1. Module raises data-ready when ready for **command phase**
* 2. Host announces command start by lowering chip-select (csn)
* 3. Host write the command (possibly several spi transfers)
* 4. Host announces end of command by raising chip-select
* 5. Module lowers data-ready signal
* 6. Module raises data-ready to signal start of the **data phase**
* 7. Host lowers chip-select
* 8. Host fetch data as long as data-ready pin is up
* 9. Module lowers data-ready to signal the end of the data Phase
* 10. Host raises chip-select
*
* Note:
* All commands to the eS-WiFi module must be post-padded with
* 0x0A (Line Feed) to an even number of bytes.
* All data from eS-WiFi module are post-padded with 0x15(NAK) to an
* even number of bytes.
*/
if (!cmd) {
goto data;
}
/* CMD/DATA READY signals the Command Phase */
err = eswifi_spi_wait_cmddata_ready(spi);
if (err) {
LOG_ERR("CMD ready timeout\n");
return err;
}
if (clen % 2) { /* Add post-padding if necessary */
/* cmd is a string so cmd[clen] is 0x00 */
cmd[clen] = 0x0a;
clen++;
}
eswifi_spi_write(eswifi, cmd, clen);
/* Our device is flagged with SPI_HOLD_ON_CS|SPI_LOCK_ON, release */
spi_release(spi->spi_dev, &spi->spi_cfg);
data:
/* CMD/DATA READY signals the Data Phase */
err = eswifi_spi_wait_cmddata_ready(spi);
if (err) {
LOG_ERR("DATA ready timeout\n");
return err;
}
eswifi_spi_read(eswifi, rsp, rlen);
k_sleep(1);
while (eswifi_spi_cmddata_ready(spi)) {
eswifi_spi_read(eswifi, tmp, 2);
k_sleep(1);
}
/* Our device is flagged with SPI_HOLD_ON_CS|SPI_LOCK_ON, release */
spi_release(spi->spi_dev, &spi->spi_cfg);
LOG_DBG("success");
return 0;
}
static void eswifi_spi_read_msg(struct eswifi_dev *eswifi)
{
char cmd[] = "MR\r";
int err;
eswifi_lock(eswifi);
err = eswifi_request(eswifi, cmd, strlen(cmd),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to read msg %d", err);
}
eswifi_unlock(eswifi);
}
static void eswifi_spi_poll_thread(void *p1)
{
struct eswifi_dev *eswifi = p1;
while (1) {
k_sleep(K_MSEC(1000));
eswifi_spi_read_msg(eswifi);
}
}
int eswifi_spi_init(struct eswifi_dev *eswifi)
{
struct eswifi_spi_data *spi = &eswifi_spi0; /* Static instance */
/* SPI DEV */
spi->spi_dev = device_get_binding("SPI_3");
if (!spi->spi_dev) {
LOG_ERR("Failed to initialize SPI driver");
return -ENODEV;
}
/* SPI DATA READY PIN */
spi->dr.dev = device_get_binding(ESWIFI0_DATA_GPIOS_CONTROLLER);
if (!spi->dr.dev) {
LOG_ERR("Failed to initialize GPIO driver: %s",
ESWIFI0_DATA_GPIOS_CONTROLLER);
return -ENODEV;
}
spi->dr.pin = ESWIFI0_DATA_GPIOS_PIN;
gpio_pin_configure(spi->dr.dev, spi->dr.pin, GPIO_DIR_IN);
/* SPI CONFIG/CS */
spi->spi_cfg.frequency = ESWIFI0_SPI_MAX_FREQUENCY;
spi->spi_cfg.operation = (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB |
SPI_WORD_SET(16) | SPI_LINES_SINGLE |
SPI_HOLD_ON_CS | SPI_LOCK_ON);
spi->spi_cfg.slave = ESWIFI0_BASE_ADDRESS;
spi->spi_cs.gpio_dev = device_get_binding(ESWIFI0_CS_GPIOS_CONTROLLER);
spi->spi_cs.gpio_pin = ESWIFI0_CS_GPIOS_PIN;
spi->spi_cs.delay = 1000;
spi->spi_cfg.cs = &spi->spi_cs;
eswifi->bus_data = spi;
LOG_DBG("success");
k_thread_create(&spi->poll_thread, eswifi_spi_poll_stack,
ESWIFI_SPI_THREAD_STACK_SIZE,
(k_thread_entry_t)eswifi_spi_poll_thread, eswifi, NULL,
NULL, K_PRIO_COOP(CONFIG_WIFI_ESWIFI_THREAD_PRIO), 0,
K_NO_WAIT);
return 0;
}
struct eswifi_bus_ops eswifi_bus_ops_spi = {
.init = eswifi_spi_init,
.request = eswifi_spi_request,
};

View file

@ -0,0 +1,502 @@
/**
* Copyright (c) 2018 Linaro
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_WIFI_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(wifi_eswifi_core);
#include <zephyr.h>
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <errno.h>
#include <gpio.h>
#include <net/net_pkt.h>
#include <net/net_if.h>
#include <net/net_context.h>
#include <net/net_offload.h>
#include <net/wifi_mgmt.h>
#include <net/ethernet.h>
#include <net_private.h>
#include <net/net_core.h>
#include <net/net_pkt.h>
#include <stdio.h>
#include <stdlib.h>
#include <misc/printk.h>
#include "eswifi.h"
#define ESWIFI_WORKQUEUE_STACK_SIZE 1024
K_THREAD_STACK_DEFINE(eswifi_work_q_stack, ESWIFI_WORKQUEUE_STACK_SIZE);
static struct eswifi_dev eswifi0; /* static instance */
static int eswifi_reset(struct eswifi_dev *eswifi)
{
gpio_pin_write(eswifi->resetn.dev, eswifi->resetn.pin, 0);
k_sleep(10);
gpio_pin_write(eswifi->resetn.dev, eswifi->resetn.pin, 1);
gpio_pin_write(eswifi->wakeup.dev, eswifi->wakeup.pin, 1);
k_sleep(500);
/* fetch the cursor */
eswifi_request(eswifi, NULL, 0, eswifi->buf, sizeof(eswifi->buf));
return 0;
}
static inline int __parse_ssid(char *str, char *ssid)
{
/* fnt => '"SSID"' */
if (!*str || (*str != '"')) {
return -EINVAL;
}
str++;
while (*str && (*str != '"')) {
*ssid++ = *str++;
}
*ssid = '\0';
if (*str != '"') {
return -EINVAL;
}
return -EINVAL;
}
static void __parse_scan_res(char *str, struct wifi_scan_result *res)
{
int field = 0;
/* fmt => #001,"SSID",MACADDR,RSSI,BITRATE,MODE,SECURITY,BAND,CHANNEL */
while (*str) {
if (*str != ',') {
str++;
continue;
}
if (!*++str) {
break;
}
switch (++field) {
case 1: /* SSID */
__parse_ssid(str, res->ssid);
res->ssid_length = strlen(res->ssid);
str += res->ssid_length;
break;
case 2: /* mac addr */
break;
case 3: /* RSSI */
res->rssi = atoi(str);
break;
case 4: /* bitrate */
break;
case 5: /* mode */
break;
case 6: /* security */
if (!strncmp(str, "Open", 4)) {
res->security = WIFI_SECURITY_TYPE_NONE;
} else {
res->security = WIFI_SECURITY_TYPE_PSK;
}
break;
case 7: /* band */
break;
case 8: /* channel */
res->channel = atoi(str);
break;
}
}
}
struct eswifi_dev *eswifi_by_iface_idx(u8_t iface)
{
/* only one instance */
LOG_DBG("%d", iface);
return &eswifi0;
}
static int __parse_ipv4_address(char *str, char *ssid, u8_t ip[4])
{
unsigned int byte = -1;
/* fmt => [JOIN ] SSID,192.168.2.18,0,0 */
while (*str) {
if (byte == -1) {
if (!strncmp(str, ssid, strlen(ssid))) {
byte = 0;
str += strlen(ssid);
}
str++;
continue;
}
ip[byte++] = atoi(str);
while (*str && (*str++ != '.')) {
}
}
return 0;
}
bool eswifi_is_buf_at_ok(char *str)
{
char at_ok[] = "OK\r\n> ";
while (*str) {
if (!strncmp(str++, at_ok, sizeof(at_ok) - 1)) {
return true;
}
}
return false;
}
static int eswifi_scan(struct eswifi_dev *eswifi)
{
char cmd[] = "F0\r";
int i, err;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err) {
eswifi_unlock(eswifi);
return err;
}
for (i = 0; i < sizeof(eswifi->buf); i++) {
if (eswifi->buf[i] == '#') {
struct wifi_scan_result res = {0};
__parse_scan_res(&eswifi->buf[i], &res);
eswifi->scan_cb(eswifi->iface, 0, &res);
k_yield();
while (eswifi->buf[i] != '\n')
i++;
}
}
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_connect(struct eswifi_dev *eswifi)
{
char connect[] = "C0\r";
struct in_addr addr;
int err;
LOG_DBG("Connecting to %s (pass=%s)", eswifi->sta.ssid,
eswifi->sta.pass);
eswifi_lock(eswifi);
/* Set SSID */
snprintf(eswifi->buf, sizeof(eswifi->buf), "C1=%s\r", eswifi->sta.ssid);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set SSID");
goto error;
}
/* Set passphrase */
snprintf(eswifi->buf, sizeof(eswifi->buf), "C2=%s\r", eswifi->sta.pass);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set passphrase");
goto error;
}
/* Set Security type */
snprintf(eswifi->buf, sizeof(eswifi->buf), "C3=%u\r",
eswifi->sta.security);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to configure security");
goto error;
}
/* Join Network */
err = eswifi_request(eswifi, connect, strlen(connect),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to join network");
goto error;
}
/* Any IP assigned ? (dhcp offload or manually) */
err = __parse_ipv4_address(eswifi->buf, eswifi->sta.ssid,
(u8_t *)&addr.s4_addr);
if (err) {
LOG_ERR("Unable to retrieve IP address");
goto error;
}
LOG_DBG("ip = %d.%d.%d.%d", addr.s4_addr[0], addr.s4_addr[1],
addr.s4_addr[2], addr.s4_addr[3]);
net_if_ipv4_addr_add(eswifi->iface, &addr, NET_ADDR_DHCP, 0);
LOG_DBG("Connected!");
eswifi_unlock(eswifi);
return 0;
error:
eswifi_unlock(eswifi);
return -EIO;
}
static int eswifi_disconnect(struct eswifi_dev *eswifi)
{
char disconnect[] = "CD\r";
int err;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_request(eswifi, disconnect, strlen(disconnect),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to disconnect network");
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
static void eswifi_request_work(struct k_work *item)
{
struct eswifi_dev *eswifi;
int err;
LOG_DBG("");
eswifi = CONTAINER_OF(item, struct eswifi_dev, request_work);
switch (eswifi->req) {
case ESWIFI_REQ_CONNECT:
err = eswifi_connect(eswifi);
wifi_mgmt_raise_connect_result_event(eswifi->iface, err);
break;
case ESWIFI_REQ_DISCONNECT:
err = eswifi_disconnect(eswifi);
wifi_mgmt_raise_disconnect_result_event(eswifi->iface, err);
break;
case ESWIFI_REQ_SCAN:
eswifi_scan(eswifi);
break;
case ESWIFI_REQ_NONE:
default:
break;
}
}
static int eswifi_get_mac_addr(struct eswifi_dev *eswifi, u8_t addr[6])
{
char cmd[] = "Z5\r";
int err, i, byte = 0;
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err) {
return err;
}
for (i = 0; i < sizeof(eswifi->buf); i++) {
if (i < 2) {
continue;
}
if (eswifi->buf[i] == ':' ||
((byte == 5) && (eswifi->buf[i] == '\r'))) {
addr[byte++] = strtol(&eswifi->buf[i - 2], NULL, 16);
}
}
if (byte != 6) {
return -EIO;
}
return 0;
}
static void eswifi_iface_init(struct net_if *iface)
{
struct eswifi_dev *eswifi = &eswifi0;
u8_t mac[6];
int err;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_reset(eswifi);
if (err) {
LOG_ERR("Unable to reset device");
return;
}
err = eswifi_get_mac_addr(eswifi, mac);
if (err) {
LOG_ERR("Unable to read MAC address");
return;
}
LOG_DBG("MAC Address %02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
net_if_set_link_addr(iface, mac, sizeof(mac), NET_LINK_ETHERNET);
eswifi->iface = iface;
eswifi_unlock(eswifi);
eswifi_offload_init(eswifi);
}
static int eswifi_mgmt_scan(struct device *dev, scan_result_cb_t cb)
{
struct eswifi_dev *eswifi = dev->driver_data;
LOG_DBG("");
eswifi_lock(eswifi);
eswifi->scan_cb = cb;
eswifi->req = ESWIFI_REQ_SCAN;
k_work_submit_to_queue(&eswifi->work_q, &eswifi->request_work);
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_mgmt_disconnect(struct device *dev)
{
struct eswifi_dev *eswifi = dev->driver_data;
LOG_DBG("");
eswifi_lock(eswifi);
eswifi->req = ESWIFI_REQ_DISCONNECT;
k_work_submit_to_queue(&eswifi->work_q, &eswifi->request_work);
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_mgmt_connect(struct device *dev,
struct wifi_connect_req_params *params)
{
struct eswifi_dev *eswifi = dev->driver_data;
LOG_DBG("");
eswifi_lock(eswifi);
memcpy(eswifi->sta.ssid, params->ssid, params->ssid_length);
eswifi->sta.ssid[params->ssid_length] = '\0';
switch (params->security) {
case WIFI_SECURITY_TYPE_NONE:
eswifi->sta.pass[0] = '\0';
eswifi->sta.security = ESWIFI_SEC_OPEN;
break;
case WIFI_SECURITY_TYPE_PSK:
memcpy(eswifi->sta.pass, params->psk, params->psk_length);
eswifi->sta.pass[params->psk_length] = '\0';
eswifi->sta.security = ESWIFI_SEC_WPA2_MIXED;
break;
default:
LOG_ERR("Unsupported security type %d", params->security);
eswifi_unlock(eswifi);
return -EINVAL;
}
eswifi->req = ESWIFI_REQ_CONNECT;
k_work_submit_to_queue(&eswifi->work_q, &eswifi->request_work);
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_init(struct device *dev)
{
struct eswifi_dev *eswifi = dev->driver_data;
LOG_DBG("");
eswifi->role = ESWIFI_ROLE_CLIENT;
k_mutex_init(&eswifi->mutex);
eswifi->bus = &eswifi_bus_ops_spi;
eswifi->bus->init(eswifi);
eswifi->resetn.dev = device_get_binding(ESWIFI0_RESETN_GPIOS_CONTROLLER);
if (!eswifi->resetn.dev) {
LOG_ERR("Failed to initialize GPIO driver: %s",
ESWIFI0_RESETN_GPIOS_CONTROLLER);
}
eswifi->resetn.pin = ESWIFI0_RESETN_GPIOS_PIN;
gpio_pin_configure(eswifi->resetn.dev, eswifi->resetn.pin,
GPIO_DIR_OUT);
eswifi->wakeup.dev = device_get_binding(ESWIFI0_WAKEUP_GPIOS_CONTROLLER);
if (!eswifi->wakeup.dev) {
LOG_ERR("Failed to initialize GPIO driver: %s",
ESWIFI0_WAKEUP_GPIOS_CONTROLLER);
}
eswifi->wakeup.pin = ESWIFI0_WAKEUP_GPIOS_PIN;
gpio_pin_configure(eswifi->wakeup.dev, eswifi->wakeup.pin,
GPIO_DIR_OUT);
gpio_pin_write(eswifi->wakeup.dev, eswifi->wakeup.pin, 1);
k_work_q_start(&eswifi->work_q, eswifi_work_q_stack,
K_THREAD_STACK_SIZEOF(eswifi_work_q_stack),
CONFIG_SYSTEM_WORKQUEUE_PRIORITY - 1);
k_work_init(&eswifi->request_work, eswifi_request_work);
return 0;
}
static const struct net_wifi_mgmt_offload eswifi_offload_api = {
.iface_api.init = eswifi_iface_init,
.iface_api.send = NULL,
.scan = eswifi_mgmt_scan,
.connect = eswifi_mgmt_connect,
.disconnect = eswifi_mgmt_disconnect,
};
NET_DEVICE_OFFLOAD_INIT(eswifi_mgmt, CONFIG_WIFI_ESWIFI_NAME,
eswifi_init, &eswifi0, NULL,
CONFIG_WIFI_INIT_PRIORITY, &eswifi_offload_api, 1500);

View file

@ -0,0 +1,514 @@
/**
* Copyright (c) 2018 Linaro
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_LEVEL CONFIG_WIFI_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(wifi_eswifi_offload);
#include <zephyr.h>
#include <kernel.h>
#include <device.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <net/net_pkt.h>
#include <net/net_if.h>
#include "eswifi.h"
#define ESWIFI_OFFLOAD_THREAD_STACK_SIZE 1024
K_THREAD_STACK_MEMBER(eswifi_data_read_stack, ESWIFI_OFFLOAD_THREAD_STACK_SIZE);
struct k_thread data_read_thread;
struct eswifi_offload {
struct eswifi_off_socket socket[ESWIFI_OFFLOAD_MAX_SOCKETS];
};
static int __select_socket(struct eswifi_dev *eswifi, u8_t idx)
{
int err;
snprintf(eswifi->buf, sizeof(eswifi->buf), "P0=%d\r", idx);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
return -EIO;
}
return 0;
}
static int __read_data(struct eswifi_dev *eswifi, size_t len)
{
char cmd[] = "R0\r";
char size[] = "R1=9999\r";
char timeout[] = "R2=30000\r";
int err, i, read = 0;
/* Set max read size */
snprintf(size, sizeof(eswifi->buf), "R1=%u\r", len);
err = eswifi_request(eswifi, size, strlen(size),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set read size");
return -EIO;
}
/* Set timeout */
snprintf(timeout, sizeof(eswifi->buf), "R2=%u\r", 30); /* 30 ms */
err = eswifi_request(eswifi, timeout, strlen(timeout),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set timeout");
return -EIO;
}
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err) {
return -EIO;
}
/* find payload size */
/* '\r\n''paylod'\r\n''OK''\r\n''> ' */
for (i = 0; i < sizeof(eswifi->buf); i++) {
if (!strncmp(&eswifi->buf[i], AT_OK_STR, AT_OK_STR_LEN)) {
read = i - AT_RSP_DELIMITER_LEN;
break;
}
}
return read;
}
static int eswifi_off_get(sa_family_t family,
enum net_sock_type type,
enum net_ip_protocol ip_proto,
struct net_context **context)
{
struct eswifi_dev *eswifi = eswifi_by_iface_idx((*context)->iface);
struct eswifi_off_socket *socket = NULL;
int err, i;
LOG_DBG("");
if (family != AF_INET) {
LOG_ERR("Only AF_INET is supported!");
return -EPFNOSUPPORT;
}
if (ip_proto != IPPROTO_TCP) {
/* TODO: add UDP */
LOG_ERR("Only TCP supported");
return -EPROTONOSUPPORT;
}
eswifi_lock(eswifi);
/* pickup available socket */
for (i = 0; i < ESWIFI_OFFLOAD_MAX_SOCKETS; i++) {
if (!eswifi->socket[i].context) {
socket = &eswifi->socket[i];
socket->index = i;
socket->context = *context;
(*context)->offload_context = socket;
break;
}
}
if (!socket) {
LOG_ERR("No socket resource available");
eswifi_unlock(eswifi);
return -ENOMEM;
}
err = __select_socket(eswifi, socket->index);
if (err) {
LOG_ERR("Unable to select socket %u", socket->index);
eswifi_unlock(eswifi);
return -EIO;
}
/* Set Transport Protocol */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P1=%d\r",
ESWIFI_TRANSPORT_TCP);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set transport protocol");
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_bind(struct net_context *context,
const struct sockaddr *addr,
socklen_t addrlen)
{
struct eswifi_off_socket *socket = context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
int err;
if (addr->sa_family != AF_INET) {
LOG_ERR("Only AF_INET is supported!");
return -EPFNOSUPPORT;
}
LOG_DBG("");
eswifi_lock(eswifi);
__select_socket(eswifi, socket->index);
/* Set Local Port */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P2=%d\r",
(u16_t)sys_be16_to_cpu(net_sin(addr)->sin_port));
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set local port");
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_listen(struct net_context *context, int backlog)
{
/* TODO */
LOG_ERR("");
return -ENOTSUP;
}
static int eswifi_off_connect(struct net_context *context,
const struct sockaddr *addr,
socklen_t addrlen,
net_context_connect_cb_t cb,
s32_t timeout,
void *user_data)
{
struct eswifi_off_socket *socket = context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
struct in_addr *sin_addr = &net_sin(addr)->sin_addr;
int err;
if (addr->sa_family != AF_INET) {
LOG_ERR("Only AF_INET is supported!");
return -EPFNOSUPPORT;
}
eswifi_lock(eswifi);
/* Set Remote IP */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P3=%u.%u.%u.%u\r",
sin_addr->s4_addr[0], sin_addr->s4_addr[1],
sin_addr->s4_addr[2], sin_addr->s4_addr[3]);
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set remote ip");
eswifi_unlock(eswifi);
return -EIO;
}
/* Set Remote Port */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P4=%d\r",
(u16_t)sys_be16_to_cpu(net_sin(addr)->sin_port));
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to set remote port");
eswifi_unlock(eswifi);
return -EIO;
}
/* Start TCP client */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P6=1\r");
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to connect");
eswifi_unlock(eswifi);
return -EIO;
}
socket->state = ESWIFI_SOCKET_STATE_CONNECTED;
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_accept(struct net_context *context,
net_tcp_accept_cb_t cb,
s32_t timeout,
void *user_data)
{
/* TODO */
LOG_DBG("");
return -ENOTSUP;
}
static int eswifi_off_send(struct net_pkt *pkt,
net_context_send_cb_t cb,
s32_t timeout,
void *token,
void *user_data)
{
struct eswifi_off_socket *socket = pkt->context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(socket->context->iface);
unsigned int bytes;
struct net_buf *frag;
int err, offset;
bytes = net_pkt_get_len(pkt);
LOG_DBG("%u bytes", bytes);
eswifi_lock(eswifi);
__select_socket(eswifi, socket->index);
/* header */
snprintf(eswifi->buf, sizeof(eswifi->buf), "S3=%u\r", bytes);
offset = strlen(eswifi->buf);
/* copy payload */
for (frag = pkt->frags; frag; frag = frag->frags) {
memcpy(&eswifi->buf[offset], frag->data, frag->len);
offset += frag->len;
}
err = eswifi_request(eswifi, eswifi->buf, offset + 1,
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to send data");
eswifi_unlock(eswifi);
return -EIO;
}
net_pkt_unref(pkt);
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_sendto(struct net_pkt *pkt,
const struct sockaddr *dst_addr,
socklen_t addrlen,
net_context_send_cb_t cb,
s32_t timeout,
void *token,
void *user_data)
{
/* TODO */
LOG_DBG("");
return -ENOTSUP;
}
static int eswifi_off_recv(struct net_context *context,
net_context_recv_cb_t cb,
s32_t timeout,
void *user_data)
{
struct eswifi_off_socket *socket = context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
/* TODO */
LOG_DBG("");
eswifi_lock(eswifi);
socket->recv_cb = cb;
socket->user_data = user_data;
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_put(struct net_context *context)
{
struct eswifi_off_socket *socket = context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
int err;
LOG_DBG("");
eswifi_lock(eswifi);
__select_socket(eswifi, socket->index);
socket->context = NULL;
socket->state = ESWIFI_SOCKET_STATE_NONE;
/* Stop TCP client */
snprintf(eswifi->buf, sizeof(eswifi->buf), "P6=0\r");
err = eswifi_request(eswifi, eswifi->buf, strlen(eswifi->buf),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
LOG_ERR("Unable to connect");
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
static struct net_offload eswifi_offload = {
.get = eswifi_off_get,
.bind = eswifi_off_bind,
.listen = eswifi_off_listen,
.connect = eswifi_off_connect,
.accept = eswifi_off_accept,
.send = eswifi_off_send,
.sendto = eswifi_off_sendto,
.recv = eswifi_off_recv,
.put = eswifi_off_put,
};
static void eswifi_off_read_data(struct eswifi_dev *eswifi)
{
int i;
LOG_DBG("");
eswifi_lock(eswifi);
if (!eswifi->iface) { /* not yet initialized */
eswifi_unlock(eswifi);
return;
}
for (i = 0; i < ESWIFI_OFFLOAD_MAX_SOCKETS; i++) {
struct eswifi_off_socket *socket = &eswifi->socket[i];
struct net_pkt *pkt;
int err, len;
if (socket->state != ESWIFI_SOCKET_STATE_CONNECTED) {
continue;
}
err = __select_socket(eswifi, i);
if (err) {
continue;
}
len = __read_data(eswifi, 1460); /* 1460 is max size */
if (len <= 0 /*|| !socket->recv_cb*/) {
continue;
}
LOG_DBG("payload sz = %d", len);
pkt = net_pkt_get_reserve_rx(0, K_NO_WAIT);
if (!pkt) {
LOG_ERR("Cannot allocate rx packet");
continue;
}
if (!net_pkt_append_all(pkt, len,
eswifi->buf + AT_RSP_DELIMITER_LEN,
K_NO_WAIT)) {
LOG_WRN("Incomplete buffer copy");
}
if (!socket->recv_cb) {
net_pkt_unref(pkt);
continue;
}
socket->recv_cb(socket->context, pkt, 0, socket->user_data);
}
eswifi_unlock(eswifi);
}
static void eswifi_off_data_read_thread(void *p1)
{
struct eswifi_dev *eswifi = p1;
while (1) {
k_sleep(K_MSEC(500));
eswifi_off_read_data(eswifi);
}
}
static int eswifi_off_enable_dhcp(struct eswifi_dev *eswifi)
{
char cmd[] = "C4=1\r";
int err;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_request(eswifi, cmd, strlen(cmd),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_off_disable_bypass(struct eswifi_dev *eswifi)
{
char cmd[] = "PR=0\r";
int err;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return 0;
}
int eswifi_offload_init(struct eswifi_dev *eswifi)
{
eswifi->iface->if_dev->offload = &eswifi_offload;
int err;
k_thread_create(&data_read_thread, eswifi_data_read_stack,
ESWIFI_OFFLOAD_THREAD_STACK_SIZE,
(k_thread_entry_t)&eswifi_off_data_read_thread, eswifi,
NULL, NULL, K_PRIO_COOP(CONFIG_WIFI_ESWIFI_THREAD_PRIO),
0, K_NO_WAIT);
err = eswifi_off_enable_dhcp(eswifi);
if (err) {
LOG_ERR("Unable to configure dhcp");
return err;
}
err = eswifi_off_disable_bypass(eswifi);
if (err) {
LOG_ERR("Unable to disable bypass mode");
return err;
}
return 0;
}

View file

@ -0,0 +1,37 @@
/**
* Copyright (c) 2018 Linaro
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_WIFI_ESWIFI_ESWIFI_OFFLOAD_H_
#define ZEPHYR_DRIVERS_WIFI_ESWIFI_ESWIFI_OFFLOAD_H_
#include <net/net_offload.h>
#include "eswifi.h"
#define ESWIFI_OFFLOAD_MAX_SOCKETS 4
enum eswifi_transport_type {
ESWIFI_TRANSPORT_TCP,
ESWIFI_TRANSPORT_UDP,
ESWIFI_TRANSPORT_UDP_LITE,
ESWIFI_TRANSPORT_TCP_SSL,
};
enum eswifi_socket_state {
ESWIFI_SOCKET_STATE_NONE,
ESWIFI_SOCKET_STATE_CONNECTED,
};
struct eswifi_off_socket {
u8_t index;
enum eswifi_transport_type type;
enum eswifi_socket_state state;
struct net_context *context;
net_context_recv_cb_t recv_cb;
void *user_data;
};
#endif