risc-v/bl602: Support AP and STA as independent network interface device

Signed-off-by: Virus.V <virusv@live.com>
This commit is contained in:
Virus.V 2021-06-28 09:45:46 +08:00 committed by Xiang Xiao
parent abc2767b0d
commit cd50650583
6 changed files with 242 additions and 86 deletions

View File

@ -92,11 +92,14 @@ config BL602_WIRELESS_CONTRY_CODE
depends on BL602_WIRELESS
default "CN"
config BL602_NET_MULTI_INTERFACE
bool "STA and AP as independent interfaces"
depends on BL602_WIRELESS
default n
config BL602_BLE_CONTROLLER
bool "ble controller support"
default n
depends on PSEUDOTERM
depends on PSEUDOTERM_SUSV1
depends on !DISABLE_MQUEUE
depends on SCHED_HPWORK
depends on BL602_WIRELESS

View File

@ -83,10 +83,9 @@ CHIP_CSRCS += bl602_glb.c bl602_gpio.c bl602_hbn.c bl602_systemreset.c
ifeq ($(CONFIG_BL602_WIRELESS),y)
WIRELESS_DRV_UNPACK = bl_blob
WIRELESS_DRV_VERSION = v1.6.19
WIRELESS_DRV_ID = dev_irq
WIRELESS_DRV_ZIP = $(WIRELESS_DRV_ID).zip
WIRELESS_DRV_URL = https://github.com/bouffalolab/bl_blob/archive
WIRELESS_DRV_VERSION = 1.6.20
WIRELESS_DRV_ZIP = v$(WIRELESS_DRV_VERSION).zip
WIRELESS_DRV_URL = https://github.com/bouffalolab/bl_blob/archive/refs/heads
$(WIRELESS_DRV_ZIP):
$(Q) echo "Downloading: BL602 Wireless Drivers"
@ -96,7 +95,7 @@ chip/$(WIRELESS_DRV_UNPACK): $(WIRELESS_DRV_ZIP)
$(Q) echo "Unpacking: BL602 Wireless Drivers"
$(Q) mkdir -p chip/$(WIRELESS_DRV_UNPACK)
$(Q) unzip -oqq chip/$(WIRELESS_DRV_ZIP) -d chip/
$(Q) mv chip/$(WIRELESS_DRV_UNPACK)-$(WIRELESS_DRV_ID)/* chip/$(WIRELESS_DRV_UNPACK)
$(Q) mv chip/$(WIRELESS_DRV_UNPACK)-$(WIRELESS_DRV_VERSION)/* chip/$(WIRELESS_DRV_UNPACK)
$(Q) touch chip/$(WIRELESS_DRV_UNPACK)
context:: chip/$(WIRELESS_DRV_UNPACK)
@ -105,10 +104,10 @@ clean_context::
$(call DELFILE, chip/$(WIRELESS_DRV_ZIP))
$(call DELDIR, chip/$(WIRELESS_DRV_UNPACK))
INCLUDES += $(shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)$(WIRELESS_DRV_UNPACK)$(DELIM)includes$(DELIM)$(WIRELESS_DRV_VERSION)$(DELIM)BL602$(DELIM)nuttx)
INCLUDES += $(shell $(INCDIR) "$(CC)" $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)$(WIRELESS_DRV_UNPACK)$(DELIM)includes$(DELIM)BL602$(DELIM)nuttx)
CHIP_CSRCS += bl602_netdev.c
EXTRA_LIBPATHS += -L $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)$(WIRELESS_DRV_UNPACK)$(DELIM)libs$(DELIM)$(WIRELESS_DRV_VERSION)$(DELIM)BL602$(DELIM)nuttx
EXTRA_LIBPATHS += -L $(ARCH_SRCDIR)$(DELIM)chip$(DELIM)$(WIRELESS_DRV_UNPACK)$(DELIM)libs$(DELIM)BL602$(DELIM)nuttx
EXTRA_LIBS += -lbl602_wifi -lblecontroller
# Due to some Wi-Fi related libraries, the option is need to avoid linking too much

View File

@ -90,12 +90,14 @@
#define ETHWORK HPWORK
/* CONFIG_BL602_NET_NINTERFACES determines the number of physical interfaces
/* BL602_NET_NINTERFACES determines the number of physical interfaces
* that will be supported.
*/
#ifndef CONFIG_BL602_NET_NINTERFACES
#define CONFIG_BL602_NET_NINTERFACES 1
#ifndef CONFIG_BL602_NET_MULTI_INTERFACE
#define BL602_NET_NINTERFACES 1
#else
#define BL602_NET_NINTERFACES 2
#endif
/* TX poll delay = 1 seconds.
@ -150,7 +152,6 @@ struct bl602_net_driver_s
*/
unsigned int current_mode : 2; /* current mode */
unsigned int scan_result_len : 6; /* max 64 */
unsigned int push_cnt : 4; /* max 16 */
unsigned int prev_connectd : 1; /* mark of prev connection status */
@ -189,6 +190,7 @@ typedef uint8_t (*tx_buff_t)[BL602_NET_TXBUFF_SIZE];
struct rx_pending_item_s
{
struct list_node node;
struct bl602_net_driver_s *priv; /* Which interface should to deliver */
uint8_t * data;
int len;
};
@ -199,7 +201,7 @@ struct rx_pending_item_s
/* Driver state structure */
struct bl602_net_driver_s g_bl602_net[CONFIG_BL602_NET_NINTERFACES];
struct bl602_net_driver_s g_bl602_net[BL602_NET_NINTERFACES];
static struct tx_buf_ind_s g_tx_buf_indicator =
BITSET_T_INITIALIZER((1 << BL602_NET_TXBUFF_NUM) - 1);
@ -214,11 +216,21 @@ static sem_t g_wifi_connect_sem;
static struct list_node g_rx_pending;
/* Firmware default config */
static wifi_conf_t g_conf =
{
.country_code = CONFIG_BL602_WIRELESS_CONTRY_CODE,
};
/* Global state */
static struct
{
uint32_t scan_result_status : 2; /* WiFi scan result status */
uint32_t scan_result_len : 6;
} g_state;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@ -645,7 +657,7 @@ static void bl602_net_receive(FAR struct bl602_net_driver_s *priv)
}
}
static int bl602_launch_pending_rx(FAR struct bl602_net_driver_s *priv)
static int bl602_launch_pending_rx(void)
{
struct rx_pending_item_s *item;
irqstate_t irqstate;
@ -689,14 +701,15 @@ static int bl602_launch_pending_rx(FAR struct bl602_net_driver_s *priv)
/* now we have avaliable tx buffer and pending rx data, launch it */
DEBUGASSERT(priv->net_dev.d_buf == NULL);
DEBUGASSERT(item->priv != NULL);
DEBUGASSERT(item->priv->net_dev.d_buf == NULL);
DEBUGASSERT(item->data != NULL && item->len > 0);
priv->net_dev.d_buf = item->data;
priv->net_dev.d_len = item->len;
bl602_net_receive(priv);
item->priv->net_dev.d_buf = item->data;
item->priv->net_dev.d_len = item->len;
bl602_net_receive(item->priv);
DEBUGASSERT(priv->net_dev.d_buf == NULL);
DEBUGASSERT(item->priv->net_dev.d_buf == NULL);
net_unlock();
kmm_free(item);
@ -713,24 +726,29 @@ static int bl602_launch_pending_rx(FAR struct bl602_net_driver_s *priv)
* event: notify type, tx done or received new data
* data: The data of the event, may be NULL
* len: data length
* opaque: customer data
*
* Returned Value:
* OK on success; a negated errno on failure
*
****************************************************************************/
int bl602_net_notify(uint32_t event, uint8_t *data, int len)
int bl602_net_notify(uint32_t event, uint8_t *data, int len, void *opaque)
{
/* TODO distinguish which driver */
DEBUGASSERT(opaque != NULL);
FAR struct bl602_net_driver_s *priv = &g_bl602_net[0];
int ret;
FAR struct bl602_net_driver_s *priv =
(FAR struct bl602_net_driver_s *)opaque;
DEBUGASSERT(priv == &g_bl602_net[0] || priv == &g_bl602_net[1]);
int ret;
if (event & BL602_NET_EVT_TX_DONE)
{
/* if we have tx buffer, we put pending input packet first */
ret = bl602_launch_pending_rx(priv);
ret = bl602_launch_pending_rx();
if (ret != OK)
{
/* There is no tx buffer, we needn't to poll.. */
@ -782,6 +800,7 @@ int bl602_net_notify(uint32_t event, uint8_t *data, int len)
item->data = data;
item->len = len;
item->priv = priv;
wlinfo("pending rx data :%p %d\n", item->data, item->len);
@ -959,6 +978,25 @@ static int bl602_net_ifup(FAR struct net_driver_s *dev)
return OK;
}
static int bl602_net_soft_reset(void)
{
int idx;
wifi_mgmr_sta_disconnect();
nxsig_sleep(1);
wifi_mgmr_api_ap_stop();
nxsig_sleep(1);
wifi_mgmr_api_idle();
wifi_mgmr_reset();
for (idx = 0; idx < BL602_NET_NINTERFACES; idx++)
{
g_bl602_net[idx].current_mode = IW_MODE_AUTO;
}
return 0;
}
/****************************************************************************
* Name: bl602_net_ifdown
*
@ -993,6 +1031,12 @@ static int bl602_net_ifdown(FAR struct net_driver_s *dev)
wd_cancel(&priv->txpoll);
leave_critical_section(flags);
if (priv == &g_bl602_net[0])
{
bl602_net_soft_reset();
}
net_unlock();
return OK;
}
@ -1245,7 +1289,7 @@ static void scan_complete_indicate(void *data, void *param)
para = (struct scan_parse_param_s *)data;
DEBUGASSERT(para != NULL);
DEBUGASSERT(para->priv != NULL);
para->priv->scan_result_len = 0;
g_state.scan_result_len = 0;
for (i = 0;
i < sizeof(WIFI_MGMR.scan_items) / sizeof(WIFI_MGMR.scan_items[0]);
@ -1260,14 +1304,19 @@ static void scan_complete_indicate(void *data, void *param)
}
else if (scan->is_used)
{
if (para->flags & IW_SCAN_THIS_ESSID)
if (para->priv->channel != 0 &&
scan->channel != para->priv->channel)
{
scan->is_used = 0;
}
else if (para->flags & IW_SCAN_THIS_ESSID)
{
if (strncmp(scan->ssid,
(char *)para->scan_req.essid,
sizeof(scan->ssid)) == 0)
{
scan->is_used = 1;
para->priv->scan_result_len++;
g_state.scan_result_len++;
}
else
{
@ -1276,12 +1325,11 @@ static void scan_complete_indicate(void *data, void *param)
}
else
{
para->priv->scan_result_len++;
g_state.scan_result_len++;
}
}
}
sem_post(&g_wifi_scan_sem);
kmm_free(data);
return;
}
@ -1453,7 +1501,7 @@ static int bl602_ioctl_wifi_start(FAR struct bl602_net_driver_s *priv,
0,
priv->channel) == -1)
{
return -ENOBUFS;
return -EPIPE;
}
sem_wait(&g_wifi_connect_sem);
@ -1463,17 +1511,21 @@ static int bl602_ioctl_wifi_start(FAR struct bl602_net_driver_s *priv,
wifi_mgmr_state_get_internal(&state);
if (state != WIFI_STATE_CONNECTED_IP_GOT)
{
return -EINVAL;
return -EPIPE;
}
}
else if (priv->current_mode == IW_MODE_MASTER)
{
int channel;
wifi_mgmr_channel_get(&channel);
syslog(LOG_INFO, "current channel:%d\n", channel);
if (wifi_mgmr_api_ap_start(mgmr->wifi_mgmr_stat_info.ssid,
mgmr->wifi_mgmr_stat_info.psk,
1,
channel ? channel : 1,
0) < 0)
{
return -ENOBUFS;
return -EPIPE;
}
}
else
@ -1568,7 +1620,16 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
if (sem_trywait(&g_wifi_scan_sem) == 0)
{
wifi_mgmr_scan(para, scan_complete_indicate);
if (priv->channel != 0)
{
wifi_mgmr_scan_fixed_channels(para, scan_complete_indicate,
&priv->channel, 1);
}
else
{
wifi_mgmr_scan(para, scan_complete_indicate);
}
return OK;
}
else
@ -1587,14 +1648,21 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
sem_wait(&g_wifi_scan_sem);
if (priv->scan_result_len == 0)
if (g_state.scan_result_status != 0)
{
wlwarn("scan failed\n");
sem_post(&g_wifi_scan_sem);
return -EIO;
}
if (g_state.scan_result_len == 0)
{
req->u.data.length = 0;
sem_post(&g_wifi_scan_sem);
return OK;
}
ret = format_scan_result_to_wapi(req, priv->scan_result_len);
ret = format_scan_result_to_wapi(req, g_state.scan_result_len);
sem_post(&g_wifi_scan_sem);
return ret;
}
@ -1662,6 +1730,13 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
do
{
struct iwreq *req = (struct iwreq *)arg;
#ifdef CONFIG_BL602_NET_MULTI_INTERFACE
int interface_idx = priv - g_bl602_net;
DEBUGASSERT(interface_idx >= 0 &&
interface_idx < BL602_NET_NINTERFACES);
#endif
if (req->u.mode == priv->current_mode)
{
wlinfo("mode not change\n");
@ -1672,7 +1747,15 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
{
/* station */
priv->wlan = wifi_mgmr_sta_enable();
#ifdef CONFIG_BL602_NET_MULTI_INTERFACE
if (interface_idx != 0)
{
wlwarn("The interface does not support this mode.\n");
return -ENOSYS;
}
#endif
priv->wlan = wifi_mgmr_sta_enable((void *)priv);
memcpy(priv->wlan->mac,
priv->net_dev.d_mac.ether.ether_addr_octet,
@ -1685,7 +1768,15 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
{
/* AP Mode */
priv->wlan = wifi_mgmr_ap_enable();
#ifdef CONFIG_BL602_NET_MULTI_INTERFACE
if (interface_idx != 1)
{
wlwarn("The interface does not support this mode.\n");
return -ENOSYS;
}
#endif
priv->wlan = wifi_mgmr_ap_enable((void *)priv);
memcpy(priv->wlan->mac,
priv->net_dev.d_mac.ether.ether_addr_octet,
6);
@ -1862,6 +1953,22 @@ bl602_net_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg)
while (0);
break;
case SIOCSIWCOUNTRY: /* Set country code */
do
{
struct iwreq *req = (struct iwreq *)arg;
ret = wifi_mgmr_set_country_code(req->u.data.pointer);
if (ret != 0)
{
return -EINVAL;
}
return OK;
}
while (0);
break;
default:
wlerr("ERROR: Unrecognized IOCTL command: %d\n", cmd);
return -ENOTTY; /* Special return value for this case */
@ -1967,9 +2074,6 @@ void bl602_netdev_free_txbuf(uint8_t *buf)
void bl602_net_event(int evt, int val)
{
/* TODO distinguish which driver */
FAR struct bl602_net_driver_s *priv = &g_bl602_net[0];
net_lock();
switch (evt)
@ -1977,8 +2081,10 @@ void bl602_net_event(int evt, int val)
case CODE_WIFI_ON_CONNECTED:
do
{
struct bl602_net_driver_s *priv = &g_bl602_net[0];
priv->prev_connectd = 1;
wifi_mgmr_sta_autoconnect_disable();
sem_post(&g_wifi_connect_sem);
}
while (0);
@ -1987,11 +2093,13 @@ void bl602_net_event(int evt, int val)
case CODE_WIFI_CMD_RECONNECT:
do
{
struct bl602_net_driver_s *priv = &g_bl602_net[0];
static int retry_cnt = 0;
wlinfo("retry connect : %d\n", retry_cnt);
if (!priv->prev_connectd)
{
if (retry_cnt++ > 3)
if (retry_cnt++ > 1)
{
retry_cnt = 0;
wifi_mgmr_sta_autoconnect_disable();
@ -2004,6 +2112,14 @@ void bl602_net_event(int evt, int val)
while (0);
break;
case CODE_WIFI_ON_SCAN_DONE:
do
{
g_state.scan_result_status = val;
sem_post(&g_wifi_scan_sem);
}
while (0);
default:
wlwarn("unhandled msg:%d\n", evt);
break;
@ -2019,8 +2135,7 @@ void bl602_net_event(int evt, int val)
* Initialize the Wireless controller and driver
*
* Input Parameters:
* intf - In the case where there are multiple EMACs, this value
* identifies which EMAC is to be initialized.
* None
*
* Returned Value:
* OK on success; Negated errno on failure.
@ -2030,39 +2145,13 @@ void bl602_net_event(int evt, int val)
*
****************************************************************************/
int bl602_net_initialize(int intf)
int bl602_net_initialize(void)
{
FAR struct bl602_net_driver_s *priv;
int tmp;
int idx;
uint8_t mac[6];
/* Get the interface structure associated with this interface number. */
DEBUGASSERT(intf < CONFIG_BL602_NET_NINTERFACES);
priv = &g_bl602_net[intf];
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct bl602_net_driver_s));
priv->net_dev.d_ifup =
bl602_net_ifup; /* I/F up (new IP address) callback */
priv->net_dev.d_ifdown = bl602_net_ifdown; /* I/F down callback */
priv->net_dev.d_txavail = bl602_net_txavail; /* New TX data callback */
#ifdef CONFIG_NET_MCASTGROUP
priv->net_dev.d_addmac = bl602_net_addmac; /* Add multicast MAC address */
priv->net_dev.d_rmmac = bl602_net_rmmac; /* Remove multicast MAC address */
#endif
#ifdef CONFIG_NETDEV_IOCTL
priv->net_dev.d_ioctl = bl602_net_ioctl; /* Handle network IOCTL commands */
#endif
priv->net_dev.d_private = priv; /* Used to recover private state from dev */
priv->net_dev.d_pktsize =
BL602_NET_TXBUFF_SIZE - PRESERVE_80211_HEADER_LEN;
priv->current_mode = IW_MODE_AUTO;
priv->scan_result_len = 0;
/* Initialize scan semaphore */
tmp = sem_init(&g_wifi_scan_sem, 0, 1);
@ -2097,17 +2186,66 @@ int bl602_net_initialize(int intf)
mac[4],
mac[5]);
memcpy(priv->net_dev.d_mac.ether.ether_addr_octet, mac, 6);
bl_wifi_ap_mac_addr_set(priv->net_dev.d_mac.ether.ether_addr_octet);
bl_wifi_sta_mac_addr_set(priv->net_dev.d_mac.ether.ether_addr_octet);
/* Register the device with the OS so that socket IOCTLs can be performed */
tmp = netdev_register(&priv->net_dev, NET_LL_IEEE80211);
if (tmp < 0)
for (idx = 0; idx < BL602_NET_NINTERFACES; idx++)
{
sem_destroy(&g_wifi_scan_sem);
return tmp;
/* Get the interface structure associated with this interface number. */
priv = &g_bl602_net[idx];
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct bl602_net_driver_s));
priv->net_dev.d_ifup =
bl602_net_ifup; /* I/F up (new IP address) callback */
priv->net_dev.d_ifdown = bl602_net_ifdown; /* I/F down callback */
priv->net_dev.d_txavail = bl602_net_txavail; /* New TX data callback */
#ifdef CONFIG_NET_MCASTGROUP
priv->net_dev.d_addmac = bl602_net_addmac; /* Add multicast MAC address */
priv->net_dev.d_rmmac = bl602_net_rmmac; /* Remove multicast MAC address */
#endif
#ifdef CONFIG_NETDEV_IOCTL
priv->net_dev.d_ioctl = bl602_net_ioctl; /* Handle network IOCTL commands */
#endif
priv->net_dev.d_private = priv; /* Used to recover private state from dev */
priv->net_dev.d_pktsize =
BL602_NET_TXBUFF_SIZE - PRESERVE_80211_HEADER_LEN;
#ifdef CONFIG_BL602_NET_MULTI_INTERFACE
/* Set AP's MAC address equals STA's MAC */
memcpy(priv->net_dev.d_mac.ether.ether_addr_octet, mac, 6);
if (idx == 0)
{
bl_wifi_sta_mac_addr_set(
priv->net_dev.d_mac.ether.ether_addr_octet);
}
else
{
bl_wifi_ap_mac_addr_set(
priv->net_dev.d_mac.ether.ether_addr_octet);
}
#else
DEBUGASSERT(idx == 0);
memcpy(priv->net_dev.d_mac.ether.ether_addr_octet, mac, 6);
bl_wifi_sta_mac_addr_set(priv->net_dev.d_mac.ether.ether_addr_octet);
bl_wifi_ap_mac_addr_set(priv->net_dev.d_mac.ether.ether_addr_octet);
#endif
priv->current_mode = IW_MODE_AUTO;
/* Register the device with the OS so that socket IOCTLs can be
* performed
*/
tmp = netdev_register(&priv->net_dev, NET_LL_IEEE80211);
if (tmp < 0)
{
sem_destroy(&g_wifi_scan_sem);
return tmp;
}
}
return OK;

View File

@ -100,13 +100,14 @@ void bl602_netdev_free_txbuf(uint8_t *buf);
* event: notify type, tx done or received new data
* data: The data of the event, may be NULL
* len: data length
* opaque: customer data
*
* Returned Value:
* OK on success; a negated errno on failure
*
****************************************************************************/
int bl602_net_notify(uint32_t event, uint8_t *data, int len);
int bl602_net_notify(uint32_t event, uint8_t *data, int len, void *opaque);
/****************************************************************************
* Name: bl602_net_event

View File

@ -3,6 +3,10 @@ OUTPUT_ARCH( "riscv" )
ENTRY( bl602_start )
__EM_SIZE = DEFINED(ble_controller_init) ? 8K : 0K;
__RFTLV_SIZE_OFFSET = 1K;
__RFTLV_SIZE_HOLE = 2K;
__RFTLV_HEAD1_H = (0x46524C42); /* BLRF */
__RFTLV_HEAD1_L = (0x41524150); /* PAPA */
MEMORY
{
@ -23,6 +27,17 @@ SECTIONS
KEEP (*(SORT_NONE(.init)))
} > flash
/* value for rftlv */
.rftlv.tool :
{
. = ORIGIN(flash) + __RFTLV_SIZE_OFFSET;
PROVIDE( _ld_symbol_rftlv_address = . );
LONG(__RFTLV_HEAD1_H);
LONG(__RFTLV_HEAD1_L);
. = ORIGIN(flash) + __RFTLV_SIZE_OFFSET + __RFTLV_SIZE_HOLE;
} > flash
.text :
{
PROVIDE(_stext = .);

View File

@ -94,7 +94,7 @@ static struct work_s g_ble_hci_rx_work;
****************************************************************************/
#if defined(CONFIG_BL602_WIRELESS)
extern int bl602_net_initialize(int intf);
extern int bl602_net_initialize(void);
#endif
#if defined(CONFIG_BL602_BLE_CONTROLLER)
@ -274,7 +274,7 @@ int bl602_bringup(void)
#ifdef CONFIG_BL602_WIRELESS
bl602_set_em_sel(BL602_GLB_EM_8KB);
bl602_net_initialize(0);
bl602_net_initialize();
#endif
#ifdef CONFIG_RTC_DRIVER