Skip to content

Concepts First

  • UDP client: the device that actively "throws" datagrams at a server. UDP needs no connection — sendto with a destination address is enough.
  • Datagram: one complete packet per send/receive with preserved boundaries; delivery and order are not guaranteed, which suits real-time apps that tolerate occasional loss.
  • sendto / recvfrom: sending carries the destination, receiving carries the sender; since there is no connection, the address must be stated explicitly each time.
  • UDP port: the server listens on a fixed port; the client's source port is assigned by the system.

Example Overview

The SDK has no standalone UDP client example; this self-written example is built on the wifi_tcp skeleton (its networking matches the official wifi_udp example, both based on lwIP sockets):

  • after getting an IP, creates udp_client_task;
  • socket(AF_INET, SOCK_DGRAM, 0) creates a UDP socket;
  • sends hello from ai-m6x to UDP_SERVER_IP:6000 every second and prints the reply;
  • change UDP_SERVER_IP / UDP_SERVER_PORT at the top of the file to retarget.
  • Related reference: the official wifi_udp example demonstrates the server/echo side (see UDP Server).

Operation Steps

1
Enter the Example Directory

The SDK has no standalone UDP client example (wifi_udp only ships an echo server), so this page is written on the wifi_tcp skeleton (marked self-written). First enter the directory:

cd examples/wifi/sta/wifi_tcp
2
Replace main.c

Overwrite main.c in the example directory with the self-written one below (change UDP_SERVER_IP to your server’s IP):

3
Build the Project

Both Ai-M61 and Ai-M62 use bl616:

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 Verify

Serial tool at 2000000 baud. After connecting to the router the program automatically sends hello from ai-m6x to UDP_SERVER_IP:6000 every second and prints the server’s reply. On the PC, run a UDP echo service first (e.g. nc -u -l 6000) to observe.

wifi_sta_connect Your_SSID 12345678

Code Execution Flow

The complete UDP client flow from boot to send/receive:

APIs Used by the Example

socket(AF_INET, SOCK_DGRAM, 0)

Creates a UDP socket.

Parameters:

  • AF_INET: IPv4 family
  • SOCK_DGRAM: datagram (UDP) socket

Return: >= 0 handle; < 0 on failure

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

Sends a datagram to the given address.

Parameters:

  • sock: socket handle
  • buf / len: data and length
  • to / tolen: destination (server IP and port)

Return: bytes sent; < 0 on error

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

Blocks until a datagram arrives and returns the sender's address. The example uses it to wait for the server's reply.

Parameters:

  • sock: socket handle
  • from / fromlen: sender address

Return: bytes received; < 0 on error

Complete Code

The self-written main.c below (built on the SDK wifi_tcp skeleton; not an SDK file). Collapsed by default; click to expand:

📜 Click to expand self-written udp_client main.c full code
c
/*
 * Self-written example: UDP client (based on lwIP sockets)
 * Usage:
 *   1. Overwrite examples/wifi/sta/wifi_tcp/main.c with this file;
 *   2. Change UDP_SERVER_IP to your server's IP;
 *   3. make CHIP=bl616 BOARD=bl616dk && make flash CHIP=bl616 COMX=/dev/ttyUSB0;
 *   4. Run wifi_sta_connect <SSID> <password> on the serial shell; the program sends/receives automatically.
 */

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#include <string.h>

#include <lwip/tcpip.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>

#include "wifi_mgmr_ext.h"
#include "fhost_api.h"
#include "wifi_mgmr.h"

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

#include "rfparam_adapter.h"
#include "async_event.h"
#include "mm.h"
#include "board.h"
#include "shell.h"

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

#define UDP_SERVER_IP   "192.168.1.2"
#define UDP_SERVER_PORT 6000

static volatile uint32_t wifi_state = 0;
static struct bflb_device_s *uart0;

extern void shell_init_with_task(struct bflb_device_s *shell);

void wifi_event_handler(async_input_event_t ev, void *priv)
{
    switch (ev->code) {
        case CODE_WIFI_ON_GOT_IP:
            wifi_state = 1;
            LOG_I("Got IP\r\n");
            break;
        case CODE_WIFI_ON_DISCONNECT:
            wifi_state = 0;
            LOG_I("WiFi disconnected\r\n");
            break;
        default:
            break;
    }
}

static void udp_client_task(void *param)
{
    int sock;
    struct sockaddr_in server;
    char send_buf[] = "hello from ai-m6x";
    char recv_buf[128];
    socklen_t addr_len = sizeof(server);

    /* Wait for Wi-Fi to get an IP */
    while (!wifi_state) {
        vTaskDelay(pdMS_TO_TICKS(200));
    }

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        LOG_E("create socket failed\r\n");
        vTaskDelete(NULL);
        return;
    }

    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(UDP_SERVER_PORT);
    server.sin_addr.s_addr = inet_addr(UDP_SERVER_IP);

    LOG_I("UDP client send to %s:%d\r\n", UDP_SERVER_IP, UDP_SERVER_PORT);

    while (1) {
        int ret = sendto(sock, send_buf, strlen(send_buf), 0,
                         (struct sockaddr *)&server, sizeof(server));
        if (ret < 0) {
            LOG_E("sendto failed\r\n");
        } else {
            LOG_I("send %d bytes\r\n", ret);
        }

        ret = recvfrom(sock, recv_buf, sizeof(recv_buf) - 1, 0,
                       (struct sockaddr *)&server, &addr_len);
        if (ret >= 0) {
            recv_buf[ret] = '\0';
            LOG_I("recv %d bytes: %s\r\n", ret, recv_buf);
        }

        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

static 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);
}

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;
    }

    tcpip_init(NULL, NULL);

    xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);
    xTaskCreate(udp_client_task, "udp client", 1024, NULL, 11, NULL);

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

The server receives nothing

Confirm the module got an IP (log shows Got IP); UDP_SERVER_IP must be the server's actual IP and you must rebuild/flash after changing it; the server's firewall may block UDP — test with nc -u -l 6000 on the same subnet first.

recvfrom blocks forever and never prints a reply

UDP delivery is not guaranteed; if the server never replies, recvfrom waits forever. Set a receive timeout (setsockopt(SO_RCVTIMEO)) or comment out the receive part while debugging the send path.

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