Skip to content

yangcong-bit/esp-now-tdma

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESP-TDMA-MAC Component for ESP-IDF

An open-source, high-performance, and payload-agnostic TDMA (Time Division Multiple Access) scheduled MAC layer for ESP-NOW on ESP32-S3. Features low-latency deterministic communication with Adaptive Frequency Hopping (AFH) and NFC Out-Of-Band (OOB) provisioning.

Features

  • Time Division scheduled (TDMA): Master broadcasts a beacon every 10 ms (configurable). Up to 15 slaves transmit in assigned slots, completely eliminating collisions.
  • Adaptive Frequency Hopping (AFH): Automatic real-time Packet Error Rate (PER) tracking per node. When interference is detected, the master schedules a synchronized hop across channels (1 -> 6 -> 11 -> 1).
  • NFC Out-Of-Band Provisioning: Fast provisioning payloads designed to be written to ST25DV mailbox. Allows nodes to pair instantly with zero radio pollution.
  • Payload Agnostic: The MAC layer treats the payload as an opaque byte buffer (void *). You define your own structures.
  • Thread-safe & Lock-free: Uses a Single-Producer Single-Consumer (SPSC) ring buffer under the hood, ensuring that real-time sensor processing (e.g., IMU sampling) is never blocked by transmission.

Getting Started

1. Installation

Copy the esp_tdma_mac folder into your ESP-IDF project's components directory or specify it in your main/CMakeLists.txt.

Ensure your component requires esp_wifi and espressif/esp-now:

REQUIRES esp_wifi espressif__esp-now

2. Configuration (Kconfig)

Run idf.py menuconfig and navigate to ESP TDMA MAC Configuration:

  • Maximum number of slave nodes (Default: 15)
  • Beacon broadcast interval (Default: 10 ms)
  • Time slot step per node (Default: 700 µs)
  • PER sliding window size (Default: 1000 packets)
  • PER threshold to trigger AFH (Default: 5%)
  • Maximum user payload size per packet (Default: 220 bytes)

Quick Example

Master (Gateway) Setup

#include "esp_tdma_mac.h"
#include "esp_log.h"

static const char *TAG = "gateway";

static void on_data_received(uint8_t node_id, uint32_t seq, uint8_t battery, 
                             const void *payload, uint8_t payload_len) {
    ESP_LOGI(TAG, "Received payload from node %d, seq=%lu, battery=%d%%, len=%d",
             node_id, (unsigned long)seq, battery, payload_len);
    // Cast payload back to your custom struct
    // my_sensor_data_t *data = (my_sensor_data_t *)payload;
}

static void on_node_registered(uint8_t node_id, uint32_t fw_ver, bool upgrade_required) {
    ESP_LOGI(TAG, "Node %d registered. Firmware version: %lu", node_id, (unsigned long)fw_ver);
}

void app_main(void) {
    // Wi-Fi (STA mode) and ESP-NOW are automatically initialized by the component on startup.
    // No manual Wi-Fi or ESP-NOW initialization boilerplate required.
    
    esp_tdma_master_cfg_t cfg = {
        .target_node_count = 1,
        .on_data_received = on_data_received,
        .on_node_registered = on_node_registered,
        .on_state_changed = NULL
    };
    
    ESP_ERROR_CHECK(esp_tdma_master_init(&cfg));
    ESP_ERROR_CHECK(esp_tdma_master_start());
}

Slave (Node) Setup

#include "esp_tdma_mac.h"
#include "esp_log.h"

static const char *TAG = "node";

void app_main(void) {
    // Wi-Fi (STA mode) and ESP-NOW are automatically initialized by the component on startup.
    // No manual Wi-Fi or ESP-NOW initialization boilerplate required.
    
    esp_tdma_slave_cfg_t cfg = {
        .on_state_changed = NULL
    };
    
    ESP_ERROR_CHECK(esp_tdma_slave_init(&cfg));
    
    // Config received via NFC or loaded from NVS:
    uint8_t node_id = 1;
    uint8_t gateway_mac[6] = {0x28, 0x84, 0x85, 0x52, 0xC4, 0x0C};
    uint8_t aes_lmk[16] = {0}; // LMK for encrypted ESP-NOW
    uint32_t slot_offset_us = node_id * 700; // 700us offset
    
    esp_tdma_slave_set_config(node_id, gateway_mac, aes_lmk, slot_offset_us);
    ESP_ERROR_CHECK(esp_tdma_slave_start());
    
    // In your sensor sampling task:
    while (1) {
        my_sensor_data_t data = read_sensor();
        esp_tdma_slave_enqueue(&data, sizeof(data));
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

About

A payload-agnostic TDMA MAC layer for ESP-NOW on ESP32 series, featuring microsecond-level clock synchronization, Adaptive Frequency Hopping (AFH), and NFC OOB provisioning.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors