Dhyara
Dhyara adhoc Network
DHYARA

GitHub Repository | Doxygen Documentation

Dhyara is a ESP-IDF component for Mobile Ad-Hoc Networks on the top of ESP NOW (Layer 2). Dhyara is Open Source under BSD 2 Clause License. See LICENSE

Management Console

Basic Usage

The dhyara nodes identify each other via MAC address. Once deployed the nodes communicate with each other and each node builds a routing table based on its local view. On the top of that, dhyara provides C and C++ APIs for send/receice/ping/traceroute functionalities.

In the following example, the string "Hello World" is a variable length data which is sent to the destination identified with the mac address 4c:11:ae:9c:a6:85 over the multihop network. If the destination is a direct neighbour of the source then the message will be delivered in one hop. Otherwise the message sent will find its path to the destination 4c:11:ae:9c:a6:85 on its own by following the routing decisions of each intermediate nodes.

uint8_t sink[] = {0x4c, 0x11, 0xae, 0x9c, 0xa6, 0x85};
dhyara_send(sink, "Hello World");

C++ version of the above mentined C example.

dhyara::peer_address sink("4c:11:ae:9c:a6:85");
std::string data = "Hello World";
dhyara_send(sink, data.begin(), data.end());

To receive the mesage sent over the network the sink node needs to register a callback where the data is received.

void data_received(const unsigned char* source, const void* data, unsigned long len){
// data received here
}
dhyara_receivef(&data_received);

ESP Now limits maximum size of a frame to 250 bytes. The variable length data is represented as a data packet (dhyara::packets::data), which is broken into multiple smaller sized chunks. On the receiving end these chunks are joined to comstruct a data packet, which is used while calling the receive callback set using dhyara_receivef, dhyara_receive, and dhyara_receive_data.

dhyara_receive_data([](const dhyara::peer::address& source, const dhyara::packets::data& data){
std::cout << "received data " << " originating from " << data.source() << " via " << source << " of size " << data.length() << std::endl;
});

In the above mentioned C++ example, source represents the immediate neighbour of the desination, and data.source() is the originator of the message.

Read More

Compilation & Integration

Dhyara is a C++11 library that has to be used as an ESP-IDF component. It can be cloned to the components directory or can be used as a git submodule inside your projects components directory. If the application project is using an extra components directory then path to that directory has to be added in the root directory's CMakeLists.txt file as shown in the following example.

set(EXTRA_COMPONENT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/components)

To configure the network parameters use idf.py menuconfig in the aplications directory and Go to Component config > Dhyara ad hoc network To build and flash the application use idf.py build and idf.py flash as usual.

menuconfig

See Building the examples.

C Example

The examples are provided in the examples directory. See Building the examples for instructions on building the examples.

Following is a C example demonstrating basic usage of dhyara

void data_received(const unsigned char* source, const void* data, unsigned long len){
ESP_LOGI("hello-c", "data received \"%s\" (length %lu)", (const char*)data, len);
}
void app_main(){
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(dhyara_init(WIFI_MODE_AP));
dhyara_receivef(&data_received);
uint8_t self[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
dhyara_local(self);
ESP_LOGI("hello-c", "Local MAC address %x:%x:%x:%x:%x:%x", self[0], self[1], self[2], self[3], self[4], self[5]);
uint8_t source[] = {0x4c, 0x11, 0xae, 0x71, 0x0f, 0x4d}; // TODO change the source address
uint8_t sink[] = {0x4c, 0x11, 0xae, 0x9c, 0xa6, 0x85}; // TODO change the sink address
const uint8_t* other = 0x0;
if(memcmp(self, source, 6) == 0) other = sink;
if(memcmp(self, sink, 6) == 0) other = source;
while(1){
if(other){
dhyara_ping(other, .count = 1, .batch = 10);
dhyara_send(other, "Hello World");
dhyara_send(other, "Hello World", 5);
}
vTaskDelay(pdMS_TO_TICKS(2000));
}
}

C++ Example

Dhyara is primarily intended to be used for C++ application. To build a C++ application with ESP-IDF we first start from a main.c which calls a C++ function mainx(). Following is the main.c from the example hello-cxx

void app_main(){
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(dhyara_init(WIFI_MODE_AP));
mainx(); // Enter C++
}

The mainx() is declared and gaurded by extern C{} block in the mainx.h, so that it can be included from c as well as C++. Following is the definition of mainx() which can be found in the mainx.cpp in the hello-cxx example project.

void mainx(){
dhyara::network network(dhyara_link());
dhyara_set_default_network(&network);
dhyara::peer_address sink("4c:11:ae:9c:a6:85"), source("4c:11:ae:71:0f:4d");
dhyara::peer_address local = dhyara_local();
dhyara::peer_address other = (local == source) ? sink : ((local == sink) ? source : dhyara::peer_address::null());
// The anonymous function will be called once all chunks of a data packet is received
dhyara_receive_data([](const dhyara::peer::address& source, const dhyara::packets::data& data){
std::cout << "received data " << " originating from " << data.source() << " via " << source << " of size " << data.length() << std::endl;
});
while(1){
if(!other.is_null()){
dhyara_ping(other, 1, 10);
std::string buffer = "Hello World";
dhyara_send(other, buffer.begin(), buffer.end());
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
dhyara_receive_data
bool dhyara_receive_data(dhyara_receive_data_callback_type callback)
Sets a callback on the default networks on_data.
dhyara::packets::data
A virtual packet, that is never sent accros the network.
Definition: data.h:27
dhyara_receivef
bool dhyara_receivef(dhyara_receivef_callback_t callback)
Callback for dhyara_receivef.
dhyara::packets::data::source
const dhyara::address & source() const
source of the data packet
Definition: data.h:76
dhyara_ping
bool dhyara_ping(const unsigned char *target, count=254, batch=1, sleep=15)
pings target with the configuration provided as designated initializers
dhyara_traceroute
bool dhyara_traceroute(const unsigned char *target)
Run traceroute on target.
dhyara::packets::data::length
std::size_t length() const
length of the data packet
Definition: data.h:92
dhyara_local
bool dhyara_local(unsigned char *address)
gets the mac address of self
dhyara::network
The dhyara ad-hoc network.
Definition: network.h:31
dhyara_init
esp_err_t dhyara_init(wifi_mode_t mode)
Initializes wifi, starts wifi, then initializes ESP Now.
dhyara_start_default_network
void dhyara_start_default_network()
Starts the default network.
dhyara_send
bool dhyara_send(const unsigned char *target, const void *data, unsigned long len)
Send a variable length data as data packet to the destination over multi hop network.