yangcong-bit/esp-now-tdma

1.0.7

Latest
uploaded 13 hours ago
A TDMA MAC layer for ESP-NOW on ESP32-S3 with Adaptive Frequency Hopping (AFH). Provides deterministic time-slotted access, NFC OOB provisioning support, and automatic PER-based channel hopping between 2.4 GHz channels 1/6/11. Payload-agnostic: the user defines and owns all application data structures.

Readme

# 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`:
```cmake
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

```c
#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

```c
#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.

Links

Supports all targets

To add this component to your project, run:

idf.py add-dependency "yangcong-bit/esp-now-tdma^1.0.7"

download archive

Stats

  • Archive size
    Archive size ~ 26.29 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

yangcong-bit/esp-now-tdma version: 1.0.7
|