Skip to content

Commit 14a32d6

Browse files
Implement dynamic neighbors count (#69)
* Duplicate `rafting-button` project * Remove README description * Update SDK config file for new SDK version * Define SDK path * Define project goal * Describe implementation plan * Preload more files * Fix typo * Change device IDs * Update header file definition * Update check neighbor calculation * Update `espnow_data_parser` * Update `espnow_data_prepare` function * Update sending callback processing * Map related files * Define header for `get_message_type` function * Commented code related to NEIGHBORS message type * Add `espnow` word into workspace dictionary * Allocate memory for `espnow_send_neighbor_param_t` * Implement function `espnow_data_neighbor_prepare` to prepare data * Implement send info about inactive device * Implement function to get neighbor check number * Implement function for sending neighbor message * Implement espnow_data_neighbor_parse function * Implement parsing incoming NEIGHBORS message * Rename send_neighbor_message to send_neighbor_message_to_all * Implement response for HELLO_DS message * Add task as a note * Remove neighbor handling in standard case cycle * Implement dynamic neighbor for all functions * Fix pointer typing error * Add C associations file * Unify `espnow_data_parse` function header * Fix struct pointer problem * Fix struct name bug * Fix passing parameter * Fix passing parameter * Add missing esp_err_t ret variable * Fix do not free using memory * Remove epoch message skipper * Define SDK version & debug stackoverflow * Restore new header definition * Fix stack size problem * Remove old README file * Update README file * Optimised images with calibre/image-actions --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent f49e767 commit 14a32d6

22 files changed

+7932
-135
lines changed

code/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ Softwarová implementace.
22

33
## Seznam projektů
44

5+
- `dynamic-neighbors` - implementac v rámci předmětu DSV, která umožňuje dynamický počet sousedů
56
- `esp-now-parameters` - měření latence ESP-NOW na ESP32
67
- `hello-world` - testovací kód na ESP32S2
78
- `measure-esp-now` - měření síťové infratruktury na ESP32S2

code/dynamic-neighbors/.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.vscode/*
2+
doc/html/*
3+
doc/latex/*
4+
# Created by https://www.toptal.com/developers/gitignore/api/cmake
5+
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
6+
7+
### CMake ###
8+
CMakeLists.txt.user
9+
CMakeCache.txt
10+
CMakeFiles
11+
CMakeScripts
12+
Testing
13+
Makefile
14+
cmake_install.cmake
15+
install_manifest.txt
16+
compile_commands.json
17+
CTestTestfile.cmake
18+
_deps
19+
build/
20+
21+
### CMake Patch ###
22+
# External projects
23+
*-prefix/
24+
25+
## ESP-IDF
26+
*.old
27+
dependencies.lock
28+
managed_components
29+
30+
# End of https://www.toptal.com/developers/gitignore/api/cmake

code/dynamic-neighbors/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# For more information about build system see
2+
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
3+
# The following five lines of boilerplate have to be in your project's
4+
# CMakeLists in this exact order for cmake to work correctly
5+
cmake_minimum_required(VERSION 3.16)
6+
7+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8+
project(rafting-button)

code/dynamic-neighbors/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Hlasovací zařízení řešící koncenzus v distribuovaném systému
2+
3+
> [!NOTE]
4+
> Generovano pomoc chatGPT z report.pdf
5+
6+
## Úvod
7+
8+
Cílem projektu bylo zrobustnit algoritmus, který obsluhuje distribuovanou síť tvořenou hlasovacími zařízeními. Konkrétně bylo cílem ošetřit chybové stavy a navrhnout a implementovat přístup, který zajistí, že v síti bude moci být připojeno 1–N zařízení.
9+
10+
Síť je postavena na zařízeních ESP32, která jsou propojena pomocí protokolu ESP-NOW. Tento protokol spojuje horních pět vrstev OSI modelu do jedné, zvané ESP-NOW. Protokol má určité limity, jako je počet sousedů (maximálně 20 nešifrovaných) a velikost zprávy (maximálně 250 B). Tyto limity bylo nutné zohlednit při návrhu a implementaci.
11+
12+
13+
## Algoritmus a implementace
14+
15+
Algoritmus tvoří tři základní komponenty:
16+
17+
1. Registrace zařízení do distribuované sítě (DS)
18+
2. Běžný chod a terminace zařízení
19+
3. Synchronizace času, distribuce logů a seznamu zařízení
20+
21+
### Registrace zařízení
22+
23+
Po spuštění zařízení odešle broadcast zprávu typu `HELLO_DS`. Ostatní zařízení v síti si jej přidají do seznamu sousedů a odešlou zprávu typu `NEIGHBOURS` s informacemi o DS (např. ID epochy). Pokud zařízení obdrží více než polovinu odpovědí, přechází do další fáze – běžného chodu DS.
24+
25+
### Běžný chod
26+
27+
Každá epocha má dvě fáze:
28+
29+
1. **Volba lídra**: Probíhá podobně jako v algoritmu Raft. Lídr synchronizuje čas pomocí zpráv typu `TIME`. Pokud zařízení neobdrží zprávu do určitého timeoutu, spustí nové volby.
30+
2. **Běžný provoz**: Lídr distribuuje logy, seznamy sousedů a synchronizační zprávy. Pokud dojde k selhání zařízení, uživatel je informován o stavu.
31+
32+
#### Role zařízení
33+
34+
- **Lídr (MASTER)**: Rozesílá logy, seznamy sousedů a synchronizuje čas.
35+
- **Následovník (SLAVE)**: Pasivní zařízení.
36+
- **Kandidát**: Přechodná role během volby lídra.
37+
38+
### Terminace zařízení
39+
40+
Zařízení, které nepřijme více než tři zprávy úspěšně, je označeno jako neaktivní a terminováno z DS. Tato informace je poté rozeslána do celé sítě.
41+
42+
### Přizpůsobení dynamickému počtu sousedů
43+
44+
- **Ukládání dat**: Použit statický způsob ukládání sousedů (20 × 16 bytes) kvůli menší chybovosti a nižší výpočetní zátěži.
45+
- **Struktura packetu**: Přidán checksum typu `uint32_t`, reprezentující stav sousedů.
46+
- **Nový typ zprávy**: Zpráva obsahující seznam sousedů rozdělena na dvě části kvůli limitu velikosti zprávy.
47+
48+
![Ukázka testování provozu](measure-set.jpg)
49+
50+
51+
## Spuštění kódu
52+
53+
Pro spuštění kódu je třeba mít nainstalovaný framework `esp-idf`.
54+
55+
```bash
56+
# Klonování repozitáře esp-idf
57+
git clone https://github.com/espressif/esp-idf.git
58+
# Přepnutí na vhodný release (testováno na v5.4)
59+
cd esp-idf
60+
./install.bat # Nebo jiný vhodný instalátor pro použitý systém
61+
```
62+
63+
### Kompilace a flashování
64+
65+
Pro kompilaci a flashování kódu:
66+
67+
```bash
68+
idf.py reconfigure # Stažení a instalace komponent ESP-NOW
69+
idf.py build
70+
idf.py flash
71+
idf.py monitor
72+
```
73+
74+
Doporučuje se nastavit automatické spuštění exportu. Při použití připraveného VSCode prostředí a správné konfiguraci cesty k esp-idf knihovně se export spustí automaticky při otevření terminálu.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRCS "espnow_utils.c"
2+
INCLUDE_DIRS "."
3+
REQUIRES esp_wifi esp_wifi peripheral)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @file espnow_utils.c
3+
* @brief Contains supported functions for the ESP-NOW protocol.
4+
* @details This file provides functions for initializing and deinitializing
5+
* ESP-NOW, initializing Wi-Fi, printing the device's MAC address, and comparing
6+
* MAC addresses.
7+
* @version 1.0
8+
* @date 2023-06-08
9+
* @author Petr Kucera ([email protected])
10+
*
11+
* @note This code is subject to the terms of the MIT license.
12+
*
13+
*/
14+
15+
#include "espnow_utils.h"
16+
#include "peripheral.h"
17+
#include <esp_log.h>
18+
#include <esp_mac.h>
19+
#include <esp_now.h>
20+
#include <esp_wifi.h>
21+
#include <freertos/FreeRTOS.h>
22+
#include <freertos/task.h>
23+
24+
#define TRUE 1
25+
#define FALSE 0
26+
27+
static const char *TAG = "ESPNOW_UTILS";
28+
29+
void wifi_init(void)
30+
{
31+
// 1. Initialize TCP/IP stack layer
32+
ESP_ERROR_CHECK(esp_netif_init());
33+
34+
// 2. Create a loop for system tasks like Wi-Fi
35+
ESP_ERROR_CHECK(esp_event_loop_create_default());
36+
37+
// 3. Initialize Wi-Fi with default configuration
38+
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
39+
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
40+
41+
// 4. Set storage
42+
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
43+
44+
// 5. Set current WiFi power save type
45+
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
46+
47+
// 6. Set Wi-Fi mode
48+
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
49+
ESP_ERROR_CHECK(esp_wifi_start());
50+
// ESP_ERROR_CHECK(esp_wifi_set_channel())
51+
}
52+
53+
esp_err_t custom_espnow_init(void)
54+
{
55+
// Initialize ESP-NOW
56+
ESP_ERROR_CHECK(esp_now_init());
57+
58+
return ESP_OK;
59+
}
60+
61+
esp_err_t custom_espnow_deinit(void)
62+
{
63+
ESP_ERROR_CHECK(esp_now_deinit());
64+
65+
return ESP_OK;
66+
}
67+
68+
void print_mac_address()
69+
{
70+
uint8_t mac_addr[6];
71+
ESP_ERROR_CHECK(esp_read_mac(mac_addr, ESP_MAC_BASE));
72+
ESP_LOGI(TAG, "Device MAC address is: " MACSTR "\n", MAC2STR(mac_addr));
73+
}
74+
75+
uint8_t is_device_mac(uint8_t *mac_addr)
76+
{
77+
uint8_t tmp[6];
78+
ESP_ERROR_CHECK(esp_read_mac(tmp, ESP_MAC_BASE));
79+
for (uint8_t i = 0; i < 6; ++i) {
80+
if (tmp[i] != mac_addr[i])
81+
return FALSE;
82+
}
83+
return TRUE;
84+
}
85+
86+
uint8_t is_same_mac(uint8_t *mac_1, uint8_t *mac_2)
87+
{
88+
for (uint8_t i = 0; i < ESP_NOW_ETH_ALEN; ++i) {
89+
if (mac_1[i] != mac_2[i])
90+
return FALSE;
91+
}
92+
return TRUE;
93+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @file espnow_utils.h
3+
* @brief Contains functions for working with the ESP-NOW protocol.
4+
* @details This file provides functions for initializing and deinitializing
5+
* ESP-NOW, initializing Wi-Fi for ESP-NOW, printing the device's MAC address,
6+
* and comparing MAC addresses.
7+
* @version 1.0
8+
* @date 2023-06-08
9+
* @author Petr Kucera ([email protected])
10+
*
11+
* @note This code is subject to the terms of the MIT license.
12+
*
13+
*/
14+
15+
#ifndef ESPNOW_UTILS_H
16+
#define ESPNOW_UTILS_H
17+
18+
#include "peripheral.h"
19+
#include <esp_now.h>
20+
#include <esp_types.h>
21+
#include <esp_wifi.h>
22+
#include <freertos/FreeRTOS.h>
23+
#include <freertos/task.h>
24+
25+
/**
26+
* @brief Initializes Wi-Fi for ESP-NOW.
27+
*/
28+
void wifi_init(void);
29+
30+
/**
31+
* @brief Initializes ESP-NOW.
32+
* @return esp_err_t The result of the initialization.
33+
*/
34+
esp_err_t custom_espnow_init(void);
35+
36+
/**
37+
* @brief Deinitializes ESP-NOW.
38+
* @return esp_err_t The result of the deinitialization.
39+
*/
40+
esp_err_t custom_espnow_deinit(void);
41+
42+
/**
43+
* @brief Prints the MAC address of the device.
44+
*/
45+
void print_mac_address();
46+
47+
/**
48+
* @brief Compares the device's MAC address with the provided address.
49+
* @param mac_addr The MAC address to compare with the device's address.
50+
* @return uint8_t Logic value indicating if the addresses match (1 - true, 0 -
51+
* false).
52+
*/
53+
uint8_t is_device_mac(uint8_t *mac_addr);
54+
55+
/**
56+
* @brief Compares two MAC addresses.
57+
* @param mac_1 The first MAC address to compare.
58+
* @param mac_2 The second MAC address to compare.
59+
* @return uint8_t Logic value indicating if the addresses match (1 - true, 0 -
60+
* false).
61+
*/
62+
uint8_t is_same_mac(uint8_t *mac_1, uint8_t *mac_2);
63+
64+
#endif // ESPNOW_UTILS_H
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRCS "peripheral.c"
2+
INCLUDE_DIRS "."
3+
REQUIRES driver)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @file peripheral.c
3+
* @brief Contains functions for basic manipulation with peripherals.
4+
* @version 1.0
5+
* @date 2023-06-08
6+
* @author Petr Kucera ([email protected])
7+
*
8+
* @note This code is subject to the terms of the MIT license.
9+
*
10+
*/
11+
12+
#include "peripheral.h"
13+
#include <driver/gpio.h>
14+
#include <freertos/FreeRTOS.h>
15+
#include <freertos/task.h>
16+
#include <stdio.h>
17+
18+
void config_led(gpio_num_t gpio_num)
19+
{
20+
// Set up GPIO direction as output
21+
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
22+
}
23+
24+
void turn_on_led(gpio_num_t gpio_num)
25+
{
26+
// Set GPIO output level to HIGH (1)
27+
gpio_set_level(gpio_num, 1);
28+
}
29+
30+
void turn_off_led(gpio_num_t gpio_num)
31+
{
32+
// Set GPIO output level to LOW (0)
33+
gpio_set_level(gpio_num, 0);
34+
}
35+
36+
void turn_on_buildin_led()
37+
{
38+
gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT);
39+
gpio_set_level(GPIO_NUM_2, 1);
40+
}
41+
42+
void turn_off_buildin_led() { gpio_set_level(GPIO_NUM_2, 0); }
43+
44+
void do_blink_task(uint16_t mils)
45+
{
46+
config_led(GPIO_NUM_23);
47+
turn_on_led(GPIO_NUM_23);
48+
turn_on_buildin_led();
49+
50+
vTaskDelay(mils / portTICK_PERIOD_MS);
51+
52+
turn_off_led(GPIO_NUM_23);
53+
turn_off_buildin_led();
54+
55+
vTaskDelete(NULL);
56+
}
57+
58+
void do_blink(uint16_t mils)
59+
{
60+
turn_on_led(GPIO_NUM_23);
61+
turn_on_buildin_led();
62+
63+
vTaskDelay(mils / portTICK_PERIOD_MS);
64+
65+
turn_off_led(GPIO_NUM_23);
66+
turn_off_buildin_led();
67+
}
68+
69+
void turn_on_led_task(gpio_num_t gpio_num)
70+
{
71+
turn_on_buildin_led();
72+
turn_on_led(gpio_num);
73+
vTaskDelete(NULL);
74+
}
75+
76+
void turn_off_led_task(gpio_num_t gpio_num)
77+
{
78+
turn_off_buildin_led();
79+
turn_off_led(gpio_num);
80+
vTaskDelete(NULL);
81+
}

0 commit comments

Comments
 (0)