【基于ESP32-C2和ESP-IDF平台实现ADHOC(动态源路由DSR)自组网的代码实现】

ESP32-C2实现DSR自组网

以下是基于ESP32-C2和ESP-IDF平台实现ADHOC(动态源路由DSR)自组网的代码实现,分为核心模块和函数实现。假设使用ESP-NOW作为底层通信协议,并简化了部分路由逻辑。


数据结构定义

// dsr_route.h
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "esp_now.h"

#define MAX_NODES 10
#define MAX_HOPS 5
#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}

typedef struct {
    uint8_t mac[6];      // 节点MAC地址
    uint8_t seq_num;     // 序列号用于路由新鲜度
    uint16_t metric;     // 路由度量(如跳数)
} DSRRouteEntry;

typedef struct {
    uint8_t src[6];       // 源地址
    uint8_t dst[6];       // 目标地址
    uint8_t path[MAX_HOPS][6]; // 路径记录
    uint8_t hop_count;    // 当前跳数
    uint8_t payload[100]; // 数据负载
} DSRPacket;

typedef struct {
    DSRRouteEntry routes[MAX_NODES];
    uint8_t node_count;
} RoutingTable;

路由表管理

// routing_table.c
#include "dsr_route.h"

void init_routing_table(RoutingTable *table) {
    memset(table, 0, sizeof(RoutingTable));
}

int add_route(RoutingTable *table, const uint8_t *mac, uint8_t seq_num, uint16_t metric) {
    if (table->node_count >= MAX_NODES) return -1;

    memcpy(table->routes[table->node_count].mac, mac, 6);
    table->routes[table->node_count].seq_num = seq_num;
    table->routes[table->node_count].metric = metric;
    table->node_count++;
    return 0;
}

DSRRouteEntry* find_route(RoutingTable *table, const uint8_t *dst_mac) {
    for (int i = 0; i < table->node_count; i++) {
        if (memcmp(table->routes[i].mac, dst_mac, 6) == 0) {
            return &table->routes[i];
        }
    }
    return NULL;
}

DSR路由请求(RREQ)

// dsr_rreq.c
void send_rreq(RoutingTable *table, const uint8_t *dst_mac) {
    DSRPacket pkt;
    memset(&pkt, 0, sizeof(DSRPacket));
    memcpy(pkt.src, table->local_mac, 6);
    memcpy(pkt.dst, dst_mac, 6);
    pkt.hop_count = 0;

    // 广播RREQ
    esp_now_send(BROADCAST_MAC, (uint8_t *)&pkt, sizeof(DSRPacket));
}

void handle_rreq(RoutingTable *table, const DSRPacket *pkt) {
    // 检查是否已处理过该请求(通过序列号)
    DSRRouteEntry *entry = find_route(table, pkt->src);
    if (entry && entry->seq_num >= pkt->seq_num) return;

    // 添加反向路径到路由表
    add_route(table, pkt->src, pkt->seq_num, pkt->hop_count);

    // 如果是目标节点,发送RREP
    if (memcmp(pkt->dst, table->local_mac, 6) == 0) {
        send_rrep(table, pkt);
    } else {
        // 转发RREQ(增加跳数)
        DSRPacket forwarded_pkt = *pkt;
        forwarded_pkt.hop_count++;
        esp_now_send(BROADCAST_MAC, (uint8_t *)&forwarded_pkt, sizeof(DSRPacket));
    }
}

DSR路由回复(RREP)

// dsr_rrep.c
void send_rrep(RoutingTable *table, const DSRPacket *rreq) {
    DSRPacket pkt;
    memcpy(pkt.src, table->local_mac, 6);
    memcpy(pkt.dst, rreq->src, 6);
    pkt.hop_count = 0;

    // 单播RREP
    esp_now_send(rreq->src, (uint8_t *)&pkt, sizeof(DSRPacket));
}

void handle_rrep(RoutingTable *table, const DSRPacket *pkt) {
    // 添加正向路径到路由表
    add_route(table, pkt->src, pkt->seq_num, pkt->hop_count);

    // 如果不是本机发起,则转发RREP
    if (memcmp(pkt->dst, table->local_mac, 6) != 0) {
        DSRPacket forwarded_pkt = *pkt;
        forwarded_pkt.hop_count++;
        esp_now_send(pkt->dst, (uint8_t *)&forwarded_pkt, sizeof(DSRPacket));
    }
}

数据包转发

// dsr_forward.c
void forward_data(RoutingTable *table, const DSRPacket *pkt) {
    // 检查是否为目标节点
    if (memcmp(pkt->dst, table->local_mac, 6) == 0) {
        deliver_payload(pkt->payload);
        return;
    }

    // 查找路由
    DSRRouteEntry *route = find_route(table, pkt->dst);
    if (!route) {
        send_rreq(table, pkt->dst);
        return;
    }

    // 转发数据包(需更新路径记录)
    DSRPacket forwarded_pkt = *pkt;
    memcpy(forwarded_pkt.path[forwarded_pkt.hop_count], table->local_mac, 6);
    forwarded_pkt.hop_count++;
    esp_now_send(route->mac, (uint8_t *)&forwarded_pkt, sizeof(DSRPacket));
}

ESP-NOW初始化

// main.c
#include "esp_now.h"
#include "dsr_route.h"

RoutingTable g_table;

void esp_now_recv_cb(const uint8_t *mac, const uint8_t *data, int len) {
    if (len == sizeof(DSRPacket)) {
        DSRPacket *pkt = (DSRPacket *)data;
        switch (pkt->type) {
            case PKT_RREQ: handle_rreq(&g_table, pkt); break;
            case PKT_RREP: handle_rrep(&g_table, pkt); break;
            case PKT_DATA: forward_data(&g_table, pkt); break;
        }
    }
}

void app_main() {
    esp_now_init();
    esp_now_register_recv_cb(esp_now_recv_cb);
    init_routing_table(&g_table);
}

关键点说明

  1. 路由发现:通过广播RREQ和单播RREP实现。
  2. 路由维护:使用序列号避免环路,跳数限制路径长度。
  3. 数据转发:根据路由表选择下一跳,支持动态路径更新。
  4. 扩展性:可通过增加路由超时机制、链路质量评估等优化。

实际部署时需处理以下问题:

  • ESP-NOW的广播包可能丢失,需添加重传机制
  • 动态网络拓扑变化时需路由过期策略
  • 安全机制(如MAC地址验证)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值