2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* drivers/wireless/gs2200m.c
|
|
|
|
*
|
|
|
|
* Copyright 2019 Sony Home Entertainment & Sound Products Inc.
|
|
|
|
* Author: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
|
|
* used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-02-05 08:22:24 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* gs2200m driver.
|
|
|
|
*
|
|
|
|
* See "GS2200MS2W Adapter Command Reference Guide" for the explanation
|
|
|
|
* of AT commands. You can find the document at:
|
2020-04-13 10:08:03 +02:00
|
|
|
* https://telit.com/m2m-iot-products/wifi-bluetooth-modules/wi-fi-gs2200m/
|
2020-03-31 21:59:25 +02:00
|
|
|
*
|
2020-02-05 08:22:24 +01:00
|
|
|
****************************************************************************/
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <poll.h>
|
|
|
|
|
|
|
|
#include <nuttx/ascii.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
|
|
#include <nuttx/spi/spi.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include <nuttx/wqueue.h>
|
|
|
|
#include <nuttx/semaphore.h>
|
2019-11-30 00:37:39 +01:00
|
|
|
#include <nuttx/signal.h>
|
2020-11-02 08:49:14 +01:00
|
|
|
#include <nuttx/wireless/wireless.h>
|
2019-06-18 14:44:03 +02:00
|
|
|
#include <nuttx/wireless/gs2200m.h>
|
|
|
|
#include <nuttx/net/netdev.h>
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Pre-processor Definitions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#if !defined(CONFIG_SCHED_WORKQUEUE)
|
|
|
|
# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MIN
|
|
|
|
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define GS2200MWORK LPWORK
|
|
|
|
|
2019-07-04 13:30:54 +02:00
|
|
|
#define SPI_MAXFREQ CONFIG_WL_GS2200M_SPI_FREQUENCY
|
2020-05-14 01:10:04 +02:00
|
|
|
#define NRESPMSG (16 + 2)
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-05-14 14:34:28 +02:00
|
|
|
#define BULK_CMD_HDR_SIZE_WITH_GUARD 36
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
#define MAX_PKT_LEN 1500
|
2020-05-14 14:34:28 +02:00
|
|
|
#define MAX_PAYLOAD (MAX_PKT_LEN - BULK_CMD_HDR_SIZE_WITH_GUARD)
|
2019-06-18 14:44:03 +02:00
|
|
|
#define MAX_NOTIF_Q 16
|
|
|
|
|
|
|
|
#define WR_REQ 0x01
|
|
|
|
#define RD_REQ 0x02
|
|
|
|
#define DT_FROM_MCU 0x03
|
|
|
|
|
|
|
|
#define WR_RESP_OK 0x11
|
|
|
|
#define RD_RESP_OK 0x12
|
|
|
|
#define WR_RESP_NOK 0x13
|
|
|
|
#define RD_RESP_NOK 0x14
|
|
|
|
|
|
|
|
#define LED_GPIO 30
|
2020-04-30 07:03:42 +02:00
|
|
|
#define HAL_TIMEOUT 5000000 /* in us */
|
|
|
|
#define WR_MAX_RETRY 100
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-05-14 04:26:55 +02:00
|
|
|
#define PORT_START 50000
|
|
|
|
#define PORT_END 59999
|
|
|
|
|
2020-05-22 06:52:37 +02:00
|
|
|
#define SEC_MODE_WEP 2
|
|
|
|
#define SEC_MODE_WPA2PSK 8
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
#define BULK_THRESHOLD (1024 * 8)
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Private Data Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
2019-06-18 15:01:23 +02:00
|
|
|
enum pkt_state_e
|
|
|
|
{
|
2019-06-18 14:44:03 +02:00
|
|
|
PKT_START = 0,
|
|
|
|
PKT_EVENT,
|
|
|
|
PKT_ESC_START,
|
2019-07-25 07:40:06 +02:00
|
|
|
PKT_BULK_DATA_TCP,
|
|
|
|
PKT_BULK_DATA_UDP,
|
2019-06-18 14:44:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
enum spi_status_e
|
|
|
|
{
|
|
|
|
SPI_OK = 0,
|
|
|
|
SPI_ERROR,
|
|
|
|
SPI_TIMEOUT
|
|
|
|
};
|
|
|
|
|
|
|
|
enum pkt_type_e
|
|
|
|
{
|
|
|
|
TYPE_OK = 0,
|
|
|
|
TYPE_ERROR = 1,
|
|
|
|
TYPE_DISCONNECT = 2,
|
|
|
|
TYPE_CONNECT = 3,
|
|
|
|
TYPE_BOOT_MSG = 4,
|
2019-07-25 07:40:06 +02:00
|
|
|
TYPE_BULK_DATA_TCP = 5,
|
|
|
|
TYPE_BULK_DATA_UDP = 6,
|
|
|
|
TYPE_FAIL = 7,
|
|
|
|
TYPE_TIMEOUT = 8,
|
|
|
|
TYPE_SPI_ERROR = 9,
|
2020-10-30 07:19:50 +01:00
|
|
|
TYPE_DISASSOCIATE = 10,
|
|
|
|
TYPE_UNMATCH = 11,
|
2019-06-18 14:44:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct evt_code_s
|
|
|
|
{
|
|
|
|
FAR const char *str;
|
|
|
|
enum pkt_type_e code;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pkt_dat_s
|
|
|
|
{
|
2019-07-25 07:40:06 +02:00
|
|
|
struct dq_entry_s dq;
|
|
|
|
enum pkt_type_e type;
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
char cid;
|
|
|
|
uint8_t n;
|
|
|
|
FAR char *msg[NRESPMSG];
|
|
|
|
uint16_t remain; /* bulk data length to be read */
|
|
|
|
uint16_t len; /* bulk data length */
|
|
|
|
FAR uint8_t *data; /* bulk data */
|
2019-06-18 14:44:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct pkt_ctx_s
|
|
|
|
{
|
|
|
|
enum pkt_type_e type;
|
|
|
|
enum pkt_state_e state;
|
|
|
|
FAR uint8_t *ptr;
|
|
|
|
FAR uint8_t *head;
|
|
|
|
char cid;
|
|
|
|
uint16_t dlen;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct notif_q_s
|
|
|
|
{
|
|
|
|
uint8_t rpos;
|
|
|
|
uint8_t wpos;
|
|
|
|
uint8_t count;
|
|
|
|
uint16_t inuse;
|
|
|
|
char cids[MAX_NOTIF_Q];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct gs2200m_dev_s
|
|
|
|
{
|
|
|
|
FAR char *path;
|
|
|
|
FAR struct pollfd *pfd;
|
|
|
|
struct notif_q_s notif_q;
|
|
|
|
FAR struct spi_dev_s *spi;
|
|
|
|
struct work_s irq_work;
|
|
|
|
sem_t dev_sem;
|
2020-06-01 06:52:59 +02:00
|
|
|
bool int_enabled;
|
2019-06-18 14:44:03 +02:00
|
|
|
dq_queue_t pkt_q[16];
|
2020-05-20 11:44:51 +02:00
|
|
|
uint16_t pkt_q_cnt[16];
|
2019-06-18 14:44:03 +02:00
|
|
|
uint16_t valid_cid_bits;
|
|
|
|
uint16_t aip_cid_bits;
|
2020-06-01 06:52:59 +02:00
|
|
|
uint32_t total_bulk;
|
2019-06-18 14:44:03 +02:00
|
|
|
uint8_t tx_buff[MAX_PKT_LEN];
|
|
|
|
struct net_driver_s net_dev;
|
2019-07-10 13:26:39 +02:00
|
|
|
uint8_t op_mode;
|
2019-06-18 14:44:03 +02:00
|
|
|
FAR const struct gs2200m_lower_s *lower;
|
2020-10-30 07:19:50 +01:00
|
|
|
bool disassociate_flag;
|
|
|
|
struct gs2200m_assoc_msg reconnect_msg;
|
2019-06-18 14:44:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* Character driver methods */
|
|
|
|
|
|
|
|
static int gs2200m_open(FAR struct file *filep);
|
|
|
|
static int gs2200m_close(FAR struct file *filep);
|
|
|
|
static ssize_t gs2200m_read(FAR struct file *filep, FAR char *buff,
|
|
|
|
size_t len);
|
|
|
|
static ssize_t gs2200m_write(FAR struct file *filep, FAR const char *buff,
|
|
|
|
size_t len);
|
|
|
|
static int gs2200m_ioctl(FAR struct file *filep, int cmd,
|
|
|
|
unsigned long arg);
|
|
|
|
static int gs2200m_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|
|
|
bool setup);
|
|
|
|
|
|
|
|
/* Interrupt handler and work queue handler */
|
|
|
|
|
|
|
|
static int gs2200m_irq(int irq, FAR void *context, FAR void *arg);
|
|
|
|
static void gs2200m_irq_worker(FAR void *arg);
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* This the vtable that supports the character driver interface. */
|
|
|
|
|
|
|
|
static const struct file_operations g_gs2200m_fops =
|
|
|
|
{
|
|
|
|
gs2200m_open, /* open */
|
|
|
|
gs2200m_close, /* close */
|
|
|
|
gs2200m_read, /* read */
|
|
|
|
gs2200m_write, /* write */
|
|
|
|
NULL, /* seek */
|
|
|
|
gs2200m_ioctl, /* ioctl */
|
|
|
|
gs2200m_poll, /* poll */
|
|
|
|
NULL /* unlink */
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct evt_code_s _evt_table[] =
|
|
|
|
{
|
|
|
|
{"OK", TYPE_OK},
|
2020-10-30 07:19:50 +01:00
|
|
|
{"Disassociation Event", TYPE_DISASSOCIATE},
|
2019-06-18 14:44:03 +02:00
|
|
|
{"ERROR", TYPE_ERROR},
|
|
|
|
{"DISCONNECT", TYPE_DISCONNECT},
|
2020-11-02 08:49:14 +01:00
|
|
|
{"CONNECT ", TYPE_CONNECT},
|
2019-06-18 14:44:03 +02:00
|
|
|
{"Serial2WiFi APP", TYPE_BOOT_MSG}
|
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _spi_err_to_pkt_type
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e _spi_err_to_pkt_type(enum spi_status_e s)
|
|
|
|
{
|
|
|
|
enum pkt_type_e r;
|
|
|
|
|
|
|
|
switch (s)
|
|
|
|
{
|
|
|
|
case SPI_OK:
|
|
|
|
r = TYPE_OK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_ERROR:
|
|
|
|
r = TYPE_SPI_ERROR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_TIMEOUT:
|
|
|
|
r = TYPE_TIMEOUT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2020-09-11 06:55:27 +02:00
|
|
|
r = TYPE_UNMATCH;
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _cid_to_uint8
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static uint8_t _cid_to_uint8(char c)
|
|
|
|
{
|
|
|
|
uint8_t ret;
|
|
|
|
|
|
|
|
if ('0' <= c && c <= '9')
|
|
|
|
{
|
|
|
|
ret = c - '0';
|
|
|
|
}
|
|
|
|
else if ('a' <= c && c <= 'f')
|
|
|
|
{
|
|
|
|
ret = (c - 'a') + 10;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-11 06:55:27 +02:00
|
|
|
ret = 0xff;
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _to_ascii_char
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _to_ascii_char(uint16_t num, char *str)
|
|
|
|
{
|
|
|
|
DEBUGASSERT(num <= 2032); /* See Table 20 */
|
|
|
|
snprintf(str, 5, "%04d", num);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _to_uint16
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static uint16_t _to_uint16(char *str)
|
|
|
|
{
|
|
|
|
uint16_t ret = 0;
|
|
|
|
int n;
|
|
|
|
|
2020-05-26 08:11:52 +02:00
|
|
|
n = sscanf(str, "%04hu", &ret);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(1 == n);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _enable_cid
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static bool _enable_cid(uint16_t *cid_bits, char cid, bool on)
|
|
|
|
{
|
|
|
|
uint16_t mask = 1 << _cid_to_uint8(cid);
|
|
|
|
bool ret = true;
|
|
|
|
|
|
|
|
if (on)
|
|
|
|
{
|
|
|
|
if (*cid_bits & mask)
|
|
|
|
{
|
|
|
|
ret = false; /* already set */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*cid_bits |= mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (*cid_bits & mask)
|
|
|
|
{
|
|
|
|
*cid_bits &= ~mask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = false; /* not set yet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _cid_is_set
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static bool _cid_is_set(uint16_t *cid_bits, char cid)
|
|
|
|
{
|
|
|
|
uint16_t mask = 1 << _cid_to_uint8(cid);
|
|
|
|
|
|
|
|
if (*cid_bits & mask)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _notif_q_count()
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static uint8_t _notif_q_count(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
return dev->notif_q.count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _notif_q_push()
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _notif_q_push(FAR struct gs2200m_dev_s *dev, char cid)
|
|
|
|
{
|
|
|
|
ASSERT(MAX_NOTIF_Q > dev->notif_q.count);
|
|
|
|
|
|
|
|
/* Set cid in _notif_q.inuse */
|
|
|
|
|
|
|
|
bool ret = _enable_cid(&dev->notif_q.inuse, cid, true);
|
|
|
|
|
|
|
|
if (false == ret)
|
|
|
|
{
|
|
|
|
/* already registered */
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->notif_q.cids[dev->notif_q.wpos % MAX_NOTIF_Q] = cid;
|
|
|
|
dev->notif_q.wpos++;
|
|
|
|
dev->notif_q.count++;
|
|
|
|
|
2020-04-30 06:58:11 +02:00
|
|
|
if (dev->pfd)
|
|
|
|
{
|
|
|
|
/* If poll() waits and cid has been pushed to the queue, notify */
|
|
|
|
|
|
|
|
dev->pfd->revents |= POLLIN;
|
|
|
|
nxsem_post(dev->pfd->sem);
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
wlinfo("+++ pushed %c count=%d \n", cid, dev->notif_q.count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _notif_q_pop()
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static char _notif_q_pop(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
char cid;
|
|
|
|
|
|
|
|
ASSERT(0 < dev->notif_q.count);
|
|
|
|
|
|
|
|
cid = dev->notif_q.cids[dev->notif_q.rpos % MAX_NOTIF_Q];
|
|
|
|
dev->notif_q.rpos++;
|
|
|
|
dev->notif_q.count--;
|
|
|
|
|
|
|
|
/* Clear cid in _notif_q.inuse */
|
|
|
|
|
|
|
|
_enable_cid(&dev->notif_q.inuse, cid, false);
|
|
|
|
|
|
|
|
return cid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _push_data_to_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _push_data_to_pkt(struct pkt_dat_s *pkt, uint8_t data)
|
|
|
|
{
|
|
|
|
ASSERT(pkt->len < MAX_PKT_LEN);
|
|
|
|
|
|
|
|
pkt->data[pkt->len++] = data;
|
|
|
|
pkt->remain = pkt->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _release_pkt_dat
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
static void _release_pkt_dat(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pkt_dat->n; i++)
|
|
|
|
{
|
|
|
|
kmm_free(pkt_dat->msg[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt_dat->len)
|
|
|
|
{
|
|
|
|
kmm_free(pkt_dat->data);
|
2020-06-01 06:52:59 +02:00
|
|
|
|
|
|
|
if (pkt_dat->type == TYPE_BULK_DATA_TCP ||
|
|
|
|
pkt_dat->type == TYPE_BULK_DATA_UDP)
|
|
|
|
{
|
|
|
|
/* Update total bulk data size */
|
|
|
|
|
|
|
|
ASSERT(dev->total_bulk >= pkt_dat->len);
|
|
|
|
dev->total_bulk -= pkt_dat->len;
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pkt_dat->n = 0;
|
|
|
|
pkt_dat->len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _check_pkt_q_cnt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _check_pkt_q_cnt(FAR struct gs2200m_dev_s *dev, char cid)
|
|
|
|
{
|
|
|
|
uint8_t cnt;
|
|
|
|
|
|
|
|
cnt = dev->pkt_q_cnt[_cid_to_uint8(cid)];
|
|
|
|
|
|
|
|
if (0 != cnt)
|
|
|
|
{
|
|
|
|
wlinfo("--- _pkt_p_cnt[%c]=%d \n", cid, cnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _check_pkt_q_empty
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _check_pkt_q_empty(FAR struct gs2200m_dev_s *dev, char cid)
|
|
|
|
{
|
|
|
|
uint8_t c = _cid_to_uint8(cid);
|
|
|
|
FAR struct pkt_dat_s *pkt_dat;
|
|
|
|
|
|
|
|
if (0 != dev->pkt_q_cnt[c])
|
|
|
|
{
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_peek(&dev->pkt_q[c]);
|
|
|
|
|
|
|
|
while (pkt_dat)
|
|
|
|
{
|
|
|
|
wlerr("=== error: found (type=%d msg[0]=%s|) \n",
|
|
|
|
pkt_dat->type, pkt_dat->msg[0]);
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)pkt_dat->dq.flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _control_pkt_q
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
static bool _control_pkt_q(FAR struct gs2200m_dev_s *dev)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
2020-06-01 06:52:59 +02:00
|
|
|
bool over = BULK_THRESHOLD < dev->total_bulk ? true : false;
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-07-17 02:04:15 +02:00
|
|
|
/* TODO: should enable again if disabled for long time */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
if (dev->int_enabled && over)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
2020-07-17 02:04:15 +02:00
|
|
|
wlinfo("--- disable irq \n");
|
2020-06-01 06:52:59 +02:00
|
|
|
dev->int_enabled = false;
|
2019-06-18 14:44:03 +02:00
|
|
|
dev->lower->disable();
|
|
|
|
}
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
if (!dev->int_enabled && !over)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
wlinfo("--- enable irq again \n");
|
|
|
|
dev->lower->enable();
|
2020-06-01 06:52:59 +02:00
|
|
|
dev->int_enabled = true;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
2020-06-01 06:52:59 +02:00
|
|
|
|
|
|
|
return over;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _remove_and_free_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _remove_and_free_pkt(FAR struct gs2200m_dev_s *dev, uint8_t c)
|
|
|
|
{
|
|
|
|
FAR struct pkt_dat_s *pkt_dat;
|
|
|
|
|
|
|
|
/* Decrement _pkt_q_cnt before remove */
|
|
|
|
|
|
|
|
ASSERT(0 < dev->pkt_q_cnt[c]);
|
|
|
|
dev->pkt_q_cnt[c]--;
|
|
|
|
|
|
|
|
/* Remove a packet from the queue */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_remfirst(&dev->pkt_q[c]);
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
/* Release the packet */
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
kmm_free(pkt_dat);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _remove_all_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _remove_all_pkt(FAR struct gs2200m_dev_s *dev, uint8_t c)
|
|
|
|
{
|
|
|
|
FAR struct pkt_dat_s *pkt_dat;
|
|
|
|
uint16_t mask;
|
|
|
|
|
|
|
|
mask = 1 << c;
|
|
|
|
ASSERT(0 == (dev->valid_cid_bits & mask));
|
|
|
|
|
|
|
|
ASSERT(dev->pkt_q_cnt[c] == dq_count(&dev->pkt_q[c]));
|
|
|
|
|
|
|
|
/* Remove all packets for this cid */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_peek(&dev->pkt_q[c]);
|
|
|
|
|
|
|
|
while (pkt_dat)
|
|
|
|
{
|
|
|
|
_remove_and_free_pkt(dev, c);
|
|
|
|
|
|
|
|
/* Check the next */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_peek(&dev->pkt_q[c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _copy_data_from_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static bool _copy_data_from_pkt(FAR struct gs2200m_dev_s *dev,
|
|
|
|
struct gs2200m_recv_msg *msg)
|
|
|
|
{
|
|
|
|
FAR struct pkt_dat_s *pkt_dat;
|
|
|
|
uint8_t c = _cid_to_uint8(msg->cid);
|
|
|
|
uint16_t len;
|
|
|
|
uint16_t off;
|
|
|
|
bool ret = true;
|
|
|
|
|
|
|
|
/* Peek a packet from the queue and check the remaining size */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_peek(&dev->pkt_q[c]);
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
wlinfo("+++ msg(req=%d:len=%d) pkt_data(t=%d:remain=%d) \n",
|
|
|
|
msg->reqlen, msg->len, pkt_dat->type, pkt_dat->remain);
|
|
|
|
|
|
|
|
if (msg->len && TYPE_DISCONNECT == pkt_dat->type)
|
|
|
|
{
|
|
|
|
/* Treat the packet separately */
|
|
|
|
|
|
|
|
ret = false;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-02-22 19:31:14 +01:00
|
|
|
/* Copy the pkt data to msg buffer up to MIN(request - len, remain) */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
len = MIN(msg->reqlen - msg->len, pkt_dat->remain);
|
|
|
|
off = pkt_dat->len - pkt_dat->remain;
|
|
|
|
memcpy(msg->buf + msg->len, pkt_dat->data + off, len);
|
|
|
|
msg->len += len;
|
|
|
|
msg->type = pkt_dat->type;
|
|
|
|
|
|
|
|
/* Update the remaining size. If the remaining size is 0.
|
|
|
|
* Remove the packet from the queue and free it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
pkt_dat->remain -= len;
|
|
|
|
|
|
|
|
if (0 == pkt_dat->remain)
|
|
|
|
{
|
|
|
|
_remove_and_free_pkt(dev, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
2019-07-25 07:40:06 +02:00
|
|
|
|
|
|
|
if (!msg->is_tcp)
|
|
|
|
{
|
|
|
|
/* Copy the source address and port */
|
|
|
|
|
|
|
|
memcpy(&msg->addr, &pkt_dat->addr, sizeof(pkt_dat->addr));
|
|
|
|
|
|
|
|
/* In udp case, treat the packet separately */
|
|
|
|
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_lock
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-03-31 21:59:25 +02:00
|
|
|
static int gs2200m_lock(FAR struct gs2200m_dev_s *dev)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
2020-03-31 21:59:25 +02:00
|
|
|
return nxsem_wait_uninterruptible(&dev->dev_sem);
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_unlock
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void gs2200m_unlock(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
nxsem_post(&dev->dev_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_open
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_open(FAR struct file *filep)
|
|
|
|
{
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_close
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_close(FAR struct file *filep)
|
|
|
|
{
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_read
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static ssize_t gs2200m_read(FAR struct file *filep, FAR char *buffer,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
FAR struct inode *inode;
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
2020-03-31 21:59:25 +02:00
|
|
|
int ret;
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
DEBUGASSERT(filep);
|
|
|
|
inode = filep->f_inode;
|
|
|
|
|
|
|
|
DEBUGASSERT(inode && inode->i_private);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)inode->i_private;
|
|
|
|
|
|
|
|
ASSERT(1 == len);
|
|
|
|
|
nuttx: Fix the nightly build warning
lpc2148_spi1.c:142:24: warning: initialization of 'uint32_t (*)(struct spi_dev_s *, uint32_t)' {aka 'unsigned int (*)(struct spi_dev_s *, unsigned int)'} from incompatible pointer type 'uint16_t (*)(struct spi_dev_s *, uint16_t)' {aka 'short unsigned int (*)(struct spi_dev_s *, short unsigned int)'} [-Wincompatible-pointer-types]
142 | .send = spi_send,
| ^~~~~~~~
lpc2148_spi1.c:142:24: note: (near initialization for 'g_spiops.send')
In file included from ieee802154/mac802154_bind.c:49:
ieee802154/mac802154_internal.h: In function 'mac802154_setdevmode':
ieee802154/mac802154_internal.h:788:42: warning: converting a packed 'enum ieee802154_devmode_e' pointer (alignment 1) to a 'const union ieee802154_attr_u' pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
788 | (FAR const union ieee802154_attr_u *)&mode);
| ^~~~~~~~~~~~~~~~~
chip/stm32_hciuart.c: In function 'hciuart_read':
chip/stm32_hciuart.c:2104:30: warning: statement with no effect [-Wunused-value]
2104 | ntotal == (ssize_t)ret;
| ~~~~~~~^~~~~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/bcmf_driver.c: In function 'bcmf_wl_auth_event_handler':
wireless/ieee80211/bcm43xxx/bcmf_driver.c:579:23: warning: taking address of packed member of 'struct bcmf_event_s' may result in an unaligned pointer value [-Waddress-of-packed-member]
579 | type = bcmf_getle32(&event->type);
| ^~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/bcmf_driver.c:580:25: warning: taking address of packed member of 'struct bcmf_event_s' may result in an unaligned pointer value [-Waddress-of-packed-member]
580 | status = bcmf_getle32(&event->status);
| ^~~~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/bcmf_driver.c: In function 'bcmf_wl_scan_event_handler':
wireless/ieee80211/bcm43xxx/bcmf_driver.c:619:25: warning: taking address of packed member of 'struct bcmf_event_s' may result in an unaligned pointer value [-Waddress-of-packed-member]
619 | status = bcmf_getle32(&event->status);
| ^~~~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/bcmf_driver.c:620:35: warning: taking address of packed member of 'struct bcmf_event_s' may result in an unaligned pointer value [-Waddress-of-packed-member]
620 | escan_result_len = bcmf_getle32(&event->len);
| ^~~~~~~~~~~
wireless/ieee80211/bcm43xxx/bcmf_bdc.c: In function 'bcmf_bdc_process_event_frame':
wireless/ieee80211/bcm43xxx/bcmf_bdc.c:166:27: warning: taking address of packed member of 'struct bcmf_event_s' may result in an unaligned pointer value [-Waddress-of-packed-member]
166 | event_id = bcmf_getle32(&event_msg->event.type);
| ^~~~~~~~~~~~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c: In function 'sdio_io_rw_direct':
wireless/ieee80211/bcm43xxx/mmc_sdio.c:157:3: warning: converting a packed 'struct sdio_resp_R5' pointer (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
157 | ret = SDIO_RECVR5(dev, SD_ACMD52, (uint32_t *)&resp);
| ^~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:79:28: note: defined here
79 | begin_packed_struct struct sdio_resp_R5
| ^~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c: In function 'sdio_io_rw_extended':
wireless/ieee80211/bcm43xxx/mmc_sdio.c:239:11: warning: converting a packed 'struct sdio_resp_R5' pointer (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
239 | ret = SDIO_RECVR5(dev, SD_ACMD53, (uint32_t *)&resp);
| ^~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:79:28: note: defined here
79 | begin_packed_struct struct sdio_resp_R5
| ^~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:244:11: warning: converting a packed 'struct sdio_resp_R5' pointer (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
244 | ret = SDIO_RECVR5(dev, SD_ACMD53, (uint32_t *)&resp);
| ^~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:79:28: note: defined here
79 | begin_packed_struct struct sdio_resp_R5
| ^~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:257:7: warning: converting a packed 'struct sdio_resp_R5' pointer (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
257 | ret = SDIO_RECVR5(dev, SD_ACMD53, (uint32_t *)&resp);
| ^~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:79:28: note: defined here
79 | begin_packed_struct struct sdio_resp_R5
| ^~~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:265:3: warning: converting a packed 'struct sdio_resp_R5' pointer (alignment 1) to a 'uint32_t' {aka 'unsigned int'} pointer (alignment 4) may result in an unaligned pointer value [-Waddress-of-packed-member]
265 | SDIO_RECVR1(dev, SD_ACMD52ABRT, (uint32_t *)&resp);
| ^~~~~~~~~~~
wireless/ieee80211/bcm43xxx/mmc_sdio.c:79:28: note: defined here
79 | begin_packed_struct struct sdio_resp_R5
| ^~~~~~~~~~~~
chip/stm32_adc.c: In function 'adc_reset':
chip/stm32_adc.c:2860:7: warning: unused variable 'ret' [-Wunused-variable]
2860 | int ret;
| ^~~
chip/stm32_adc.c: In function 'adc_shutdown':
chip/stm32_adc.c:3044:7: warning: unused variable 'ret' [-Wunused-variable]
3044 | int ret;
| ^~~
chip/stm32_i2c.c:722:12: warning: 'stm32_i2c_sem_wait_noncancelable' defined but not used [-Wunused-function]
722 | static int stm32_i2c_sem_wait_noncancelable(FAR struct i2c_master_s *dev)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wireless/gs2200m.c: In function 'gs2200m_read':
wireless/gs2200m.c:727:20: warning: passing argument 1 of 'nxsem_wait' from incompatible pointer type [-Wincompatible-pointer-types]
727 | ret = nxsem_wait(dev);
| ^~~
| |
| struct gs2200m_dev_s *
.config:1207:warning: symbol value '' invalid for TESTING_OSTEST_FPUSIZE
platform/audio/cxd56_audio_analog.c:69:13: warning: inline function 'cxd56_audio_clock_is_enabled' declared but never defined
69 | inline bool cxd56_audio_clock_is_enabled(void);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
platform/audio/cxd56_audio_analog.c:68:13: warning: inline function 'cxd56_audio_clock_disable' declared but never defined
68 | inline void cxd56_audio_clock_disable(void);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
platform/audio/cxd56_audio_analog.c:67:13: warning: inline function 'cxd56_audio_clock_enable' declared but never defined
67 | inline void cxd56_audio_clock_enable(uint32_t clk, uint32_t div);
| ^~~~~~~~~~~~~~~~~~~~~~~~
chip/stm32_adc.c: In function 'adc_reset':
chip/stm32_adc.c:1348:7: warning: unused variable 'ret' [-Wunused-variable]
1348 | int ret;
| ^~~
chip/stm32_adc.c: In function 'adc_shutdown':
chip/stm32_adc.c:1496:7: warning: unused variable 'ret' [-Wunused-variable]
1496 | int ret;
| ^~~
chip/stm32_i2c.c:729:12: warning: 'stm32_i2c_sem_wait_uninterruptble' defined but not used [-Wunused-function]
729 | static int stm32_i2c_sem_wait_uninterruptble(FAR struct i2c_master_s *dev)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wireless/lpwan/sx127x/sx127x.c:147:52: warning: missing terminating ' character
147 | # warning OOK support is not complete, RX+TX doesn't work yet!
| ^
str71_spi.c:435:24: warning: initialization of 'uint32_t (*)(struct spi_dev_s *, uint32_t)' {aka 'unsigned int (*)(struct spi_dev_s *, unsigned int)'} from incompatible pointer type
'uint16_t (*)(struct spi_dev_s *, uint16_t)' {aka 'short unsigned int (*)(struct spi_dev_s *, short unsigned int)'} [-Wincompatible-pointer-types]
435 | .send = spi_send,
| ^~~~~~~~
str71_spi.c:435:24: note: (near initialization for 'g_spiops.send')
chip/pic32mx-lowconsole.c:147:24: warning: 'pic32mx_getreg' defined but not used [-Wunused-function]
static inline uint32_t pic32mx_getreg(uintptr_t uart_base,
^
chip/pic32mx-gpio.c:113:20: warning: 'pic32mx_value' defined but not used [-Wunused-function]
static inline bool pic32mx_value(uint16_t pinset)
^
chip/pic32mz-gpio.c:124:20: warning: 'pic32mz_value' defined but not used [-Wunused-function]
static inline bool pic32mz_value(pinset_t pinset)
^
chip/pic32mx-usbdev.c:3065:1: warning: 'pic32mx_epreserved' defined but not used [-Wunused-function]
pic32mx_epreserved(struct pic32mx_usbdev_s *priv, int epno)
^
mmcsd/mmcsd_spi.c: In function 'mmcsd_mediachanged':
mmcsd/mmcsd_spi.c:1938:7: warning: 'return' with a value, in function returning void
return ret;
^
In file included from partition/fs_partition.c:42:0:
partition/partition.h:66:19: warning: 'read_partition_block' defined but not used [-Wunused-function]
static inline int read_partition_block(FAR struct partition_state_s *state,
^
local/local_netpoll.c: In function 'local_pollsetup':
local/local_netpoll.c:305:1: warning: label 'pollerr' defined but not used [-Wunused-label]
pollerr:
^~~~~~~
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Change-Id: If3ea8f32b878aa218072130f7c3018f0d3c1aca5
2020-04-12 15:52:28 +02:00
|
|
|
ret = nxsem_wait(&dev->dev_sem);
|
2020-03-31 21:59:25 +02:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* Return if a signal is received or if the the task was canceled
|
|
|
|
* while we were waiting.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
ASSERT(0 < _notif_q_count(dev));
|
|
|
|
char cid = _notif_q_pop(dev);
|
|
|
|
|
|
|
|
wlinfo("---- cid=%c (notif_q_cnt=%d) \n", cid, _notif_q_count(dev));
|
|
|
|
|
|
|
|
/* Copy the cid to the buffer */
|
|
|
|
|
|
|
|
memcpy(buffer, &cid, sizeof(cid));
|
|
|
|
|
|
|
|
gs2200m_unlock(dev);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_write
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static ssize_t gs2200m_write(FAR struct file *filep, FAR const char *buffer,
|
|
|
|
size_t len)
|
|
|
|
{
|
2020-03-31 21:59:25 +02:00
|
|
|
return 0; /* REVISIT: Zero is not a legal return value from write() */
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_spi_init
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_spi_init(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
SPI_LOCK(dev->spi, true);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* SPI settings (mode1/8bits/max freq) */
|
|
|
|
|
|
|
|
SPI_SETMODE(dev->spi, SPIDEV_MODE1);
|
|
|
|
SPI_SETBITS(dev->spi, 8);
|
|
|
|
SPI_SETFREQUENCY(dev->spi, SPI_MAXFREQ);
|
|
|
|
|
2020-01-02 17:49:34 +01:00
|
|
|
SPI_LOCK(dev->spi, false);
|
2019-06-18 14:44:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _checksum
|
|
|
|
* NOTE: See 3.2.2.3 Annexure - HI Frame Format (From Host)
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static uint8_t _checksum(uint8_t *p, uint8_t len)
|
|
|
|
{
|
|
|
|
uint8_t i;
|
|
|
|
uint32_t chksum = 0x0;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++, p++)
|
|
|
|
{
|
|
|
|
chksum += *p;
|
|
|
|
}
|
|
|
|
|
|
|
|
chksum ^= ~0x0;
|
|
|
|
return chksum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _prepare_header
|
|
|
|
* NOTE: See 3.2.2.3 Annexure - HI Frame Format (From Host)
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _prepare_header(uint8_t *p, uint16_t len, uint8_t class)
|
|
|
|
{
|
|
|
|
*(p + 0) = 0xa5; /* SOF: start of frame */
|
|
|
|
*(p + 1) = class;
|
|
|
|
*(p + 2) = 0x0; /* reserved */
|
|
|
|
*(p + 3) = 0x0; /* additional info */
|
|
|
|
*(p + 4) = 0x0; /* additional info */
|
|
|
|
*(p + 5) = (uint8_t)len;
|
|
|
|
*(p + 6) = (uint8_t)(len >> 8);
|
|
|
|
*(p + 7) = _checksum(p + 1, 6); /* exclude SOF */
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _write_data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _write_data(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR uint8_t *buf,
|
|
|
|
FAR uint16_t len)
|
|
|
|
{
|
2019-10-22 15:38:41 +02:00
|
|
|
SPI_SELECT(dev->spi, SPIDEV_WIRELESS(0), true);
|
2020-04-30 07:03:42 +02:00
|
|
|
SPI_SNDBLOCK(dev->spi, buf, len);
|
2019-10-22 15:38:41 +02:00
|
|
|
SPI_SELECT(dev->spi, SPIDEV_WIRELESS(0), false);
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _read_data
|
|
|
|
* NOTE: See 3.2.2.1 SPI Byte Stuffing for the idle character
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _read_data(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR uint8_t *buff,
|
|
|
|
FAR uint16_t len)
|
|
|
|
{
|
|
|
|
uint8_t req = 0xf5; /* idle character */
|
|
|
|
|
|
|
|
memset(buff, 0, len);
|
|
|
|
|
2019-10-22 15:38:41 +02:00
|
|
|
SPI_SELECT(dev->spi, SPIDEV_WIRELESS(0), true);
|
2020-04-30 07:03:42 +02:00
|
|
|
SPI_EXCHANGE(dev->spi, &req, buff, len);
|
2019-10-22 15:38:41 +02:00
|
|
|
SPI_SELECT(dev->spi, SPIDEV_WIRELESS(0), false);
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _read_data_len
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static uint16_t _read_data_len(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
uint8_t hdr[8];
|
|
|
|
uint8_t res[8];
|
|
|
|
uint16_t len = 0;
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
/* Prepare header */
|
|
|
|
|
|
|
|
_prepare_header(hdr, MAX_PKT_LEN, RD_REQ);
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
/* Send the header read request */
|
|
|
|
|
|
|
|
_write_data(dev, hdr, sizeof(hdr));
|
|
|
|
|
|
|
|
/* Wait for data ready */
|
|
|
|
|
|
|
|
while (!dev->lower->dready(NULL))
|
|
|
|
{
|
|
|
|
/* TODO: timeout */
|
|
|
|
}
|
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
/* NOTE: busy wait 50us
|
|
|
|
* workaround to avoid an invalid frame response
|
2019-06-18 14:44:03 +02:00
|
|
|
*/
|
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
up_udelay(50);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Read frame response */
|
|
|
|
|
|
|
|
_read_data(dev, res, sizeof(res));
|
|
|
|
|
|
|
|
/* In case of NOK, retry */
|
|
|
|
|
|
|
|
if (RD_RESP_NOK == res[1])
|
|
|
|
{
|
|
|
|
wlwarn("*** warning: RD_RESP_NOK received.. retrying. (n=%d) \n", n);
|
|
|
|
nxsig_usleep(100 * 1000);
|
|
|
|
n++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(RD_RESP_OK == res[1]);
|
|
|
|
|
|
|
|
/* Retrieve the length */
|
|
|
|
|
|
|
|
len = ((uint16_t)res[6] << 8) + (uint16_t)res[5];
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_hal_write
|
|
|
|
* NOTE: See Figure 13,14 Transferring data from MCU to GS node
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
enum spi_status_e gs2200m_hal_write(FAR struct gs2200m_dev_s *dev,
|
|
|
|
const void *data,
|
|
|
|
uint16_t txlen)
|
|
|
|
{
|
|
|
|
uint8_t *tx = (uint8_t *)data;
|
|
|
|
uint8_t hdr[8];
|
|
|
|
uint8_t res[8];
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
/* Prepare header */
|
|
|
|
|
|
|
|
_prepare_header(hdr, txlen, WR_REQ);
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
/* 1. Send the first 4bytes of WRITE_REQUEST */
|
|
|
|
|
|
|
|
_write_data(dev, hdr, sizeof(hdr) / 2);
|
|
|
|
|
|
|
|
/* 2. Delay 3.2usec (NOTE: here we specify 4us) */
|
|
|
|
|
|
|
|
up_udelay(4);
|
|
|
|
|
|
|
|
/* Check if a pending interrupt exists */
|
|
|
|
|
|
|
|
if (dev->lower->dready(NULL))
|
|
|
|
{
|
|
|
|
wlwarn("*** warning: gs2200m is busy.. retrying. (n=%d) \n", n);
|
|
|
|
|
|
|
|
if (!work_available(&dev->irq_work))
|
|
|
|
{
|
|
|
|
wlwarn("*** warning: there is still pending work **** \n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* NOTE: Disable gs2200m irq before calling work_queue()
|
|
|
|
* This is the same sequence in the irq handler
|
|
|
|
*/
|
|
|
|
|
|
|
|
dev->lower->disable();
|
|
|
|
|
|
|
|
work_queue(GS2200MWORK, &dev->irq_work, gs2200m_irq_worker,
|
|
|
|
(FAR void *)dev, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
nxsig_usleep(100 * 1000);
|
|
|
|
n++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 3. Send remaining 4bytes of the WRITE_REQUEST */
|
|
|
|
|
|
|
|
_write_data(dev, hdr + (sizeof(hdr) / 2), sizeof(hdr) / 2);
|
|
|
|
|
|
|
|
/* 4. Wait for dready status (GPIO37 goes high) */
|
|
|
|
|
|
|
|
while (!dev->lower->dready(NULL))
|
|
|
|
{
|
|
|
|
/* TODO: timeout */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 5 Read 8bytes of WRITE_RESPONSE */
|
|
|
|
|
|
|
|
_read_data(dev, res, sizeof(res));
|
|
|
|
|
|
|
|
/* In case of NOK, retry */
|
|
|
|
|
|
|
|
if (WR_RESP_NOK == res[1])
|
|
|
|
{
|
|
|
|
wlwarn("*** warning: WR_RESP_NOK received.. retrying. (n=%d) \n", n);
|
2020-01-28 08:45:11 +01:00
|
|
|
nxsig_usleep(10 * 1000);
|
2019-07-03 02:11:24 +02:00
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
if (WR_MAX_RETRY < n)
|
2019-07-03 02:11:24 +02:00
|
|
|
{
|
|
|
|
return SPI_TIMEOUT;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
n++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(WR_RESP_OK == res[1]);
|
|
|
|
|
|
|
|
/* Prepare header */
|
|
|
|
|
|
|
|
_prepare_header(hdr, txlen, DT_FROM_MCU);
|
|
|
|
|
|
|
|
/* 6. Send 8bytes of data header */
|
|
|
|
|
|
|
|
_write_data(dev, hdr, sizeof(hdr));
|
|
|
|
|
|
|
|
/* 7. Send actual data */
|
|
|
|
|
|
|
|
_write_data(dev, tx, txlen);
|
|
|
|
|
|
|
|
return SPI_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_hal_read
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
enum spi_status_e gs2200m_hal_read(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR uint8_t *data,
|
|
|
|
FAR uint16_t *len)
|
|
|
|
{
|
|
|
|
enum spi_status_e r = SPI_OK;
|
|
|
|
uint8_t hdr[8];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* NOTE: need to wait for data ready even if we use irq */
|
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
for (i = 0; i < HAL_TIMEOUT; i++)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
if (dev->lower->dready(NULL))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
/* Busy wait 1us */
|
|
|
|
|
|
|
|
up_udelay(1);
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
2020-04-30 07:03:42 +02:00
|
|
|
if (HAL_TIMEOUT == i)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
wlerr("***** error: timeout! \n");
|
|
|
|
r = SPI_TIMEOUT;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2019-09-18 13:34:00 +02:00
|
|
|
/* Send READ_REQUEST then receive READ_RESPONSE
|
|
|
|
* to get how many bytes we should read
|
|
|
|
*/
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
*len = _read_data_len(dev);
|
|
|
|
|
|
|
|
wlinfo("+++++ (len=%d) \n", *len);
|
|
|
|
|
|
|
|
/* Check the length */
|
|
|
|
|
|
|
|
ASSERT(0 < *len);
|
|
|
|
|
2019-09-18 13:34:00 +02:00
|
|
|
/* Read data header */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
_read_data(dev, hdr, sizeof(hdr));
|
|
|
|
|
|
|
|
/* Read the actual data */
|
|
|
|
|
|
|
|
_read_data(dev, data, *len);
|
|
|
|
|
|
|
|
errout:
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _check_evt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
enum pkt_type_e _check_evt(FAR const char *buff)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(_evt_table) / sizeof(struct evt_code_s); i++)
|
|
|
|
{
|
|
|
|
if (strstr(buff, _evt_table[i].str))
|
|
|
|
{
|
|
|
|
return _evt_table[i].code;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wlinfo("+++++ %s +++++ \n", buff);
|
|
|
|
return TYPE_UNMATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _parse_pkt_in_s0
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _parse_pkt_in_s0(FAR struct pkt_ctx_s *pkt_ctx,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
switch (*(pkt_ctx->ptr))
|
|
|
|
{
|
|
|
|
case ASCII_CR:
|
|
|
|
case ASCII_LF:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ASCII_ESC:
|
|
|
|
pkt_ctx->state = PKT_ESC_START;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
pkt_ctx->head = pkt_ctx->ptr;
|
|
|
|
pkt_ctx->state = PKT_EVENT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _parse_pkt_in_s1
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _parse_pkt_in_s1(FAR struct pkt_ctx_s *pkt_ctx,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
int msize;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (ASCII_LF != *(pkt_ctx->ptr))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(pkt_ctx->ptr > pkt_ctx->head);
|
|
|
|
msize = pkt_ctx->ptr - pkt_ctx->head;
|
|
|
|
|
|
|
|
char *msg = (char *)kmm_calloc(msize + 1, 1);
|
|
|
|
ASSERT(msg);
|
|
|
|
|
|
|
|
memcpy(msg, pkt_ctx->head, msize);
|
|
|
|
|
|
|
|
pkt_ctx->type = _check_evt(msg);
|
|
|
|
|
|
|
|
if (pkt_ctx->type == TYPE_DISCONNECT)
|
|
|
|
{
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
n = sscanf(msg, "DISCONNECT %c", &(pkt_dat->cid));
|
|
|
|
ASSERT(1 == n);
|
|
|
|
|
|
|
|
wlinfo("+++++ msg=%s| cid=%c \n", msg, pkt_dat->cid);
|
|
|
|
}
|
|
|
|
else if (pkt_ctx->type == TYPE_CONNECT)
|
|
|
|
{
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
/* NOTE: CONNECT <server cid> <new cid> <ip> <address> */
|
|
|
|
|
|
|
|
n = sscanf(msg, "CONNECT %c", &(pkt_dat->cid));
|
|
|
|
DEBUGASSERT(1 == n);
|
|
|
|
|
|
|
|
wlinfo("+++++ msg=%s| \n", msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pkt_dat)
|
|
|
|
{
|
|
|
|
/* If specified, store the msg pointer to pkt_dat */
|
|
|
|
|
|
|
|
wlinfo("+++++ %d:(msize=%d, msg=%s|) \n", pkt_dat->n, msize, msg);
|
|
|
|
ASSERT(pkt_dat->n < NRESPMSG);
|
|
|
|
pkt_dat->msg[pkt_dat->n++] = msg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wlinfo("+++++ (msize=%d, msg=%s|) \n", msize, msg);
|
|
|
|
kmm_free(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt_ctx->head = pkt_ctx->ptr + 1;
|
|
|
|
|
|
|
|
if (TYPE_UNMATCH != pkt_ctx->type)
|
|
|
|
{
|
|
|
|
pkt_ctx->state = PKT_START;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _parse_pkt_in_s2 (ESC detected)
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _parse_pkt_in_s2(FAR struct pkt_ctx_s *pkt_ctx,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
ASSERT(pkt_ctx && pkt_ctx->ptr);
|
|
|
|
|
|
|
|
char c = (char)*(pkt_ctx->ptr);
|
|
|
|
|
|
|
|
if ('Z' == c)
|
|
|
|
{
|
|
|
|
wlinfo("** <ESC>Z \n");
|
|
|
|
|
|
|
|
/* NOTE: See 7.5.3.2 Bulk Data Handling */
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
pkt_ctx->state = PKT_BULK_DATA_TCP;
|
|
|
|
}
|
|
|
|
else if ('y' == c)
|
|
|
|
{
|
|
|
|
wlinfo("** <ESC>y \n");
|
|
|
|
|
|
|
|
/* NOTE: See 7.5.3.2 Bulk Data Handling */
|
|
|
|
|
|
|
|
pkt_ctx->state = PKT_BULK_DATA_UDP;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
else if ('F' == c)
|
|
|
|
{
|
|
|
|
wlwarn("** <ESC>F \n");
|
|
|
|
|
|
|
|
/* NOTE: See Table 6 Data Handling Responses at Completion */
|
|
|
|
|
|
|
|
pkt_ctx->state = PKT_START;
|
|
|
|
pkt_ctx->type = TYPE_FAIL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wlerr("** <ESC>%c not supported \n", c);
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2019-07-25 07:40:06 +02:00
|
|
|
* Name: _parse_pkt_in_s3 (BULK data for TCP)
|
2019-06-18 14:44:03 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _parse_pkt_in_s3(FAR struct pkt_ctx_s *pkt_ctx,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
if ('z' == pkt_ctx->cid)
|
|
|
|
{
|
|
|
|
/* Proceed ptr to obtain data length
|
|
|
|
* NOTE: <CID><Data Length xxxx 4 ascii char>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Read CID */
|
|
|
|
|
|
|
|
pkt_ctx->cid = (char)*(pkt_ctx->ptr);
|
|
|
|
pkt_ctx->ptr++;
|
|
|
|
|
|
|
|
pkt_dat->cid = pkt_ctx->cid;
|
|
|
|
|
|
|
|
/* Read data length */
|
|
|
|
|
|
|
|
pkt_ctx->dlen = _to_uint16((char *)pkt_ctx->ptr);
|
|
|
|
pkt_ctx->ptr += 3;
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
wlinfo("dlen=%d \n", pkt_ctx->dlen);
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/* Allocate memory for the packet */
|
|
|
|
|
|
|
|
pkt_dat->data = kmm_calloc(pkt_ctx->dlen, 1);
|
|
|
|
ASSERT(pkt_dat->data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_push_data_to_pkt(pkt_dat, *(pkt_ctx->ptr));
|
|
|
|
|
|
|
|
pkt_ctx->dlen--;
|
|
|
|
|
|
|
|
if (0 == pkt_ctx->dlen)
|
|
|
|
{
|
|
|
|
pkt_ctx->state = PKT_START;
|
2019-07-25 07:40:06 +02:00
|
|
|
pkt_ctx->type = TYPE_BULK_DATA_TCP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _parse_pkt_in_s4 (BULK data for UDP: see Table 217)
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _parse_pkt_in_s4(FAR struct pkt_ctx_s *pkt_ctx,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
char addr[17];
|
|
|
|
char port[6];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
if ('z' == pkt_ctx->cid)
|
|
|
|
{
|
|
|
|
/* <CID><address><sp><port><tab><Data Length xxxx 4 ascii char> */
|
|
|
|
|
|
|
|
/* Read CID */
|
|
|
|
|
|
|
|
pkt_ctx->cid = (char)*(pkt_ctx->ptr);
|
|
|
|
pkt_ctx->ptr++;
|
|
|
|
|
|
|
|
pkt_dat->cid = pkt_ctx->cid;
|
|
|
|
|
|
|
|
/* Read address and port */
|
|
|
|
|
|
|
|
memset(addr, 0, sizeof(addr));
|
|
|
|
memset(port, 0, sizeof(port));
|
|
|
|
n = sscanf((char *)pkt_ctx->ptr, "%s %s\t", addr, port);
|
|
|
|
ASSERT(2 == n);
|
|
|
|
|
|
|
|
wlinfo("from (%s:%s) \n", addr, port);
|
|
|
|
|
|
|
|
inet_aton(addr, &pkt_dat->addr.sin_addr);
|
|
|
|
pkt_dat->addr.sin_port = htons((uint16_t)atoi(port));
|
|
|
|
|
|
|
|
/* Skip until data length */
|
|
|
|
|
|
|
|
for (; '\t' != (char)*(pkt_ctx->ptr); pkt_ctx->ptr++);
|
|
|
|
pkt_ctx->ptr++;
|
|
|
|
|
|
|
|
/* Read data length */
|
|
|
|
|
|
|
|
pkt_ctx->dlen = _to_uint16((char *)pkt_ctx->ptr);
|
|
|
|
pkt_ctx->ptr += 3;
|
|
|
|
|
|
|
|
wlinfo("dlen=%d \n", pkt_ctx->dlen);
|
|
|
|
|
|
|
|
/* Allocate memory for the packet */
|
|
|
|
|
|
|
|
pkt_dat->data = kmm_calloc(pkt_ctx->dlen, 1);
|
|
|
|
ASSERT(pkt_dat->data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_push_data_to_pkt(pkt_dat, *(pkt_ctx->ptr));
|
|
|
|
|
|
|
|
pkt_ctx->dlen--;
|
|
|
|
|
|
|
|
if (0 == pkt_ctx->dlen)
|
|
|
|
{
|
|
|
|
pkt_ctx->state = PKT_START;
|
|
|
|
pkt_ctx->type = TYPE_BULK_DATA_UDP;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: _parse_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e _parse_pkt(FAR uint8_t *p, uint16_t len,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
struct pkt_ctx_s pkt_ctx;
|
|
|
|
|
|
|
|
/* Initialize pkt_ctx */
|
|
|
|
|
|
|
|
pkt_ctx.type = TYPE_UNMATCH;
|
|
|
|
pkt_ctx.state = PKT_START;
|
|
|
|
pkt_ctx.head = NULL;
|
|
|
|
pkt_ctx.cid = 'z';
|
|
|
|
pkt_ctx.dlen = 0;
|
|
|
|
|
|
|
|
for (pkt_ctx.ptr = p; pkt_ctx.ptr < (p + len); pkt_ctx.ptr++)
|
|
|
|
{
|
|
|
|
switch (pkt_ctx.state)
|
|
|
|
{
|
|
|
|
case PKT_START:
|
|
|
|
_parse_pkt_in_s0(&pkt_ctx, pkt_dat);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PKT_EVENT:
|
|
|
|
_parse_pkt_in_s1(&pkt_ctx, pkt_dat);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PKT_ESC_START:
|
|
|
|
_parse_pkt_in_s2(&pkt_ctx, pkt_dat);
|
|
|
|
break;
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
case PKT_BULK_DATA_TCP:
|
2019-06-18 14:44:03 +02:00
|
|
|
_parse_pkt_in_s3(&pkt_ctx, pkt_dat);
|
|
|
|
break;
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
case PKT_BULK_DATA_UDP:
|
|
|
|
_parse_pkt_in_s4(&pkt_ctx, pkt_dat);
|
|
|
|
break;
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
default:
|
|
|
|
ASSERT(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pkt_ctx.type;
|
|
|
|
}
|
|
|
|
|
2020-10-27 02:35:43 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: _dup_pkt_dat_and_notify
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void _dup_pkt_dat_and_notify(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat0)
|
|
|
|
{
|
|
|
|
struct pkt_dat_s *pkt_dat;
|
|
|
|
uint8_t c;
|
|
|
|
|
|
|
|
/* Only bulk data */
|
|
|
|
|
|
|
|
ASSERT(pkt_dat0->data && (0 == pkt_dat0->n));
|
|
|
|
|
|
|
|
/* Allocate a new pkt_dat */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)kmm_malloc(sizeof(struct pkt_dat_s));
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
/* Copy pkt_dat0 to pkt_dat */
|
|
|
|
|
|
|
|
memcpy(pkt_dat, pkt_dat0, sizeof(struct pkt_dat_s));
|
|
|
|
|
|
|
|
/* Allocate bulk data and copy */
|
|
|
|
|
|
|
|
pkt_dat->data = (FAR uint8_t *)kmm_malloc(pkt_dat0->len);
|
|
|
|
ASSERT(pkt_dat->data);
|
|
|
|
memcpy(pkt_dat->data, pkt_dat0->data, pkt_dat0->len);
|
|
|
|
|
|
|
|
/* Convert cid to c */
|
|
|
|
|
|
|
|
c = _cid_to_uint8(pkt_dat->cid);
|
|
|
|
|
|
|
|
/* Add the pkt_dat to the pkt_q */
|
|
|
|
|
|
|
|
dq_addlast((FAR dq_entry_t *)pkt_dat, &dev->pkt_q[c]);
|
|
|
|
dev->pkt_q_cnt[c]++;
|
|
|
|
|
|
|
|
/* NOTE: total_bulk must be updated
|
|
|
|
* Usually, total_bulk is updated in gs2200m_recv_pkt()
|
|
|
|
* However, the pkt_dat was duplicated from pkt_dat0
|
|
|
|
* So it needs to be updated, otherwise it will cause ASSERT
|
|
|
|
*/
|
|
|
|
|
|
|
|
dev->total_bulk += pkt_dat->len;
|
|
|
|
|
|
|
|
_notif_q_push(dev, pkt_dat->cid);
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_recv_pkt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_recv_pkt(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
enum pkt_type_e t = TYPE_ERROR;
|
|
|
|
enum spi_status_e s;
|
|
|
|
uint16_t len;
|
|
|
|
uint8_t *p;
|
|
|
|
|
|
|
|
p = (uint8_t *)kmm_calloc(MAX_PKT_LEN, 1);
|
|
|
|
ASSERT(p);
|
|
|
|
|
|
|
|
s = gs2200m_hal_read(dev, p, &len);
|
|
|
|
t = _spi_err_to_pkt_type(s);
|
|
|
|
|
|
|
|
if (TYPE_OK != t)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
wlinfo("+++ len=%d pkt_dat=%p \n", len, pkt_dat);
|
|
|
|
|
|
|
|
/* Parse the received packet */
|
|
|
|
|
|
|
|
t = _parse_pkt(p, len, pkt_dat);
|
|
|
|
|
|
|
|
if (t == TYPE_DISCONNECT)
|
|
|
|
{
|
|
|
|
_check_pkt_q_cnt(dev, pkt_dat->cid);
|
|
|
|
}
|
|
|
|
|
2020-10-30 07:19:50 +01:00
|
|
|
if (t == TYPE_DISASSOCIATE)
|
|
|
|
{
|
|
|
|
dev->disassociate_flag = true;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
if (pkt_dat)
|
|
|
|
{
|
|
|
|
pkt_dat->type = t;
|
|
|
|
|
2020-07-29 03:27:27 +02:00
|
|
|
if (t == TYPE_BULK_DATA_TCP ||
|
|
|
|
t == TYPE_BULK_DATA_UDP)
|
|
|
|
{
|
|
|
|
/* Update total bulk data size */
|
2020-06-01 06:52:59 +02:00
|
|
|
|
2020-07-29 03:27:27 +02:00
|
|
|
dev->total_bulk += pkt_dat->len;
|
|
|
|
}
|
2020-06-01 06:52:59 +02:00
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
errout:
|
|
|
|
kmm_free(p);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_send_cmd
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_send_cmd(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR char *cmd,
|
|
|
|
FAR struct pkt_dat_s *pkt_dat)
|
|
|
|
{
|
|
|
|
enum spi_status_e s;
|
|
|
|
enum pkt_type_e r = TYPE_SPI_ERROR;
|
2020-10-27 02:35:43 +01:00
|
|
|
bool bulk = false;
|
2020-08-11 02:39:43 +02:00
|
|
|
int n = 1;
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Disable gs2200m irq to poll dready */
|
|
|
|
|
|
|
|
dev->lower->disable();
|
|
|
|
|
|
|
|
wlinfo("+++ cmd=%s", cmd);
|
|
|
|
|
2020-08-11 02:39:43 +02:00
|
|
|
retry:
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
s = gs2200m_hal_write(dev, cmd, strlen(cmd));
|
|
|
|
r = _spi_err_to_pkt_type(s);
|
|
|
|
|
|
|
|
if (TYPE_OK != r)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-10-27 02:35:43 +01:00
|
|
|
retry_recv:
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
r = gs2200m_recv_pkt(dev, pkt_dat);
|
|
|
|
|
2020-10-27 02:35:43 +01:00
|
|
|
if ((TYPE_BULK_DATA_TCP == r || TYPE_BULK_DATA_UDP == r) && pkt_dat)
|
|
|
|
{
|
|
|
|
wlwarn("*** Found bulk data \n");
|
|
|
|
|
|
|
|
/* Bulk data found in the response,
|
|
|
|
* duplicate the packet and notify
|
|
|
|
*/
|
|
|
|
|
|
|
|
_dup_pkt_dat_and_notify(dev, pkt_dat);
|
|
|
|
|
|
|
|
/* release & initialize pkt_dat before retry */
|
|
|
|
|
|
|
|
_release_pkt_dat(dev, pkt_dat);
|
|
|
|
memset(pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
|
|
|
|
bulk = true;
|
|
|
|
goto retry_recv;
|
|
|
|
}
|
|
|
|
|
2020-08-11 02:39:43 +02:00
|
|
|
/* NOTE: retry in case of errors */
|
|
|
|
|
|
|
|
if ((TYPE_OK != r) && (0 <= --n))
|
|
|
|
{
|
|
|
|
if (pkt_dat)
|
|
|
|
{
|
|
|
|
/* release & initialize pkt_dat before retry */
|
|
|
|
|
|
|
|
_release_pkt_dat(dev, pkt_dat);
|
|
|
|
memset(pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
}
|
|
|
|
|
|
|
|
wlwarn("*** retry cmd=%s (n=%d) \n", cmd, n);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
errout:
|
|
|
|
|
2020-10-27 02:35:43 +01:00
|
|
|
if (bulk)
|
|
|
|
{
|
|
|
|
wlwarn("*** Normal response r=%d \n", r);
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/* Enable gs2200m irq again */
|
|
|
|
|
|
|
|
dev->lower->enable();
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_opmode
|
|
|
|
* NOTE: See 5.1.2 Operation Mode
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_opmode(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t mode)
|
|
|
|
{
|
2019-07-10 13:26:39 +02:00
|
|
|
enum pkt_type_e t;
|
2019-06-18 14:44:03 +02:00
|
|
|
char cmd[20];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WM=%d\r\n", mode);
|
2019-07-10 13:26:39 +02:00
|
|
|
t = gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
|
|
|
|
if (TYPE_OK == t)
|
|
|
|
{
|
|
|
|
dev->op_mode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_get_mac
|
|
|
|
* NOTE: See 4.5.2 Get MAC Address
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_get_mac(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
uint32_t mac[6];
|
|
|
|
char cmd[16];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send command */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NMAC=?\r\n");
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-18 00:27:36 +01:00
|
|
|
n = sscanf(pkt_dat.msg[0], "%2" PRIx32 ":%2" PRIx32 ":%2" PRIx32
|
|
|
|
":%2" PRIx32 ":%2" PRIx32 ":%2" PRIx32,
|
|
|
|
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
|
2019-06-18 14:44:03 +02:00
|
|
|
DEBUGASSERT(n == 6);
|
|
|
|
|
|
|
|
for (n = 0; n < 6; n++)
|
|
|
|
{
|
|
|
|
dev->net_dev.d_mac.ether.ether_addr_octet[n] = (uint8_t)mac[n];
|
|
|
|
}
|
|
|
|
|
2019-07-04 13:30:54 +02:00
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_disassociate
|
|
|
|
* NOTE: See 5.3.6 Disassociation
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_disassociate(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
return gs2200m_send_cmd(dev, (char *)"AT+WD\r\n", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_enable_dhcpc
|
|
|
|
* NOTE: See 6.3 DHCP Client
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_enable_dhcpc(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t on)
|
|
|
|
{
|
|
|
|
char cmd[16];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NDHCP=%d\r\n", on);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_calc_key
|
|
|
|
* NOTE: See 5.3.3.5 WPA-PSK and WPA2-PSK Key Calculation
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_calc_key(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR char *ssid, FAR char *psk)
|
|
|
|
{
|
|
|
|
char cmd[80];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WPAPSK=%s,%s\r\n", ssid, psk);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_security
|
|
|
|
* NOTE: See 5.3.3.1 Security Setting
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_security(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t mode)
|
|
|
|
{
|
|
|
|
char cmd[16];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WSEC=%d\r\n", mode);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_join_network
|
|
|
|
* NOTE: See 5.3.5 Association
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_join_network(FAR struct gs2200m_dev_s *dev,
|
2019-07-10 13:26:39 +02:00
|
|
|
FAR char *ssid, uint8_t ch)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
char cmd[64];
|
|
|
|
char addr[3][17];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send command */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
2019-07-10 13:26:39 +02:00
|
|
|
|
|
|
|
if (0 == dev->op_mode)
|
|
|
|
{
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WA=%s\r\n", ssid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-23 09:50:23 +01:00
|
|
|
/* In AP mode, we can specify channel to use */
|
2019-07-10 13:26:39 +02:00
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WA=%s,,%d\r\n", ssid, ch);
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(3 == pkt_dat.n);
|
|
|
|
|
|
|
|
n = sscanf(pkt_dat.msg[1] + 1,
|
|
|
|
" %[^:]:%[^:]:%[^ ]",
|
|
|
|
addr[0], addr[1], addr[2]);
|
|
|
|
ASSERT(3 == n);
|
|
|
|
|
|
|
|
/* Set addresses to be shown with ifconfig */
|
|
|
|
|
|
|
|
inet_aton(addr[0], (struct in_addr *)&dev->net_dev.d_ipaddr);
|
|
|
|
inet_aton(addr[1], (struct in_addr *)&dev->net_dev.d_netmask);
|
|
|
|
inet_aton(addr[2], (struct in_addr *)&dev->net_dev.d_draddr);
|
|
|
|
|
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_addresses
|
|
|
|
* NOTE: See 6.4 IP Address
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_addresses(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR const char *address,
|
|
|
|
FAR const char *netmask,
|
|
|
|
FAR const char *gateway)
|
|
|
|
{
|
|
|
|
char cmd[100];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NSET=%s,%s,%s\r\n",
|
|
|
|
address, netmask, gateway);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_enable_dhcps
|
|
|
|
* NOTE: See 6.5 DHCP Server
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_enable_dhcps(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t on)
|
|
|
|
{
|
|
|
|
char cmd[20];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+DHCPSRVR=%d\r\n", on);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_auth
|
|
|
|
* NOTE: See 5.3.2 Authentication Mode
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_auth(FAR struct gs2200m_dev_s *dev,
|
|
|
|
int mode)
|
|
|
|
{
|
|
|
|
char cmd[16];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WAUTH=%d\r\n", mode);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
2020-05-22 06:52:37 +02:00
|
|
|
#ifdef CONFIG_WL_GS2200M_ENABLE_WEP
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_wepkey
|
2020-05-22 06:52:37 +02:00
|
|
|
* NOTE: See 5.3.3.2
|
2019-06-18 14:44:03 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_wepkey(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR char *key)
|
|
|
|
{
|
|
|
|
char cmd[32];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WWEP1=%s\r\n", key);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
2020-05-22 06:52:37 +02:00
|
|
|
#else
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_wpa2pf
|
|
|
|
* NOTE: See 5.3.3.4
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_set_wpa2pf(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR char *key)
|
|
|
|
{
|
|
|
|
char cmd[64];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WWPA=%s\r\n", key);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_WL_GS2200M_ENABLE_WEP */
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_get_wstatus
|
|
|
|
* NOTE: See 11.3.5 WLAN Status
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
enum pkt_type_e gs2200m_get_wstatus(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send command */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, (char *)"AT+WSTATUS\r\n", &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < pkt_dat.n; i++)
|
|
|
|
{
|
|
|
|
wlinfo("%s\n", pkt_dat.msg[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_create_tcpc
|
2020-04-14 09:42:45 +02:00
|
|
|
* NOTE: See 7.5.1.1 Create TCP Clients and 7.5.1.2 Create UDP Client
|
2019-06-18 14:44:03 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
2020-10-09 14:14:36 +02:00
|
|
|
static enum pkt_type_e
|
|
|
|
gs2200m_create_clnt(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_connect_msg *msg,
|
|
|
|
FAR char *cid)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
enum pkt_type_e r;
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
char cmd[40];
|
|
|
|
char *p;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
*cid = 'z'; /* Invalidate cid */
|
|
|
|
|
2020-10-09 14:14:36 +02:00
|
|
|
if (SOCK_STREAM == msg->type)
|
2020-04-14 09:42:45 +02:00
|
|
|
{
|
2020-10-09 14:14:36 +02:00
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NCTCP=%s,%s\r\n",
|
|
|
|
msg->addr, msg->port);
|
2020-04-14 09:42:45 +02:00
|
|
|
}
|
2020-10-09 14:14:36 +02:00
|
|
|
else if (SOCK_DGRAM == msg->type)
|
2020-04-14 09:42:45 +02:00
|
|
|
{
|
2020-10-09 14:14:36 +02:00
|
|
|
if (0 == msg->lport)
|
|
|
|
{
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NCUDP=%s,%s\r\n",
|
|
|
|
msg->addr, msg->port);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NCUDP=%s,%s,%d\r\n",
|
|
|
|
msg->addr, msg->port, msg->lport);
|
|
|
|
}
|
2020-04-14 09:42:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ASSERT(false);
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Initialize pkt_dat and send */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK || pkt_dat.n == 0)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: r=%d pkt_dat.msg[0]=%s \n",
|
|
|
|
r, pkt_dat.msg[0]);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-02 08:49:14 +01:00
|
|
|
if (NULL != (p = strstr(pkt_dat.msg[0], "CONNECT ")))
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
n = sscanf(p, "CONNECT %c", cid);
|
|
|
|
ASSERT(1 == n);
|
|
|
|
wlinfo("+++ OK: p=%s| (n=%d) \n", p, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
2019-07-25 07:40:06 +02:00
|
|
|
* Name: gs2200m_start_server
|
|
|
|
* NOTE: See 7.5.1.3 Start TCP Server, 7.5.1.4 Start UDP Server
|
2019-06-18 14:44:03 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
static enum pkt_type_e gs2200m_start_server(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR char *port, bool is_tcp,
|
|
|
|
FAR char *cid)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
enum pkt_type_e r;
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
char cmd[40];
|
|
|
|
char *p;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* Prepare cmd */
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
if (is_tcp)
|
|
|
|
{
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NSTCP=%s\r\n", port);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NSUDP=%s\r\n", port);
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Initialize pkt_dat and send */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK || pkt_dat.n == 0)
|
|
|
|
{
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-02 08:49:14 +01:00
|
|
|
if (NULL != (p = strstr(pkt_dat.msg[0], "CONNECT ")))
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
n = sscanf(p, "CONNECT %c", cid);
|
|
|
|
ASSERT(1 == n);
|
|
|
|
wlinfo("+++ OK: p=%s| (n=%d) \n", p, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_send_bulk
|
|
|
|
* NOTE: See 7.5.3.2 Bulk Data Handling
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_send_bulk(FAR struct gs2200m_dev_s *dev,
|
2019-07-25 07:40:06 +02:00
|
|
|
FAR struct gs2200m_send_msg *msg)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
enum pkt_type_e r;
|
|
|
|
enum spi_status_e s;
|
2019-07-25 07:40:06 +02:00
|
|
|
int bulk_hdr_size;
|
2019-06-18 14:44:03 +02:00
|
|
|
char digits[5];
|
2019-07-25 07:40:06 +02:00
|
|
|
char cmd[32];
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
memset(cmd, 0, sizeof(cmd));
|
|
|
|
|
2020-05-14 14:34:28 +02:00
|
|
|
if (MAX_PAYLOAD <= msg->len)
|
|
|
|
{
|
|
|
|
msg->len = MAX_PAYLOAD;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/* Convert the data length to 4 ascii char */
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
_to_ascii_char(msg->len, digits);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
wlinfo("** cid=%c len=%d digits=%s \n", msg->cid, msg->len, digits);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
if (msg->is_tcp)
|
|
|
|
{
|
|
|
|
/* NOTE: See 7.5.3.2 Bulk Data Handling for TCP
|
|
|
|
* <ESC>Z<CID><Data Length xxxx 4 ascii char><data>
|
|
|
|
*/
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "%cZ%c%s", ASCII_ESC, msg->cid, digits);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wlinfo("** addr=%s port=%d \n", inet_ntoa(msg->addr.sin_addr),
|
|
|
|
ntohs(msg->addr.sin_port));
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* NOTE: See 7.5.3.2 Bulk Data Handling for UDP
|
|
|
|
* <ESC>Y<CID><IP address>:<port>:<Data Length xxxx 4 ascii char><data>
|
|
|
|
*/
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "%cY%c%s:%d:%s",
|
|
|
|
ASCII_ESC, msg->cid,
|
|
|
|
inet_ntoa(msg->addr.sin_addr), ntohs(msg->addr.sin_port),
|
|
|
|
digits);
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
bulk_hdr_size = strlen(cmd);
|
2019-06-18 14:44:03 +02:00
|
|
|
memcpy(dev->tx_buff, cmd, bulk_hdr_size);
|
2019-07-25 07:40:06 +02:00
|
|
|
memcpy(dev->tx_buff + bulk_hdr_size, msg->buf, msg->len);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Send the bulk data */
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
s = gs2200m_hal_write(dev, (char *)dev->tx_buff, msg->len + bulk_hdr_size);
|
2020-01-28 08:45:11 +01:00
|
|
|
|
|
|
|
if (s == SPI_TIMEOUT)
|
|
|
|
{
|
|
|
|
/* In case of SPI_TIMEOUT, return OK with 0 bytes sent */
|
|
|
|
|
|
|
|
s = SPI_OK;
|
|
|
|
msg->len = 0;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
r = _spi_err_to_pkt_type(s);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_close_conn
|
|
|
|
* NOTE: See 7.1.4 Closing a Connection
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_close_conn(FAR struct gs2200m_dev_s *dev,
|
|
|
|
char cid)
|
|
|
|
{
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
char cmd[15];
|
|
|
|
|
|
|
|
/* Prepare cmd */
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NCLOSE=%c\r\n", cid);
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2019-06-18 14:44:03 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_enable_bulk
|
|
|
|
* NOTE: See 7.1.1 Data Transfer in Bulk Mode
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_enable_bulk(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t on)
|
|
|
|
{
|
|
|
|
char cmd[20];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+BDATA=%d\r\n", on);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_enable_echo
|
|
|
|
* NOTE: See 11.3.2 Echo
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_enable_echo(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t on)
|
|
|
|
{
|
|
|
|
char cmd[8];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "ATE%d\r\n", on);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_activate_wrx
|
|
|
|
* NOTE: See 9.1.1 Active Radio Receive
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_activate_wrx(FAR struct gs2200m_dev_s *dev,
|
|
|
|
uint8_t on)
|
|
|
|
{
|
|
|
|
char cmd[30];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+WRXACTIVE=%d\r\n", on);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_gpio
|
|
|
|
* NOTE: See 10.3 GPIO Commands
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef USE_LED
|
|
|
|
static enum pkt_type_e gs2200m_set_gpio(FAR struct gs2200m_dev_s *dev,
|
|
|
|
int n, int val)
|
|
|
|
{
|
|
|
|
char cmd[24];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+DGPIO=%d,%d\r\n", n, val);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-02-05 22:32:33 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_set_loglevel
|
|
|
|
* NOTE: See 11.3.1 Log Level
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#if CONFIG_WL_GS2200M_LOGLEVEL > 0
|
|
|
|
static enum pkt_type_e gs2200m_set_loglevel(FAR struct gs2200m_dev_s *dev,
|
|
|
|
int level)
|
|
|
|
{
|
|
|
|
char cmd[16];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+LOGLVL=%d\r\n", level);
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_get_version
|
|
|
|
****************************************************************************/
|
|
|
|
|
2020-02-05 22:32:33 +01:00
|
|
|
#ifdef CONFIG_WL_GS2200M_CHECK_VERSION
|
2019-06-18 14:44:03 +02:00
|
|
|
static enum pkt_type_e gs2200m_get_version(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
char cmd[16];
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+VER=??\r\n");
|
|
|
|
return gs2200m_send_cmd(dev, cmd, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-05-14 01:10:04 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_get_cstatus
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static enum pkt_type_e gs2200m_get_cstatus(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_name_msg *msg)
|
|
|
|
{
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
char cmd[16];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+CID=?\r\n");
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK || pkt_dat.n <= 2)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: r=%d pkt_dat.msg[0]=%s \n",
|
|
|
|
r, pkt_dat.msg[0]);
|
|
|
|
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find cid in the connection status */
|
|
|
|
|
|
|
|
for (i = 1; i < pkt_dat.n - 2; i++)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
char c;
|
|
|
|
int a[4];
|
|
|
|
int p[2];
|
|
|
|
char type[8];
|
|
|
|
char mode[8];
|
|
|
|
memset(type, 0, sizeof(type));
|
|
|
|
memset(mode, 0, sizeof(mode));
|
|
|
|
n = sscanf(pkt_dat.msg[i], "%c %7s %6s %d %d %d.%d.%d.%d",
|
|
|
|
&c, type, mode, &p[0], &p[1],
|
|
|
|
&a[0], &a[1], &a[2], &a[3]);
|
|
|
|
ASSERT(9 == n);
|
|
|
|
|
|
|
|
wlinfo("[%d]: %c %s %s %d %d %d.%d.%d.%d \n",
|
|
|
|
i, c, type, mode, p[0], p[1],
|
|
|
|
a[0], a[1], a[2], a[3]);
|
|
|
|
|
|
|
|
if (c == msg->cid)
|
|
|
|
{
|
|
|
|
/* Set family, port and address (remote only) */
|
|
|
|
|
|
|
|
msg->addr.sin_family = AF_INET;
|
|
|
|
|
|
|
|
if (msg->local)
|
|
|
|
{
|
|
|
|
msg->addr.sin_port = htons(p[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char addr[20];
|
|
|
|
msg->addr.sin_port = htons(p[1]);
|
|
|
|
snprintf(addr, sizeof(addr),
|
|
|
|
"%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
|
|
|
|
inet_aton(addr, &msg->addr.sin_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Not found */
|
|
|
|
|
|
|
|
r = TYPE_UNMATCH;
|
|
|
|
|
|
|
|
errout:
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
2020-05-14 01:10:04 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_bind
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_bind(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_bind_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e type = TYPE_OK;
|
2020-05-14 04:26:55 +02:00
|
|
|
bool auto_assign = false;
|
|
|
|
char port_str[6];
|
|
|
|
uint16_t port;
|
2019-07-25 07:40:06 +02:00
|
|
|
char cid = 'z';
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("+++ start: (cid=%c, port=%s) \n", msg->cid, msg->port);
|
|
|
|
|
2020-05-14 04:26:55 +02:00
|
|
|
port = (uint16_t)strtol(msg->port, NULL, 10);
|
|
|
|
|
|
|
|
if (0 == port)
|
|
|
|
{
|
|
|
|
auto_assign = true;
|
|
|
|
port = PORT_START;
|
|
|
|
}
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
|
|
snprintf(port_str, sizeof(port_str), "%d", port);
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* Start TCP/UDP server and retrieve cid */
|
|
|
|
|
2020-05-14 04:26:55 +02:00
|
|
|
type = gs2200m_start_server(dev, port_str, msg->is_tcp, &cid);
|
2019-07-25 07:40:06 +02:00
|
|
|
|
|
|
|
if (type != TYPE_OK)
|
|
|
|
{
|
2020-05-14 04:26:55 +02:00
|
|
|
if (auto_assign && (port < PORT_END))
|
|
|
|
{
|
|
|
|
port++;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable the cid for server socket and if the pkt_q is empty */
|
|
|
|
|
|
|
|
_enable_cid(&dev->valid_cid_bits, cid, true);
|
|
|
|
_check_pkt_q_empty(dev, cid);
|
|
|
|
|
|
|
|
errout:
|
|
|
|
|
|
|
|
msg->type = type;
|
|
|
|
msg->cid = cid;
|
|
|
|
|
|
|
|
wlinfo("+++ end: type=%d (cid=%c) \n", type, cid);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_connect
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_connect(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_connect_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e type;
|
|
|
|
char cid = 'z';
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("++ start: addr=%s port=%s \n", msg->addr, msg->port);
|
|
|
|
|
2020-04-14 09:42:45 +02:00
|
|
|
/* Create TCP or UDP connection */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-10-09 14:14:36 +02:00
|
|
|
type = gs2200m_create_clnt(dev, msg, &cid);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
msg->type = type;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case TYPE_OK:
|
|
|
|
msg->cid = cid;
|
|
|
|
|
|
|
|
/* Enable the cid and checi if the pkt_q is empty */
|
|
|
|
|
|
|
|
_enable_cid(&dev->valid_cid_bits, cid, true);
|
|
|
|
_check_pkt_q_empty(dev, cid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TYPE_ERROR:
|
|
|
|
|
|
|
|
/* We assume the connection has been refused */
|
|
|
|
|
|
|
|
ret = -ECONNREFUSED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TYPE_TIMEOUT:
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
wlerr("+++ error: type=%d \n", type);
|
|
|
|
ASSERT(false);
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
wlinfo("++ end: cid=%c (type=%d,ret=%d) \n", cid, type, ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_send
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_send(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_send_msg *msg)
|
|
|
|
{
|
2019-07-25 07:40:06 +02:00
|
|
|
FAR struct gs2200m_bind_msg bmsg;
|
2019-06-18 14:44:03 +02:00
|
|
|
enum pkt_type_e type;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("+++ start: (cid=%c) \n", msg->cid);
|
|
|
|
|
|
|
|
#ifdef USE_LED
|
|
|
|
gs2200m_set_gpio(dev, LED_GPIO, 1);
|
|
|
|
#endif
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* If the msg is udp having unassgined cid */
|
|
|
|
|
|
|
|
if (!msg->is_tcp && 'z' == msg->cid)
|
|
|
|
{
|
2020-05-14 04:26:55 +02:00
|
|
|
/* NOTE: need to assign port automatically */
|
2019-07-25 07:40:06 +02:00
|
|
|
|
2020-05-14 04:26:55 +02:00
|
|
|
memset(&bmsg, 0, sizeof(bmsg));
|
|
|
|
ret = gs2200m_ioctl_bind(dev, &bmsg);
|
|
|
|
ASSERT(0 == ret);
|
2019-07-25 07:40:06 +02:00
|
|
|
|
|
|
|
wlinfo("+++ cid is assigned for udp (cid=%c) \n", bmsg.cid);
|
|
|
|
msg->cid = bmsg.cid;
|
|
|
|
}
|
|
|
|
|
2019-07-03 02:11:24 +02:00
|
|
|
if (!_cid_is_set(&dev->valid_cid_bits, msg->cid))
|
|
|
|
{
|
|
|
|
wlinfo("+++ already closed \n");
|
|
|
|
type = TYPE_DISCONNECT;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
type = gs2200m_send_bulk(dev, msg);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
msg->type = type;
|
|
|
|
|
2019-07-03 02:11:24 +02:00
|
|
|
errout:
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
if (type != TYPE_OK)
|
|
|
|
{
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_LED
|
|
|
|
gs2200m_set_gpio(dev, LED_GPIO, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wlinfo("+++ end: cid=%c len=%d type=%d \n",
|
|
|
|
msg->cid, msg->len, type);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_recv
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_recv(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_recv_msg *msg)
|
|
|
|
{
|
|
|
|
bool cont = true;
|
|
|
|
int ret = OK;
|
|
|
|
uint8_t c = _cid_to_uint8(msg->cid);
|
|
|
|
|
|
|
|
wlinfo("+++ start: cid=%c \n", msg->cid);
|
|
|
|
|
|
|
|
#ifdef USE_LED
|
|
|
|
gs2200m_set_gpio(dev, LED_GPIO, 1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (0 == dev->pkt_q_cnt[c])
|
|
|
|
{
|
|
|
|
/* REVISIT */
|
|
|
|
|
|
|
|
wlwarn("**** no packet for cid=%c \n", msg->cid);
|
|
|
|
ret = -EAGAIN;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
/* Finished copying or no packet */
|
|
|
|
|
|
|
|
if (msg->reqlen == msg->len || 0 == dev->pkt_q_cnt[c] || !cont)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy data from the front-most packet */
|
|
|
|
|
|
|
|
cont = _copy_data_from_pkt(dev, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
wlinfo("+++ pkt_q_cnt[%c]=%d \n", msg->cid, dev->pkt_q_cnt[c]);
|
|
|
|
|
|
|
|
if (dev->pkt_q_cnt[c])
|
|
|
|
{
|
|
|
|
_notif_q_push(dev, msg->cid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do packet flow control */
|
|
|
|
|
|
|
|
_control_pkt_q(dev);
|
|
|
|
|
|
|
|
errout:
|
|
|
|
|
|
|
|
#ifdef USE_LED
|
|
|
|
gs2200m_set_gpio(dev, LED_GPIO, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wlinfo("+++ end: cid=%c len=%d type=%d ret=%d \n",
|
|
|
|
msg->cid, msg->len, msg->type, ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_close
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_close(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_close_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e type = TYPE_OK;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("++ start: (cid=%c) \n", msg->cid);
|
|
|
|
|
|
|
|
if (!_cid_is_set(&dev->valid_cid_bits, msg->cid))
|
|
|
|
{
|
|
|
|
wlinfo("+++ already closed \n");
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable the cid */
|
|
|
|
|
|
|
|
_enable_cid(&dev->valid_cid_bits, msg->cid, false);
|
|
|
|
|
|
|
|
type = gs2200m_close_conn(dev, msg->cid);
|
|
|
|
|
|
|
|
if (type != TYPE_OK)
|
|
|
|
{
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
|
|
|
|
|
|
|
/* Remove all pkt associated with this cid */
|
|
|
|
|
|
|
|
_remove_all_pkt(dev, _cid_to_uint8(msg->cid));
|
|
|
|
|
2020-05-21 02:56:05 +02:00
|
|
|
/* Do packet flow control */
|
|
|
|
|
|
|
|
_control_pkt_q(dev);
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
wlinfo("++ end: cid=%c type=%d \n", msg->cid, type);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_accept
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_accept(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_accept_msg *msg)
|
|
|
|
{
|
|
|
|
FAR struct pkt_dat_s *pkt_dat;
|
2020-10-12 06:10:23 +02:00
|
|
|
struct gs2200m_name_msg nmsg;
|
|
|
|
enum pkt_type_e r;
|
2019-06-18 14:44:03 +02:00
|
|
|
uint8_t c;
|
|
|
|
char s_cid;
|
|
|
|
char c_cid;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
wlinfo("+++ start: cid=%c \n", msg->cid);
|
|
|
|
|
|
|
|
c = _cid_to_uint8(msg->cid);
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)dq_peek(&dev->pkt_q[c]);
|
|
|
|
ASSERT(pkt_dat);
|
|
|
|
|
|
|
|
n = sscanf(pkt_dat->msg[0], "CONNECT %c %c", &s_cid, &c_cid);
|
|
|
|
ASSERT(2 == n);
|
|
|
|
|
|
|
|
wlinfo("+++ s_cid=%c c_cid=%c \n", s_cid, c_cid);
|
|
|
|
|
|
|
|
/* Remove the accept packet (actually CONNECT) from the queue */
|
|
|
|
|
|
|
|
_remove_and_free_pkt(dev, _cid_to_uint8(msg->cid));
|
|
|
|
|
|
|
|
/* Copy a client cid which was obtained in CONNECT event */
|
|
|
|
|
|
|
|
msg->type = TYPE_OK;
|
|
|
|
msg->cid = c_cid; /* NOTE: override new client cid */
|
|
|
|
|
2020-02-23 09:50:23 +01:00
|
|
|
/* Disable accept in progress */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
_enable_cid(&dev->aip_cid_bits, c_cid, false);
|
|
|
|
|
|
|
|
/* If a packet still exists, notify it */
|
|
|
|
|
|
|
|
if (dev->pkt_q_cnt[_cid_to_uint8(c_cid)])
|
|
|
|
{
|
|
|
|
_notif_q_push(dev, c_cid);
|
|
|
|
}
|
|
|
|
|
2020-10-12 06:10:23 +02:00
|
|
|
/* Obtain remote address info */
|
|
|
|
|
|
|
|
nmsg.local = 0;
|
|
|
|
nmsg.cid = msg->cid;
|
|
|
|
r = gs2200m_get_cstatus(dev, &nmsg);
|
|
|
|
ASSERT(TYPE_OK == r);
|
|
|
|
|
|
|
|
msg->addr = nmsg.addr;
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
wlinfo("+++ end: type=%d (msg->cid=%c) \n", msg->type, msg->cid);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_assoc_sta
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_assoc_sta(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_assoc_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e t;
|
|
|
|
|
2020-10-30 07:19:50 +01:00
|
|
|
/* Remember assoc request msg for reconnection */
|
|
|
|
|
|
|
|
memcpy(&dev->reconnect_msg, msg, sizeof(struct gs2200m_assoc_msg));
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* Disassociate */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
t = gs2200m_disassociate(dev);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* Set to STA mode */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
t = gs2200m_set_opmode(dev, 0);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
2019-07-30 12:49:16 +02:00
|
|
|
#ifdef CONFIG_WL_GS2200M_DISABLE_DHCPC
|
|
|
|
/* Disable DHCP Client */
|
|
|
|
|
|
|
|
t = gs2200m_enable_dhcpc(dev, 0);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set static address */
|
2019-09-18 13:34:00 +02:00
|
|
|
|
2019-07-30 12:49:16 +02:00
|
|
|
t = gs2200m_set_addresses(dev,
|
|
|
|
"10.0.0.2",
|
|
|
|
"255.255.255.0",
|
|
|
|
"10.0.0.1"
|
|
|
|
);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
#else
|
2019-07-25 07:40:06 +02:00
|
|
|
/* Enable DHCP Client */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
t = gs2200m_enable_dhcpc(dev, 1);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(TYPE_OK == t);
|
2019-07-30 12:49:16 +02:00
|
|
|
#endif
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
/* Get mac address info */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2019-07-25 07:40:06 +02:00
|
|
|
t = gs2200m_get_mac(dev);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set WPA2 Passphrase */
|
|
|
|
|
|
|
|
if (TYPE_OK != gs2200m_calc_key(dev, msg->ssid, msg->key))
|
|
|
|
{
|
|
|
|
wlerr("*** error: invalid wpa2 key (key:%s) \n", msg->key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Associate with AP */
|
|
|
|
|
2019-07-10 13:26:39 +02:00
|
|
|
if (TYPE_OK != gs2200m_join_network(dev, msg->ssid, 0))
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
|
|
|
wlerr("*** error: failed to join (ssid:%s) \n", msg->ssid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-10-30 07:19:50 +01:00
|
|
|
dev->disassociate_flag = false;
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_assoc_ap
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_assoc_ap(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_assoc_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e t;
|
|
|
|
|
|
|
|
/* Set to AP mode */
|
|
|
|
|
|
|
|
t = gs2200m_set_opmode(dev, 2);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Get mac address info */
|
|
|
|
|
|
|
|
t = gs2200m_get_mac(dev);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Disassociate */
|
|
|
|
|
|
|
|
t = gs2200m_disassociate(dev);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set address info */
|
|
|
|
|
|
|
|
t = gs2200m_set_addresses(dev,
|
|
|
|
"192.168.11.1",
|
|
|
|
"255.255.255.0",
|
|
|
|
"192.168.11.1"
|
|
|
|
);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set auth mode */
|
|
|
|
|
|
|
|
t = gs2200m_set_auth(dev, 2);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
2020-05-22 06:52:37 +02:00
|
|
|
#ifdef CONFIG_WL_GS2200M_ENABLE_WEP
|
|
|
|
/* Set security mode (WEP) */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-05-22 06:52:37 +02:00
|
|
|
t = gs2200m_set_security(dev, SEC_MODE_WEP);
|
2019-06-18 14:44:03 +02:00
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set WEP key */
|
|
|
|
|
|
|
|
if (TYPE_OK != gs2200m_set_wepkey(dev, msg->key))
|
|
|
|
{
|
|
|
|
wlerr("*** error: invalid wepkey: %s \n", msg->key);
|
|
|
|
return -1;
|
|
|
|
}
|
2020-05-22 06:52:37 +02:00
|
|
|
#else
|
|
|
|
/* Set security mode (WPA2-PSK) */
|
|
|
|
|
|
|
|
t = gs2200m_set_security(dev, SEC_MODE_WPA2PSK);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set WPA-PSK and WPA2-PSK Passphrase */
|
|
|
|
|
|
|
|
if (TYPE_OK != gs2200m_set_wpa2pf(dev, msg->key))
|
|
|
|
{
|
|
|
|
wlerr("*** error: invalid passphrase: %s \n", msg->key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Start DHCP server */
|
|
|
|
|
|
|
|
t = gs2200m_enable_dhcps(dev, 1);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Enable the AP */
|
|
|
|
|
2019-07-10 13:26:39 +02:00
|
|
|
if (TYPE_OK != gs2200m_join_network(dev, msg->ssid, msg->ch))
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
2019-07-10 13:26:39 +02:00
|
|
|
wlerr("*** error: failed to join (ssid:%s, ch:%d) \n",
|
|
|
|
msg->ssid, msg->ch);
|
2019-06-18 14:44:03 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2020-11-02 08:49:14 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_gs2200m_ioctl_iwreq
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_iwreq(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_ifreq_msg *msg)
|
|
|
|
{
|
|
|
|
struct iwreq *res = (struct iwreq *)&msg->ifr;
|
|
|
|
struct pkt_dat_s pkt_dat;
|
|
|
|
enum pkt_type_e r;
|
|
|
|
char cmd[64];
|
|
|
|
char cmd2[64];
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
snprintf(cmd, sizeof(cmd), "AT+NSTAT=?\r\n");
|
|
|
|
|
|
|
|
/* Initialize pkt_dat and send */
|
|
|
|
|
|
|
|
memset(&pkt_dat, 0, sizeof(pkt_dat));
|
|
|
|
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
|
|
|
|
|
|
|
|
if (r != TYPE_OK || pkt_dat.n <= 7)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: r=%d pkt_dat.msg[0]=%s \n",
|
|
|
|
r, pkt_dat.msg[0]);
|
|
|
|
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find cid in the connection status */
|
|
|
|
|
|
|
|
if (msg->cmd == SIOCGIWNWID)
|
|
|
|
{
|
|
|
|
if (strstr(pkt_dat.msg[2], "BSSID=") == NULL)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: pkt_dat.msg[2]=%s \n", pkt_dat.msg[2]);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-18 00:27:36 +01:00
|
|
|
n = sscanf(pkt_dat.msg[2], "BSSID=%c:%c:%c:%c:%c:%c %s",
|
2020-11-02 08:49:14 +01:00
|
|
|
&res->u.ap_addr.sa_data[0], &res->u.ap_addr.sa_data[1],
|
|
|
|
&res->u.ap_addr.sa_data[2], &res->u.ap_addr.sa_data[3],
|
|
|
|
&res->u.ap_addr.sa_data[4], &res->u.ap_addr.sa_data[5],
|
|
|
|
cmd);
|
|
|
|
ASSERT(7 == n);
|
|
|
|
wlinfo("BSSID:%02X:%02X:%02X:%02X:%02X:%02X\n",
|
|
|
|
res->u.ap_addr.sa_data[0], res->u.ap_addr.sa_data[1],
|
|
|
|
res->u.ap_addr.sa_data[2], res->u.ap_addr.sa_data[3],
|
|
|
|
res->u.ap_addr.sa_data[4], res->u.ap_addr.sa_data[5]);
|
|
|
|
}
|
|
|
|
else if (msg->cmd == SIOCGIWFREQ)
|
|
|
|
{
|
|
|
|
if (strstr(pkt_dat.msg[2], "CHANNEL=") == NULL)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: pkt_dat.msg[2]=%s \n", pkt_dat.msg[2]);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-18 00:27:36 +01:00
|
|
|
n = sscanf(pkt_dat.msg[2], "%s CHANNEL=%" SCNd32 " %s",
|
2020-11-02 08:49:14 +01:00
|
|
|
cmd, &res->u.freq.m, cmd2);
|
|
|
|
ASSERT(3 == n);
|
|
|
|
wlinfo("CHANNEL:%d\n", res->u.freq.m);
|
|
|
|
}
|
|
|
|
else if (msg->cmd == SIOCGIWSENS)
|
|
|
|
{
|
|
|
|
if (strstr(pkt_dat.msg[3], "RSSI=") == NULL)
|
|
|
|
{
|
|
|
|
wlinfo("+++ error: pkt_dat.msg[3]=%s \n", pkt_dat.msg[3]);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-11-18 00:27:36 +01:00
|
|
|
n = sscanf(pkt_dat.msg[3], "RSSI=%" SCNd8, &res->u.qual.level);
|
2020-11-02 08:49:14 +01:00
|
|
|
ASSERT(1 == n);
|
|
|
|
wlinfo("RSSI:%d\n", res->u.qual.level);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
|
|
|
_release_pkt_dat(dev, &pkt_dat);
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2019-07-30 12:49:16 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ifreq_ifreq
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_ifreq(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_ifreq_msg *msg)
|
|
|
|
{
|
|
|
|
FAR struct sockaddr_in *inaddr;
|
|
|
|
struct in_addr in[3];
|
|
|
|
char addr[3][17];
|
2019-09-02 15:08:34 +02:00
|
|
|
bool getreq = false;
|
2019-07-30 12:49:16 +02:00
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("+++ start: cmd=%x \n", msg->cmd);
|
|
|
|
|
|
|
|
inaddr = (FAR struct sockaddr_in *)&msg->ifr.ifr_addr;
|
|
|
|
|
|
|
|
switch (msg->cmd)
|
|
|
|
{
|
2019-09-02 15:08:34 +02:00
|
|
|
case SIOCGIFHWADDR:
|
|
|
|
getreq = true;
|
|
|
|
memcpy(&msg->ifr.ifr_hwaddr.sa_data,
|
|
|
|
dev->net_dev.d_mac.ether.ether_addr_octet, 6);
|
|
|
|
break;
|
|
|
|
|
2020-10-12 12:48:18 +02:00
|
|
|
case SIOCGIFADDR:
|
|
|
|
getreq = true;
|
|
|
|
memcpy(&inaddr->sin_addr,
|
|
|
|
&dev->net_dev.d_ipaddr,
|
|
|
|
sizeof(dev->net_dev.d_ipaddr)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFADDR:
|
2019-07-30 12:49:16 +02:00
|
|
|
memcpy(&dev->net_dev.d_ipaddr,
|
|
|
|
&inaddr->sin_addr, sizeof(inaddr->sin_addr)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFDSTADDR:
|
|
|
|
memcpy(&dev->net_dev.d_draddr,
|
|
|
|
&inaddr->sin_addr, sizeof(inaddr->sin_addr)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFNETMASK:
|
|
|
|
memcpy(&dev->net_dev.d_netmask,
|
|
|
|
&inaddr->sin_addr, sizeof(inaddr->sin_addr)
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
2020-11-02 08:49:14 +01:00
|
|
|
case SIOCGIWNWID:
|
|
|
|
case SIOCGIWFREQ:
|
|
|
|
case SIOCGIWSENS:
|
|
|
|
ret = gs2200m_ioctl_iwreq(dev, msg);
|
|
|
|
break;
|
|
|
|
|
2019-07-30 12:49:16 +02:00
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-02 15:08:34 +02:00
|
|
|
if (false == getreq && OK == ret)
|
2019-07-30 12:49:16 +02:00
|
|
|
{
|
|
|
|
memcpy(&in[0], &dev->net_dev.d_ipaddr, sizeof(in[0]));
|
|
|
|
memcpy(&in[1], &dev->net_dev.d_netmask, sizeof(in[1]));
|
|
|
|
memcpy(&in[2], &dev->net_dev.d_draddr, sizeof(in[2]));
|
|
|
|
strncpy(addr[0], inet_ntoa(in[0]), sizeof(addr[0]));
|
|
|
|
strncpy(addr[1], inet_ntoa(in[1]), sizeof(addr[1]));
|
|
|
|
strncpy(addr[2], inet_ntoa(in[2]), sizeof(addr[2]));
|
|
|
|
|
2020-01-02 17:49:34 +01:00
|
|
|
gs2200m_set_addresses(dev, addr[0], addr[1], addr[2]);
|
2019-07-30 12:49:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
wlinfo("+++ end: \n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-05-14 01:10:04 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl_name
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl_name(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR struct gs2200m_name_msg *msg)
|
|
|
|
{
|
|
|
|
enum pkt_type_e r;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* Obtain connection status */
|
|
|
|
|
|
|
|
r = gs2200m_get_cstatus(dev, msg);
|
|
|
|
|
|
|
|
if (r != TYPE_OK)
|
|
|
|
{
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg->local)
|
|
|
|
{
|
|
|
|
/* Copy local address from net_dev */
|
|
|
|
|
|
|
|
memcpy(&msg->addr.sin_addr,
|
|
|
|
&dev->net_dev.d_ipaddr,
|
|
|
|
sizeof(msg->addr.sin_addr)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_ioctl
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
FAR struct inode *inode;
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
DEBUGASSERT(filep);
|
|
|
|
inode = filep->f_inode;
|
|
|
|
|
|
|
|
DEBUGASSERT(inode && inode->i_private);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)inode->i_private;
|
|
|
|
|
|
|
|
/* Lock the device */
|
|
|
|
|
2020-03-31 21:59:25 +02:00
|
|
|
ret = gs2200m_lock(dev);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* Return only if the task was canceled */
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Disable gs2200m irq to poll dready */
|
|
|
|
|
|
|
|
DEBUGASSERT(dev);
|
|
|
|
dev->lower->disable();
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case GS2200M_IOC_CONNECT:
|
|
|
|
{
|
|
|
|
struct gs2200m_connect_msg *msg =
|
|
|
|
(struct gs2200m_connect_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_connect(dev, msg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS2200M_IOC_SEND:
|
|
|
|
{
|
|
|
|
struct gs2200m_send_msg *msg =
|
|
|
|
(struct gs2200m_send_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_send(dev, msg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS2200M_IOC_RECV:
|
|
|
|
{
|
|
|
|
struct gs2200m_recv_msg *msg =
|
|
|
|
(struct gs2200m_recv_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_recv(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GS2200M_IOC_CLOSE:
|
|
|
|
{
|
|
|
|
struct gs2200m_close_msg *msg =
|
|
|
|
(struct gs2200m_close_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_close(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GS2200M_IOC_BIND:
|
|
|
|
{
|
|
|
|
struct gs2200m_bind_msg *msg =
|
|
|
|
(struct gs2200m_bind_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_bind(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GS2200M_IOC_ACCEPT:
|
|
|
|
{
|
|
|
|
struct gs2200m_accept_msg *msg =
|
|
|
|
(struct gs2200m_accept_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_accept(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case GS2200M_IOC_ASSOC:
|
|
|
|
{
|
|
|
|
struct gs2200m_assoc_msg *msg =
|
|
|
|
(struct gs2200m_assoc_msg *)arg;
|
|
|
|
|
|
|
|
if (0 == msg->mode)
|
|
|
|
{
|
|
|
|
ret = gs2200m_ioctl_assoc_sta(dev, msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = gs2200m_ioctl_assoc_ap(dev, msg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-07-30 12:49:16 +02:00
|
|
|
case GS2200M_IOC_IFREQ:
|
|
|
|
{
|
|
|
|
struct gs2200m_ifreq_msg *msg =
|
|
|
|
(struct gs2200m_ifreq_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_ifreq(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-05-14 01:10:04 +02:00
|
|
|
case GS2200M_IOC_NAME:
|
|
|
|
{
|
|
|
|
struct gs2200m_name_msg *msg =
|
|
|
|
(struct gs2200m_name_msg *)arg;
|
|
|
|
|
|
|
|
ret = gs2200m_ioctl_name(dev, msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
default:
|
2019-09-14 03:01:05 +02:00
|
|
|
DEBUGPANIC();
|
|
|
|
break;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable gs2200m irq again */
|
|
|
|
|
|
|
|
dev->lower->enable();
|
|
|
|
|
|
|
|
/* Unlock the device */
|
|
|
|
|
|
|
|
gs2200m_unlock(dev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_poll
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|
|
|
bool setup)
|
|
|
|
{
|
|
|
|
FAR struct inode *inode;
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
wlinfo("== setup:%d\n", (int)setup);
|
|
|
|
DEBUGASSERT(filep && fds);
|
|
|
|
inode = filep->f_inode;
|
|
|
|
|
|
|
|
DEBUGASSERT(inode && inode->i_private);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)inode->i_private;
|
|
|
|
|
2020-03-31 21:59:25 +02:00
|
|
|
ret = gs2200m_lock(dev);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
/* Return if the task was canceled */
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Are we setting up the poll? Or tearing it down? */
|
|
|
|
|
|
|
|
if (setup)
|
|
|
|
{
|
|
|
|
/* Ignore waits that do not include POLLIN */
|
|
|
|
|
|
|
|
if ((fds->events & POLLIN) == 0)
|
|
|
|
{
|
|
|
|
ret = -EDEADLK;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NOTE: only one thread can poll the device at any time */
|
|
|
|
|
|
|
|
if (dev->pfd)
|
|
|
|
{
|
|
|
|
ret = -EBUSY;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->pfd = fds;
|
|
|
|
|
|
|
|
uint8_t n = _notif_q_count(dev);
|
|
|
|
|
|
|
|
if (0 < n)
|
|
|
|
{
|
|
|
|
dev->pfd->revents |= POLLIN;
|
|
|
|
nxsem_post(dev->pfd->sem);
|
|
|
|
wlinfo("==== _notif_q_count=%d \n", n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dev->pfd = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
|
|
|
gs2200m_unlock(dev);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_irq_worker
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void gs2200m_irq_worker(FAR void *arg)
|
|
|
|
{
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
|
|
|
enum pkt_type_e t = TYPE_ERROR;
|
|
|
|
struct pkt_dat_s *pkt_dat;
|
|
|
|
bool ignored = false;
|
2020-06-01 06:52:59 +02:00
|
|
|
bool over;
|
2019-06-18 14:44:03 +02:00
|
|
|
uint8_t c;
|
|
|
|
char s_cid;
|
|
|
|
char c_cid;
|
|
|
|
int n;
|
|
|
|
int ec;
|
2020-03-31 21:59:25 +02:00
|
|
|
int ret;
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
DEBUGASSERT(arg != NULL);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)arg;
|
|
|
|
|
2020-03-31 21:59:25 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
ret = gs2200m_lock(dev);
|
|
|
|
|
|
|
|
/* The only failure would be if the worker thread were canceled. That
|
|
|
|
* is very unlikely, however.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
|
|
|
}
|
|
|
|
while (ret < 0);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
2020-05-05 04:24:09 +02:00
|
|
|
repeat:
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
n = dev->lower->dready(&ec);
|
|
|
|
wlinfo("== start (dready=%d, ec=%d) \n", n, ec);
|
|
|
|
|
|
|
|
/* Allocate a new pkt_dat and initialize it */
|
|
|
|
|
|
|
|
pkt_dat = (FAR struct pkt_dat_s *)kmm_malloc(sizeof(struct pkt_dat_s));
|
|
|
|
ASSERT(NULL != pkt_dat);
|
|
|
|
|
|
|
|
memset(pkt_dat, 0, sizeof(struct pkt_dat_s));
|
|
|
|
pkt_dat->cid = 'z';
|
|
|
|
|
|
|
|
/* Receive a packet */
|
|
|
|
|
|
|
|
t = gs2200m_recv_pkt(dev, pkt_dat);
|
|
|
|
|
2020-10-30 07:19:50 +01:00
|
|
|
if (true == dev->disassociate_flag)
|
|
|
|
{
|
|
|
|
/* Disassociate recovery */
|
|
|
|
|
|
|
|
wlwarn("=== receive DISASSOCIATE\n");
|
|
|
|
dev->valid_cid_bits = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Discard incoming packets until timeout happens */
|
|
|
|
|
|
|
|
while (gs2200m_recv_pkt(dev, NULL) != TYPE_TIMEOUT)
|
|
|
|
{
|
|
|
|
nxsig_usleep(100 * 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (gs2200m_ioctl_assoc_sta(dev, &dev->reconnect_msg) != OK);
|
|
|
|
|
|
|
|
wlwarn("=== recover DISASSOCIATE\n");
|
|
|
|
dev->disassociate_flag = false;
|
|
|
|
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
if (TYPE_ERROR == t || 'z' == pkt_dat->cid)
|
|
|
|
{
|
|
|
|
/* An error event? */
|
|
|
|
|
|
|
|
wlinfo("=== ignore (type=%d msg[0]=%s|) \n",
|
|
|
|
pkt_dat->type, pkt_dat->msg[0]);
|
|
|
|
|
|
|
|
ignored = true;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the cid has been invalid */
|
|
|
|
|
|
|
|
if (!_cid_is_set(&dev->valid_cid_bits, pkt_dat->cid))
|
|
|
|
{
|
|
|
|
wlinfo("=== already closed (type=%d msg[0]=%s|) \n",
|
|
|
|
pkt_dat->type, pkt_dat->msg[0]);
|
|
|
|
|
|
|
|
ignored = true;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = _cid_to_uint8(pkt_dat->cid);
|
|
|
|
|
|
|
|
/* Add the pkt_dat to the pkt_q */
|
|
|
|
|
|
|
|
dq_addlast((FAR dq_entry_t *)pkt_dat, &dev->pkt_q[c]);
|
|
|
|
dev->pkt_q_cnt[c]++;
|
|
|
|
|
|
|
|
wlinfo("=== added to qkt_q[%d] t=%d \n", c, t);
|
|
|
|
|
2019-07-03 02:11:24 +02:00
|
|
|
/* When a DISCONNECT packet received, disable the cid */
|
|
|
|
|
|
|
|
if (TYPE_DISCONNECT == t)
|
|
|
|
{
|
|
|
|
wlinfo("=== received DISCONNECT for cid=%c \n", pkt_dat->cid);
|
|
|
|
_enable_cid(&dev->valid_cid_bits, pkt_dat->cid, false);
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/* If accept() is not in progress for the cid, add the packet to notif_q
|
|
|
|
*
|
|
|
|
* NOTE: we need this condition to process the packet in correct order,
|
|
|
|
* when accept() sequcence is in progress.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!_cid_is_set(&dev->aip_cid_bits, pkt_dat->cid))
|
|
|
|
{
|
|
|
|
_notif_q_push(dev, pkt_dat->cid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the packet is CONNECT event from client */
|
|
|
|
|
|
|
|
if (TYPE_CONNECT == t)
|
|
|
|
{
|
|
|
|
n = sscanf(pkt_dat->msg[0], "CONNECT %c %c", &s_cid, &c_cid);
|
|
|
|
ASSERT(2 == n);
|
|
|
|
|
|
|
|
wlinfo("==== CONNECT requested (%c:%c) pfd=%p \n",
|
|
|
|
s_cid, c_cid, dev->pfd);
|
|
|
|
|
|
|
|
/* Check pkt_q for the new client is empty */
|
|
|
|
|
|
|
|
_check_pkt_q_empty(dev, c_cid);
|
|
|
|
|
|
|
|
/* Enable the cid */
|
|
|
|
|
|
|
|
_enable_cid(&dev->valid_cid_bits, c_cid, true);
|
|
|
|
|
|
|
|
/* Enable accept in progress */
|
|
|
|
|
|
|
|
_enable_cid(&dev->aip_cid_bits, c_cid, true);
|
|
|
|
}
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
/* Do packet flow control */
|
|
|
|
|
|
|
|
over = _control_pkt_q(dev);
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
errout:
|
|
|
|
|
2020-05-05 04:24:09 +02:00
|
|
|
if (ignored)
|
|
|
|
{
|
2020-06-01 06:52:59 +02:00
|
|
|
_release_pkt_dat(dev, pkt_dat);
|
2020-05-05 04:24:09 +02:00
|
|
|
kmm_free(pkt_dat);
|
|
|
|
ignored = false;
|
|
|
|
}
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
n = dev->lower->dready(&ec);
|
|
|
|
|
|
|
|
wlinfo("== end: cid=%c (dready=%d, ec=%d) type=%d \n",
|
|
|
|
pkt_dat->cid, n, ec, t);
|
|
|
|
|
2020-06-01 06:52:59 +02:00
|
|
|
if (1 == n && !over)
|
2019-06-18 14:44:03 +02:00
|
|
|
{
|
2020-05-05 04:24:09 +02:00
|
|
|
goto repeat;
|
2019-06-18 14:44:03 +02:00
|
|
|
}
|
|
|
|
|
2020-05-05 04:24:09 +02:00
|
|
|
/* NOTE: Enable gs2200m irq which was disabled in gs2200m_irq() */
|
|
|
|
|
|
|
|
dev->lower->enable();
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
gs2200m_unlock(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_interrupt
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_irq(int irq, FAR void *context, FAR void *arg)
|
|
|
|
{
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
|
|
|
|
|
|
|
DEBUGASSERT(arg != NULL);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)arg;
|
|
|
|
|
|
|
|
wlinfo(">>>> \n");
|
|
|
|
|
|
|
|
if (!work_available(&dev->irq_work))
|
|
|
|
{
|
|
|
|
wlwarn("*** warning: there is still pending work **** \n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-25 09:07:12 +02:00
|
|
|
/* NOTE: Disable gs2200m irq during processing */
|
|
|
|
|
|
|
|
dev->lower->disable();
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
return work_queue(GS2200MWORK, &dev->irq_work, gs2200m_irq_worker,
|
|
|
|
(FAR void *)dev, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_start
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_start(FAR struct gs2200m_dev_s *dev)
|
|
|
|
{
|
|
|
|
enum pkt_type_e t;
|
|
|
|
|
|
|
|
/* NOTE: irq is still disabled here */
|
|
|
|
|
|
|
|
/* Check boot msg */
|
|
|
|
|
|
|
|
wlinfo("*** wait for boot msg \n");
|
|
|
|
|
|
|
|
while (dev->lower->dready(NULL))
|
|
|
|
{
|
2020-01-02 17:49:34 +01:00
|
|
|
gs2200m_recv_pkt(dev, NULL);
|
2019-06-18 14:44:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Need to check Regulatory Domain stored in the internal flash.
|
|
|
|
* If we need to change the damin, set here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Disable echo */
|
|
|
|
|
|
|
|
t = gs2200m_enable_echo(dev, 0);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
2020-02-05 22:32:33 +01:00
|
|
|
#if CONFIG_WL_GS2200M_LOGLEVEL > 0
|
|
|
|
/* Set log level */
|
2020-03-31 21:59:25 +02:00
|
|
|
|
2020-02-05 22:32:33 +01:00
|
|
|
t = gs2200m_set_loglevel(dev, CONFIG_WL_GS2200M_LOGLEVEL);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_WL_GS2200M_CHECK_VERSION
|
2019-06-18 14:44:03 +02:00
|
|
|
/* Version */
|
|
|
|
|
|
|
|
t = gs2200m_get_version(dev);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Activate RX */
|
|
|
|
|
|
|
|
t = gs2200m_activate_wrx(dev, 1);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Set Bulk Data mode */
|
|
|
|
|
|
|
|
t = gs2200m_enable_bulk(dev, 1);
|
|
|
|
ASSERT(TYPE_OK == t);
|
|
|
|
|
|
|
|
/* Interface is up */
|
|
|
|
|
|
|
|
dev->net_dev.d_flags |= IFF_UP;
|
|
|
|
|
|
|
|
/* NOTE: Enable interrupt here */
|
|
|
|
|
|
|
|
dev->lower->enable();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_initialize
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int gs2200m_initialize(FAR struct gs2200m_dev_s *dev,
|
|
|
|
FAR const struct gs2200m_lower_s *lower)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* For each cid (0-f) */
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
/* Initialize packet queue */
|
|
|
|
|
|
|
|
dq_init(&dev->pkt_q[i]);
|
|
|
|
}
|
|
|
|
|
2019-08-04 22:50:28 +02:00
|
|
|
/* Initialize SPI driver. */
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
ret = gs2200m_spi_init(dev);
|
|
|
|
|
2019-10-15 23:03:33 +02:00
|
|
|
/* Reset and Unreset GS2200M */
|
|
|
|
|
|
|
|
lower->reset(true);
|
|
|
|
up_mdelay(1);
|
|
|
|
lower->reset(false);
|
|
|
|
up_mdelay(180);
|
|
|
|
|
2019-06-18 14:44:03 +02:00
|
|
|
/* Attach interrupt handler */
|
|
|
|
|
|
|
|
lower->attach(gs2200m_irq, dev);
|
2020-06-01 06:52:59 +02:00
|
|
|
dev->int_enabled = true;
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
/* Start gs2200m by sending commands */
|
|
|
|
|
|
|
|
gs2200m_start(dev);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: gs2200m_register
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
FAR void *gs2200m_register(FAR const char *devpath,
|
|
|
|
FAR struct spi_dev_s *spi,
|
|
|
|
FAR const struct gs2200m_lower_s *lower)
|
|
|
|
{
|
|
|
|
FAR struct gs2200m_dev_s *dev;
|
|
|
|
int ret;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = sizeof(struct gs2200m_dev_s);
|
|
|
|
dev = (FAR struct gs2200m_dev_s *)kmm_malloc(size);
|
|
|
|
|
|
|
|
if (!dev)
|
|
|
|
{
|
|
|
|
wlerr("Failed to allocate instance.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(dev, 0, size);
|
|
|
|
|
|
|
|
dev->spi = spi;
|
|
|
|
dev->path = strdup(devpath);
|
|
|
|
dev->lower = lower;
|
|
|
|
|
|
|
|
nxsem_init(&dev->dev_sem, 0, 1);
|
|
|
|
|
|
|
|
dev->pfd = NULL;
|
|
|
|
|
|
|
|
ret = gs2200m_initialize(dev, lower);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
wlerr("Failed to initialize driver: %d\n", ret);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = register_driver(devpath, &g_gs2200m_fops, 0666, dev);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
wlerr("Failed to register driver: %d\n", ret);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2020-09-17 07:56:08 +02:00
|
|
|
ret = netdev_register(&dev->net_dev, NET_LL_IEEE80211);
|
2019-06-18 14:44:03 +02:00
|
|
|
|
|
|
|
return (FAR void *)dev;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
kmm_free(dev);
|
|
|
|
return NULL;
|
|
|
|
}
|