Skip to content

Concepts First

  • UDP server: UDP has no connections — the server simply binds a socket to a port and exchanges datagrams with anyone.
  • Datagram: each UDP send/receive is one complete packet with preserved boundaries, unlike the TCP byte stream.
  • recvfrom / sendto: UDP functions carry the peer's address, so you know who sent it and where to reply.
  • Echo: the example returns received data verbatim to the sender.

Example Overview

This page covers the UDP echo server part of the wifi_udp example in the official Bouffalo SDK (examples/wifi/sta/wifi_udp/wifi_udp_echo.c):

  • socket(AF_INET, SOCK_DGRAM, 0) creates a UDP socket; bind() binds 0.0.0.0:port;
  • loops recvfrom() to receive datagrams, prints the source IP and content, then sendto() echoes back;
  • the shell command wifi_udp_echo <port> starts the server; Ctrl+C exits and prints statistics.
  • Related reference: UDP client and broadcast/multicast have no standalone examples; the tutorial provides self-written UDP client, UDP broadcast and UDP multicast.

Operation Steps

1
Enter the Example Directory

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

cd examples/wifi/sta/wifi_udp
2
Build the Project

Both Ai-M61 and Ai-M62 use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

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

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

Serial tool at 2000000 baud. Wait for bouffalolab />, connect to the router, then start the UDP echo server on port 3365:

wifi_sta_connect Your_SSID 12345678
wifi_udp_echo 3365
5
Run and Verify

On the PC, send datagrams to the module with netcat in UDP mode; the module echoes them back verbatim:

nc -uv 192.168.1.3 3365

Code Execution Flow

The complete UDP server flow from boot to echo:

APIs Used by the Example

socket(AF_INET, SOCK_DGRAM, 0)

Creates a UDP socket. SOCK_DGRAM (datagram) is the key difference from TCP.

Parameters:

  • AF_INET: IPv4 family
  • SOCK_DGRAM: connectionless datagram socket

Return: >= 0 handle; < 0 on failure

bind(sock, addr, len)

Binds the socket to a local port (the example uses 0.0.0.0:3365); datagrams to that port then arrive on this socket.

Parameters:

  • sock: socket handle
  • addr: sockaddr_in with htons(port) and INADDR_ANY

Return: 0 on success; -1 on failure

recvfrom(sock, buf, len, 0, from, fromlen)

Blocks until a datagram arrives and writes the sender's address into from.

Parameters:

  • sock: socket handle
  • buf / len: receive buffer and length (1024 in the example)
  • from / fromlen: sender address

Return: bytes received; < 0 on error

sendto(sock, buf, len, 0, to, tolen)

Sends a datagram to the given address; for echo, pass the from from recvfrom back.

Parameters:

  • sock: socket handle
  • to / tolen: destination address

Return: bytes sent; < 0 on error

Complete Code

The full wifi_udp_echo.c source, identical to the official example (examples/wifi/sta/wifi_udp). Collapsed by default; click to expand:

📜 Click to expand wifi_udp/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"

#ifndef BL602
#include "fhost_api.h"
#include "wifi_mgmr.h"
#endif
#include "async_event.h"
#include "mm.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);
#ifdef BL602
extern void wifi_task_create(void);
extern int fhost_init(void);
extern int wifi_mgmr_task_start(void);
#endif

/****************************************************************************
 * 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;
        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) {
    }
}
📜 Click to expand wifi_udp_echo.c full code
c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <lwip/api.h>
#include <lwip/arch.h>
#include <lwip/opt.h>
#include <lwip/inet.h>
#include <lwip/errno.h>
#include <netdb.h>

#include "shell.h"
#include "utils_getopt.h"
#include "bflb_mtimer.h"

// clang-format off
uint32_t recv_buf[2 * 1024] = {0};
// clang-format on

shell_sig_func_ptr abort_exec;
uint64_t recv_len = 0;
int sock = -1;

static void test_close(int sig)
{
    if (sock) {
        closesocket(sock);
    }
    abort_exec(sig);
    if (recv_len > 0) {
        printf("Total send data=%lld\r\n", recv_len);
    }
}

#define PING_USAGE             \
    "wifi_udp_echo [port]\r\n" \
    "\t port: local listen port, default port 5001\r\n"

static void wifi_test_udp_echo_init(int argc, char **argv)
{
    abort_exec = shell_signal(SHELL_SIGINT, test_close);
    printf("udp server task start ...\r\n");

    char *port;
    struct sockaddr_in udp_addr, remote_addr;
    socklen_t addr_len;

    if (argc < 2) {
        printf("%s", PING_USAGE);
        return;
    }

    /* get port number (argv[1] if present) */
    if (argc > 1) {
        port = argv[1];
    } else {
        port = "5001";
    }

    memset(&recv_buf[0], 0, sizeof(recv_buf));

    while (1) {
        if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            printf("udp create socket error\r\n");
            return;
        }
        udp_addr.sin_family = AF_INET;
        udp_addr.sin_port = htons(atoi(port));
        udp_addr.sin_addr.s_addr = INADDR_ANY;
        memset(&(udp_addr.sin_zero), 0, sizeof(udp_addr.sin_zero));

        printf("Server ip Address : %s:%s\r\n", udp_addr.sin_addr.s_addr, port);

        if (bind(sock, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) != 0) {
            printf("udp bind falied!\r\n");
            closesocket(sock);
            return;
        }

        printf("udp bind port success!\r\n");
        printf("Press CTRL-C to exit.\r\n");
        recv_len = 0;
        while (1) {
            recv_len = recvfrom(sock, recv_buf, 1024, 0, (struct sockaddr *)&remote_addr, &addr_len);
            printf("recv from %s\r\n", inet_ntoa(remote_addr.sin_addr));
            printf("recv:%s \r\n", recv_buf);
            sendto(sock, recv_buf, recv_len, 0, (struct sockaddr *)&remote_addr, addr_len);
        }
        closesocket(sock);
        return;
    }
}

#ifdef CONFIG_SHELL
#include <shell.h>

int cmd_wifi_udp_echo(int argc, char **argv)
{
    wifi_test_udp_echo_init(argc, argv);

    return 0;
}

SHELL_CMD_EXPORT_ALIAS(cmd_wifi_udp_echo, wifi_udp_echo, wifi udp test);
#endif

FAQ

nc -uv cannot connect / no echo

Confirm the module and PC are on the same subnet and wifi_sta_connect succeeded (got IP). UDP has no connection — netcat's "Connection succeeded" only means the local socket is ready; send several packets (e.g. echo hi | nc -uv 192.168.1.3 3365) and check after the module receives them.

Cannot receive my own broadcast

This page is unicast echo. For subnet-wide broadcast or multicast, see UDP Broadcast and UDP Multicast; broadcast requires the SO_BROADCAST option.

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