Skip to content

Concepts First

  • RESTful API: expressing "resources and operations" with HTTP methods — GET to query, POST to create, PUT/PATCH to update, DELETE to delete; responses are usually JSON.
  • HTTP server: the module listens on a port and waits for phones/PCs/clouds to access it — ideal for remotely controlled devices.
  • Router: the example keeps a route table mapping URL+method to handler functions; unmatched paths return 404.
  • lwIP netconn API: the example uses netconn_new/bind/listen/accept/recv/write, a higher-level API above lwIP sockets, for its multi-threaded HTTP service.

Example Overview

This page covers the http_restful_api example in the official Bouffalo SDK (examples/wifi/sta/http_restful_api):

  • http_test starts the HTTP server (http_server_restfulAPI.c), listening on port 80;
  • route table (from httpRouter[]):
MethodURLPurpose
GET/api/v1/gpiosList all GPIO states
POST/api/v1/gpiosCreate/set a GPIO (JSON body)
PUT/api/v1/gpios/Update a GPIO (ID in URL)
DELETE/api/v1/gpios/Delete a GPIO
PATCH/api/v1/gpios/Partially update a GPIO
  • also serves a web page (fsdata_custom.c) for browser-based control;
  • main.c handles Wi-Fi/shell/event init; the server logic lives in http_server_restfulAPI.c.
  • Related reference: client requests in HTTP GET/POST and HTTPS; this page turns the module into a server.

Operation Steps

1
Enter the Example Directory

Open a terminal and enter the SDK HTTP RESTful API example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/wifi/sta/http_restful_api
2
Prepare Web Resources (optional)

The example ships a prebuilt web page array fsdata_custom.c. If you modify the page, regenerate it with makefsdata and copy it into the lwIP HTTP app, then rebuild:

cd makefsdata
cp fsdata.c ../../../components/net/lwip/lwip/src/apps/http/fsdata.c
3
Build the Project

Both Ai-M61 and Ai-M62 use bl616 (the example defconfig enables CONFIG_HTTPD etc.):

make CHIP=bl616 BOARD=bl616dk
4
Flash the Firmware

Hold BOOT, briefly press EN/RST to enter download mode, then flash:

make flash CHIP=bl616 COMX=/dev/ttyUSB0
5
Connect Wi-Fi and Start the HTTP Server

Serial tool at 2000000 baud. Connect to the router, then run http_test to start the server (listening on port 80):

wifi_sta_connect Your_SSID 12345678
http_test
6
Run and Verify

Open http://<module-IP>/ in a PC browser for the control page; or call the RESTful API with curl, e.g. list GPIOs, create/modify/delete one:

curl http://192.168.1.3/api/v1/gpios
curl -X POST http://192.168.1.3/api/v1/gpios -d '{"pin":3,"value":1}'
curl -X DELETE http://192.168.1.3/api/v1/gpios/3

Code Execution Flow

The complete RESTful server flow from boot to handling requests:

APIs Used by the Example

netconn_new / netconn_bind / netconn_listen(NETCONN_TCP) / (conn, addr, port) / (conn)

Creates a TCP connection object and listens on port 80 — the server's entry point.

Parameters:

  • conn: struct netconn
  • NETCONN_TCP: TCP type
  • port: HTTP_SERVER_PORT (80)

Return: ERR_OK on success; lwIP error codes otherwise

netconn_accept / netconn_recv(conn, &newconn) / (conn, &inbuf)

Accepts a client connection; reads request data into a netbuf.

Parameters:

  • conn: listening connection object
  • newconn: accepted connection (output)
  • inbuf: netbuf receive buffer

Return: ERR_OK on success

router_match(conn, url, method, body)

(example-specific) looks up (method, url) in the httpRouter[] table; on hit calls the handler, otherwise returns 404.

Parameters:

  • conn: connection object
  • url: request path
  • method: HtmlRequestMethod_TypeDef
  • body: request body (JSON)

Return: none

netconn_write(conn, data, len, NETCONN_COPY)

Sends the response (status line + JSON body) to the client.

Parameters:

  • conn: connection object
  • data / len: response data and length
  • NETCONN_COPY: copy-send flag

Return: ERR_OK on success

Complete Code

The full main.c source, identical to the official example (examples/wifi/sta/http_restful_api; server routing logic is in http_server_restfulAPI.c in the same directory). Collapsed by default; click to expand:

📜 Click to expand http_restful_api/main.c full code
c
/****************************************************************************
 *
 * 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 "wifi_mgmr_ext.h"

#include "bflb_irq.h"
#include "bflb_uart.h"

#include "rfparam_adapter.h"

#include "board.h"
#include "shell.h"

#define DBG_TAG "MAIN"
#include "log.h"
#include "async_event.h"

struct bflb_device_s *gpio;

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/****************************************************************************
 * Private Types
 ****************************************************************************/

/****************************************************************************
 * Private Data
 ****************************************************************************/

static struct bflb_device_s *uart0;

static wifi_conf_t conf = {
    .country_code = "CN",
};

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_init(&conf);
        } 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");

    tcpip_init(NULL, NULL);

    xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

The browser cannot open the module's page

Confirm the module got an IP (the browser URL must be the module's IP) and http_test was run first; the PC and module must be on the same subnet; disable "AP isolation" if the router has it.

curl returns 404

Check the URL against the route table (note the trailing slash difference: /api/v1/gpios vs /api/v1/gpios/; PUT/DELETE use the trailing-slash path) and that the HTTP method (GET/POST/PUT/DELETE) matches the route.

Have questions?

For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23