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:
parent
a94f97b4b3
commit
0b8fde39e4
9 changed files with 1451 additions and 0 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
14
drivers/wifi/eswifi/CMakeLists.txt
Normal file
14
drivers/wifi/eswifi/CMakeLists.txt
Normal 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()
|
28
drivers/wifi/eswifi/Kconfig.eswifi
Normal file
28
drivers/wifi/eswifi/Kconfig.eswifi
Normal 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
|
105
drivers/wifi/eswifi/eswifi.h
Normal file
105
drivers/wifi/eswifi/eswifi.h
Normal 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
|
249
drivers/wifi/eswifi/eswifi_bus_spi.c
Normal file
249
drivers/wifi/eswifi/eswifi_bus_spi.c
Normal 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,
|
||||
};
|
502
drivers/wifi/eswifi/eswifi_core.c
Normal file
502
drivers/wifi/eswifi/eswifi_core.c
Normal 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);
|
514
drivers/wifi/eswifi/eswifi_offload.c
Normal file
514
drivers/wifi/eswifi/eswifi_offload.c
Normal 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;
|
||||
}
|
37
drivers/wifi/eswifi/eswifi_offload.h
Normal file
37
drivers/wifi/eswifi/eswifi_offload.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue