wifi: eswifi: Add controller at command helpers

Create eswifi_at_cmd and eswifi_at_cmd_rsp helpers, allowing to send an
at command and parse the at response. These methods return success if
the response contains the OK* string. The eswifi_at_cmd_rsp method
extracts response content/size (DATA) on success.

*Response format is:
\r\n[DATA]\r\nOK\r\n>
Where DATA can be arbitrary (ASCII or not).

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
This commit is contained in:
Loic Poulain 2018-12-21 16:00:56 +01:00 committed by Anas Nashif
commit 654d93999e
4 changed files with 140 additions and 153 deletions

View file

@ -98,6 +98,7 @@ static inline void eswifi_unlock(struct eswifi_dev *eswifi)
extern 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);
int eswifi_at_cmd_rsp(struct eswifi_dev *eswifi, char *cmd, char **rsp);
int eswifi_at_cmd(struct eswifi_dev *eswifi, char *cmd);
#endif

View file

@ -20,6 +20,8 @@ LOG_MODULE_REGISTER(wifi_eswifi_bus_spi);
#define ESWIFI_SPI_THREAD_STACK_SIZE 1024
K_THREAD_STACK_MEMBER(eswifi_spi_poll_stack, ESWIFI_SPI_THREAD_STACK_SIZE);
#define SPI_READ_CHUNK_SIZE 32
struct eswifi_spi_data {
struct device *spi_dev;
struct eswifi_gpio csn;
@ -100,6 +102,7 @@ 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;
unsigned int offset = 0, to_read = SPI_READ_CHUNK_SIZE;
char tmp[2];
int err;
@ -155,9 +158,15 @@ data:
return err;
}
eswifi_spi_read(eswifi, rsp, rlen);
k_sleep(1);
while (eswifi_spi_cmddata_ready(spi) && to_read) {
to_read = min(rlen - offset, to_read);
memset(rsp + offset, 0, to_read);
eswifi_spi_read(eswifi, rsp + offset, to_read);
offset += to_read;
k_yield();
}
/* Flush remaining data if receiving buffer not large enough */
while (eswifi_spi_cmddata_ready(spi)) {
eswifi_spi_read(eswifi, tmp, 2);
k_sleep(1);
@ -168,19 +177,19 @@ data:
LOG_DBG("success");
return 0;
return offset;
}
static void eswifi_spi_read_msg(struct eswifi_dev *eswifi)
{
char cmd[] = "MR\r";
char *rsp;
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)) {
err = eswifi_at_cmd_rsp(eswifi, cmd, &rsp);
if (err < 0) {
LOG_ERR("Unable to read msg %d", err);
}

View file

@ -119,6 +119,54 @@ static void __parse_scan_res(char *str, struct wifi_scan_result *res)
}
}
int eswifi_at_cmd_rsp(struct eswifi_dev *eswifi, char *cmd, char **rsp)
{
const char startstr[] = "\r\n";
const char endstr[] = "\r\nOK\r\n>";
int i, len, rsplen = -EINVAL;
len = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (len < 0) {
return -EIO;
}
/*
* Check response, format should be "\r\n[DATA]\r\nOK\r\n>"
* Data is in arbitrary format (not only ASCII)
*/
/* Check start characters */
if (strncmp(eswifi->buf, startstr, strlen(startstr))) {
return -EINVAL;
}
if (len < sizeof(endstr) - 1 + sizeof(startstr) - 1) {
return -EINVAL;
}
/* Check end characters */
for (i = len - sizeof(endstr); i > 0; i--) {
if (!strncmp(&eswifi->buf[i], endstr, 7)) {
if (rsp) {
eswifi->buf[i] = '\0';
*rsp = &eswifi->buf[2];
rsplen = &eswifi->buf[i] - *rsp;
} else {
rsplen = 0;
}
break;
}
}
return rsplen;
}
int eswifi_at_cmd(struct eswifi_dev *eswifi, char *cmd)
{
return eswifi_at_cmd_rsp(eswifi, cmd, NULL);
}
struct eswifi_dev *eswifi_by_iface_idx(u8_t iface)
{
/* only one instance */
@ -149,58 +197,45 @@ static int __parse_ipv4_address(char *str, char *ssid, u8_t ip[4])
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)
static void eswifi_scan(struct eswifi_dev *eswifi)
{
char cmd[] = "F0\r";
int i, err;
char *data;
int i, ret;
LOG_DBG("");
eswifi_lock(eswifi);
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err) {
ret = eswifi_at_cmd_rsp(eswifi, cmd, &data);
if (ret < 0) {
eswifi->scan_cb(eswifi->iface, -EIO, NULL);
eswifi_unlock(eswifi);
return err;
return;
}
for (i = 0; i < sizeof(eswifi->buf); i++) {
if (eswifi->buf[i] == '#') {
for (i = 0; i < ret; i++) {
if (data[i] == '#') {
struct wifi_scan_result res = {0};
__parse_scan_res(&eswifi->buf[i], &res);
__parse_scan_res(&data[i], &res);
eswifi->scan_cb(eswifi->iface, 0, &res);
k_yield();
while (eswifi->buf[i] != '\n')
while (data[i] && data[i] != '\n')
i++;
}
}
eswifi_unlock(eswifi);
return 0;
}
static int eswifi_connect(struct eswifi_dev *eswifi)
{
char connect[] = "C0\r";
struct in_addr addr;
char *rsp;
int err;
LOG_DBG("Connecting to %s (pass=%s)", eswifi->sta.ssid,
@ -210,18 +245,16 @@ static int eswifi_connect(struct eswifi_dev *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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set passphrase");
goto error;
}
@ -229,25 +262,23 @@ static int eswifi_connect(struct eswifi_dev *eswifi)
/* 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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
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)) {
err = eswifi_at_cmd_rsp(eswifi, connect, &rsp);
if (err < 0) {
LOG_ERR("Unable to join network");
goto error;
}
/* Any IP assigned ? (dhcp offload or manually) */
err = __parse_ipv4_address(eswifi->buf, eswifi->sta.ssid,
err = __parse_ipv4_address(rsp, eswifi->sta.ssid,
(u8_t *)&addr.s4_addr);
if (err) {
if (err < 0) {
LOG_ERR("Unable to retrieve IP address");
goto error;
}
@ -276,17 +307,15 @@ static int eswifi_disconnect(struct eswifi_dev *eswifi)
eswifi_lock(eswifi);
err = eswifi_request(eswifi, disconnect, strlen(disconnect),
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
err = eswifi_at_cmd(eswifi, disconnect);
if (err < 0) {
LOG_ERR("Unable to disconnect network");
eswifi_unlock(eswifi);
return -EIO;
err = -EIO;
}
eswifi_unlock(eswifi);
return 0;
return err;
}
static void eswifi_request_work(struct k_work *item)
@ -319,23 +348,18 @@ static void eswifi_request_work(struct k_work *item)
static int eswifi_get_mac_addr(struct eswifi_dev *eswifi, u8_t addr[6])
{
char cmd[] = "Z5\r";
int err, i, byte = 0;
int ret, i, byte = 0;
char *rsp;
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err) {
return err;
ret = eswifi_at_cmd_rsp(eswifi, cmd, &rsp);
if (ret < 0) {
return ret;
}
for (i = 0; i < sizeof(eswifi->buf) && byte < 6; i++) {
if (i < 2) {
continue;
}
if (eswifi->buf[i] == ':' ||
((byte == 5) && (eswifi->buf[i] == '\r'))) {
addr[byte++] = strtol(&eswifi->buf[i - 2], NULL, 16);
}
/* format is "ff:ff:ff:ff:ff:ff" */
for (i = 0; i < ret && byte < 6; i++) {
addr[byte++] = strtol(&rsp[i], NULL, 16);
i += 2;
}
if (byte != 6) {
@ -349,20 +373,17 @@ 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) {
if (eswifi_reset(eswifi) < 0) {
LOG_ERR("Unable to reset device");
return;
}
err = eswifi_get_mac_addr(eswifi, mac);
if (err) {
if (eswifi_get_mac_addr(eswifi, mac) < 0) {
LOG_ERR("Unable to read MAC address");
return;
}

View file

@ -20,62 +20,36 @@ LOG_MODULE_REGISTER(wifi_eswifi_offload);
#include "eswifi.h"
static int __select_socket(struct eswifi_dev *eswifi, u8_t idx)
static inline 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;
return eswifi_at_cmd(eswifi, eswifi->buf);
}
static int __read_data(struct eswifi_dev *eswifi, size_t len)
static int __read_data(struct eswifi_dev *eswifi, size_t len, char **data)
{
char cmd[] = "R0\r";
char size[] = "R1=9999\r";
char timeout[] = "R2=30000\r";
int err, i, read = 0;
int ret;
/* Set max read size */
snprintf(size, sizeof(size), "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)) {
ret = eswifi_at_cmd(eswifi, size);
if (ret < 0) {
LOG_ERR("Unable to set read size");
return -EIO;
}
/* Set timeout */
snprintf(timeout, sizeof(timeout), "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)) {
ret = eswifi_at_cmd(eswifi, timeout);
if (ret < 0) {
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;
return eswifi_at_cmd_rsp(eswifi, cmd, data);
}
static inline
@ -90,6 +64,7 @@ static void eswifi_off_read_work(struct k_work *work)
struct eswifi_dev *eswifi;
struct net_pkt *pkt;
int err, len;
char *data;
LOG_DBG("");
@ -104,12 +79,12 @@ static void eswifi_off_read_work(struct k_work *work)
__select_socket(eswifi, socket->index);
len = __read_data(eswifi, 1460); /* 1460 is max size */
len = __read_data(eswifi, 1460, &data); /* 1460 is max size */
if (len <= 0 || !socket->recv_cb) {
goto done;
}
LOG_DBG("payload sz = %d", len);
LOG_ERR("payload sz = %d", len);
pkt = net_pkt_get_reserve_rx(K_NO_WAIT);
if (!pkt) {
@ -117,8 +92,7 @@ static void eswifi_off_read_work(struct k_work *work)
goto done;
}
if (!net_pkt_append_all(pkt, len, eswifi->buf + AT_RSP_DELIMITER_LEN,
K_NO_WAIT)) {
if (!net_pkt_append_all(pkt, len, data, K_NO_WAIT)) {
LOG_WRN("Incomplete buffer copy");
}
@ -159,9 +133,8 @@ static int eswifi_off_bind(struct net_context *context,
/* 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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set local port");
eswifi_unlock(eswifi);
return -EIO;
@ -176,7 +149,7 @@ static int eswifi_off_listen(struct net_context *context, int backlog)
{
struct eswifi_off_socket *socket = context->offload_context;
struct eswifi_dev *eswifi = eswifi_by_iface_idx(context->iface);
char *cmd = "P5=1\r";
char cmd[] = "P5=1\r";
int err;
/* TODO */
@ -187,16 +160,14 @@ static int eswifi_off_listen(struct net_context *context, int backlog)
__select_socket(eswifi, socket->index);
/* Start TCP Server */
err = eswifi_request(eswifi, cmd, strlen(cmd), eswifi->buf,
sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
err = eswifi_at_cmd(eswifi, cmd);
if (err < 0) {
LOG_ERR("Unable to start TCP server");
eswifi_unlock(eswifi);
return -EIO;
}
eswifi_unlock(eswifi);
return -ENOTSUP;
return err;
}
static int __eswifi_off_connect(struct eswifi_dev *eswifi,
@ -215,9 +186,8 @@ static int __eswifi_off_connect(struct eswifi_dev *eswifi,
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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set remote ip");
return -EIO;
}
@ -225,18 +195,16 @@ static int __eswifi_off_connect(struct eswifi_dev *eswifi,
/* 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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set remote port");
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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to connect");
return -EIO;
}
@ -367,7 +335,7 @@ static int __eswifi_off_send_pkt(struct eswifi_dev *eswifi,
err = eswifi_request(eswifi, eswifi->buf, offset + 1,
eswifi->buf, sizeof(eswifi->buf));
if (err || !eswifi_is_buf_at_ok(eswifi->buf)) {
if (err < 0) {
LOG_ERR("Unable to send data");
return -EIO;
}
@ -523,11 +491,10 @@ static int eswifi_off_put(struct net_context *context)
/* 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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
err = -EIO;
LOG_ERR("Unable to connect");
LOG_ERR("Unable to disconnect");
}
eswifi_unlock(eswifi);
@ -582,7 +549,7 @@ static int eswifi_off_get(sa_family_t family,
k_sem_init(&socket->read_sem, 1, 1);
err = __select_socket(eswifi, socket->index);
if (err) {
if (err < 0) {
LOG_ERR("Unable to select socket %u", socket->index);
eswifi_unlock(eswifi);
return -EIO;
@ -591,9 +558,8 @@ static int eswifi_off_get(sa_family_t family,
/* 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)) {
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set transport protocol");
eswifi_unlock(eswifi);
return -EIO;
@ -628,12 +594,7 @@ static int eswifi_off_enable_dhcp(struct eswifi_dev *eswifi)
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;
}
err = eswifi_at_cmd(eswifi, cmd);
eswifi_unlock(eswifi);
@ -649,16 +610,11 @@ static int eswifi_off_disable_bypass(struct eswifi_dev *eswifi)
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;
}
err = eswifi_at_cmd(eswifi, cmd);
eswifi_unlock(eswifi);
return 0;
return err;
}
int eswifi_offload_init(struct eswifi_dev *eswifi)
@ -667,13 +623,13 @@ int eswifi_offload_init(struct eswifi_dev *eswifi)
int err;
err = eswifi_off_enable_dhcp(eswifi);
if (err) {
if (err < 0) {
LOG_ERR("Unable to configure dhcp");
return err;
}
err = eswifi_off_disable_bypass(eswifi);
if (err) {
if (err < 0) {
LOG_ERR("Unable to disable bypass mode");
return err;
}