Custom Packet Ping Pong
This example demonstrates the custom packet functionality of MeshNOW.
We set everything up, and then broadcast a PING message from the root to all nodes in the mesh.
Each node will respond with a PONG message, and the root will print the responses.
1#include <esp_err.h>
2#include <esp_event.h>
3#include <esp_log.h>
4#include <esp_mac.h>
5#include <esp_wifi.h>
6#include <freertos/FreeRTOS.h>
7#include <freertos/task.h>
8#include <meshnow.h>
9#include <nvs_flash.h>
10
11// Waitbits
12#define CONNECTED_BIT BIT0
13
14static const char *TAG = "ping-pong";
15
16// Fixed MAC address of the root node
17static const uint8_t root_mac[MESHNOW_ADDRESS_LENGTH] = {0x24, 0x6f, 0x28, 0x4a, 0x63, 0x3c};
18
19// MAC address of the current node
20static uint8_t node_mac[MESHNOW_ADDRESS_LENGTH];
21
22// Whether this node is the root
23static bool is_root = false;
24
25// Event group for various waiting processes
26static EventGroupHandle_t my_event_group;
27
28// Custom packet types
29typedef enum {
30 PING = 0,
31 PONG = 1,
32} custom_packet_type_t;
33
34// Custom packet for ping-ponging
35typedef struct {
36 custom_packet_type_t type;
37 uint32_t timestamp;
38} __attribute__((__packed__)) custom_packet_t;
39
40// Event handler for MESHNOW_EVEMT
41static void meshnow_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
42 assert(event_base == MESHNOW_EVENT);
43
44 switch (event_id) {
45 case MESHNOW_EVENT_PARENT_CONNECTED: {
46 meshnow_event_parent_connected_t *data = event_data;
47 ESP_LOGI(TAG, "Parent connected: " MACSTR, MAC2STR(data->parent_mac));
48 xEventGroupSetBits(my_event_group, CONNECTED_BIT);
49 break;
50 }
51 case MESHNOW_EVENT_PARENT_DISCONNECTED: {
52 meshnow_event_parent_disconnected_t *data = event_data;
53 ESP_LOGI(TAG, "Parent disconnected: " MACSTR, MAC2STR(data->parent_mac));
54 xEventGroupClearBits(my_event_group, CONNECTED_BIT);
55 break;
56 }
57 }
58}
59
60// Sends custom ping messages to every node in the mesh
61static void perform_ping() {
62 // since we are root, we can send right away
63 while (true) {
64 custom_packet_t data = {
65 .type = PING,
66 .timestamp = xTaskGetTickCount(),
67 };
68 ESP_ERROR_CHECK(meshnow_send(&MESHNOW_BROADCAST_ADDRESS, (uint8_t *)&data, sizeof(data));
69 vTaskDelay(pMS_TO_TICKS(5000));
70 }
71}
72
73// Callback, reacts to pings and pongs depending on the node type
74static void my_data_callback(uint8_t *src, uint8_t *buffer, size_t len) {
75 // usually, you would do input sanitization here
76 // we skip it for the sake of simplicity
77
78 // cast buffer to custom packet
79 custom_packet_t *data = (custom_packet_t *)buffer;
80
81 ESP_LOGI(TAG, "Received packet of type %d from " MACSTR " with timestamp %lu", data->type, MAC2STR(src),
82 data->timestamp);
83
84 // if we are not the root, we send a pong
85 if (!is_root) {
86 custom_packet_t pong = {
87 .type = PONG,
88 .timestamp = data->timestamp,
89 };
90 ESP_ERROR_CHECK(meshnow_send(src, (uint8_t *)&pong, sizeof(pong)));
91 }
92}
93
94// Initializes NVS, Event Loop, Wi-Fi, and Netif
95static void pre_init(void) {
96 // nvs
97 esp_err_t ret = nvs_flash_init();
98 if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
99 ESP_ERROR_CHECK(nvs_flash_erase());
100 ret = nvs_flash_init();
101 }
102 ESP_ERROR_CHECK(ret);
103
104 // event loop
105 ESP_ERROR_CHECK(esp_event_loop_create_default());
106
107 // wifi
108 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
109 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
110
111 // netif
112 ESP_ERROR_CHECK(esp_netif_init());
113}
114
115void app_main(void) {
116 pre_init();
117
118 // get MAC address
119 ESP_ERROR_CHECK(esp_read_mac(node_mac, ESP_MAC_WIFI_STA));
120
121 // check if root
122 is_root = memcmp(node_mac, root_mac, MESHNOW_ADDRESS_LENGTH) == 0;
123
124 // create event group
125 my_event_group = xEventGroupCreate();
126 assert(my_event_group != NULL);
127
128 // initialize meshnow
129 meshnow_config_t config = {
130 .root = is_root,
131 .router_config =
132 {
133 .should_connect = fale, // do not connect to internet, we want to use inter-node communication
134 .sta_config = NULL,
135 },
136 };
137 ESP_ERROR_CHECK(meshnow_init(&config));
138
139 // register event handler for MESHNOW_EVENT
140 ESP_ERROR_CHECK(
141 esp_event_handler_instance_register(MESHNOW_EVENT, ESP_EVENT_ANY_IID, &meshnow_event_handler, NULL, NULL));
142
143 // register data callback
144 meshnow_data_cb_handle_t data_cb_handle; // unused, as we do not unregister the callback
145 ESP_ERROR_CHECK(meshnow_register_data_cb(&my_data_callback, &data_cb_handle));
146
147 // start meshnow
148 ESP_ERROR_CHECK(meshnow_start());
149
150 // wait for IP
151 // when we get an IP address, the node has to have connected to a parent/router
152 // in a real application, you would want to handle disconnects/lost IP as well and restart MQTT
153 EventBits_t bits = xEventGroupWaitBits(my_event_group, GOT_IP_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
154 assert((bits & GOT_IP_BIT) != 0);
155
156 if (is_root) {
157 perform_ping();
158 }
159}