Concepts First
- Soft-AP (software hotspot): the module itself creates a Wi-Fi hotspot without dedicated router hardware.
- Router mode / AP+STA bridge: the module joins the router as STA while running an AP; phones joining the hotspot get their traffic bridged to the router, so they can go online. This "connection sharing" is the core of router mode.
- Bridge interface: the STA and AP network interfaces are logically merged into one
br3, so packets can be forwarded between them. - DHCP ownership:
-d 0lets the router (through the bridge) assign IPs instead of the AP, putting the phone and the module on the same subnet for easy mutual access.
Example Overview
This page is based on the ap_sta_bridge example in the official Bouffalo SDK (examples/wifi/ap_sta_bridge), which demonstrates router mode (AP+STA bridge):
board_init()/ shell /rfparam_init()basic initialization;- additionally calls
netifd_nano_init()to support bridge interfaces; - the rest matches the STA skeleton: register events → start Wi-Fi firmware and fhost;
- actual operations are shell commands:
wifi_sta_connect -D→wifi_ap_start→netifd bridge create/add; - once bridged, phones on the hotspot share the router's Internet.
- Sibling example:
examples/wifi/sta/smartconfig_softap(auto-start AP with web-based provisioning; its README primarily targets BL602).
Operation Steps
Open a terminal and enter the AP+STA bridge example directory:
cd examples/wifi/ap_sta_bridgeBoth Ai-M61 and Ai-M62 use bl616:
make CHIP=bl616 BOARD=bl616dkHold BOOT, briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616 COMX=/dev/ttyUSB0Serial tool at 2000000 baud. First connect the module’s STA interface to your router (-D disables DHCP on STA, which the bridge handles later):
wifi_sta_connect -D Your_SSID 12345678Start the AP: -s sets the hotspot name, -d 0 disables AP-side DHCP (the bridge handles it), -c sets the channel (match the STA’s channel):
wifi_ap_start -s tiny_ap -d 0 -c 6Create a bridge interface br3 and add the STA interface (wl1) and the AP interface (wl2) to it; the module now behaves like a router:
netifd bridge create -b br3
netifd bridge add -b br3 -i wl1
netifd bridge add -b br3 -i wl2Connect a phone to the tiny_ap hotspot. The phone gets an IP from the router and can access the Internet; the bridge transparently forwards packets between the STA and AP interfaces (mat shows forwarding statistics).
Code Execution Flow
The complete flow from boot to bridged forwarding:
APIs Used by the Example
netifd_nano_init()
Initializes the lightweight network interface daemon (netifd) that provides the netifd bridge commands.
Parameters: none
Return: none
wifi_mgmr_sta_connect / wifi_mgmr_ap_start(params) / (if, ssid, ch, pwd, channel)
Connect the STA interface to the router and start the AP (via wifi_ap_start shell command).
Parameters:
-D: do not run DHCP on STA (bridge assigns later)-s: AP SSID,-d 0: no AP DHCP,-c: channel
Return: none (see event logs)
netifd bridge create / add(-b br3) / (-b br3 -i wlX)
Create a bridge interface and attach network interfaces (wl1 STA, wl2 AP) so packets flow between them.
Parameters:
-b br3: bridge name-i wlX: interface to attach
Return: none
Complete Code
The full main.c source of the ap_sta_bridge example, identical to the official example (examples/wifi/ap_sta_bridge). Collapsed by default; click to expand:
📜 Click to expand ap_sta_bridge/main.c full code
/****************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "bl_fw_api.h"
#include "fhost_api.h"
#include "wifi_mgmr_ext.h"
#include "wifi_mgmr.h"
#include "bflb_irq.h"
#include "bflb_uart.h"
#include "rfparam_adapter.h"
#include "async_event.h"
#include "board.h"
#include "shell.h"
#include "mm.h"
#include "netifd_nano.h"
#define DBG_TAG "MAIN"
#include "log.h"
struct bflb_device_s *gpio;
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define WIFI_STACK_SIZE (1536)
#define TASK_PRIORITY_FW (16)
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static struct bflb_device_s *uart0;
extern void shell_init_with_task(struct bflb_device_s *shell);
extern void wifi_event_handler(async_input_event_t ev, void *priv);
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Functions
****************************************************************************/
void wifi_start_firmware_task(void *param)
{
LOG_I("Starting wifi ...\r\n");
async_register_event_filter(EV_WIFI, wifi_event_handler, NULL);
wifi_task_create();
LOG_I("Starting fhost ...\r\n");
fhost_init();
vTaskDelete(NULL);
}
void wifi_event_handler(async_input_event_t ev, void *priv)
{
uint32_t code = ev->code;
switch (code) {
case CODE_WIFI_ON_INIT_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE\r\n", __func__);
wifi_mgmr_task_start();
} break;
case CODE_WIFI_ON_MGMR_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE\r\n", __func__);
} break;
case CODE_WIFI_ON_SCAN_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE\r\n", __func__);
wifi_mgmr_sta_scanlist();
} break;
case CODE_WIFI_ON_CONNECTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED\r\n", __func__);
void mm_sec_keydump();
mm_sec_keydump();
} break;
#ifdef CODE_WIFI_ON_GOT_IP_ABORT
case CODE_WIFI_ON_GOT_IP_ABORT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_ABORT\r\n", __func__);
} break;
#endif
#ifdef CODE_WIFI_ON_GOT_IP_TIMEOUT
case CODE_WIFI_ON_GOT_IP_TIMEOUT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_TIMEOUT\r\n", __func__);
} break;
#endif
case CODE_WIFI_ON_GOT_IP: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP\r\n", __func__);
LOG_I("[SYS] Memory left is %d Bytes\r\n", kfree_size(0));
} break;
case CODE_WIFI_ON_DISCONNECT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STARTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STOPPED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STA_ADD: {
LOG_I("[APP] [EVT] [AP] [ADD] %lld\r\n", xTaskGetTickCount());
} break;
case CODE_WIFI_ON_AP_STA_DEL: {
LOG_I("[APP] [EVT] [AP] [DEL] %lld\r\n", xTaskGetTickCount());
} break;
default: {
LOG_I("[APP] [EVT] Unknown code %u \r\n", code);
}
}
}
int main(void)
{
board_init();
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
if (0 != rfparam_init(0, NULL, 0)) {
LOG_I("PHY RF init failed!\r\n");
return 0;
}
LOG_I("PHY RF init success!\r\n");
netifd_nano_init();
tcpip_init(NULL, NULL);
xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);
vTaskStartScheduler();
while (1) {
}
}FAQ
Phone connects to the hotspot but cannot get an IP
Confirm the STA interface is connected to a working router first (wifi_sta_connect -D), the bridge br3 contains both wl1 and wl2, and the router's DHCP is enabled; also make sure the AP channel matches the STA channel.
Only AP or only STA seems to work
Check the interface names with netifd / ifconfig; the bridge commands must use the real STA (wl1) and AP (wl2) interface names printed by the SDK.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

