Библиотека Loramesher реализует протокол маршрутизации дистанционного вектора для передачи сообщений среди узлов LORA. Для взаимодействия с радиопрометом Lora мы используем Radiolib, универсальную библиотеку связи, которая поддерживает различные модули серии Lora.
В этот момент Loramesher был протестирован в следующих модулях:
Вы можете запросить еще один модуль, чтобы быть добавленным в библиотеку, открыв проблему.
Вы можете проверить library.json для получения более подробной информации. По сути, мы используем радиолиб, который реализует низкоуровневую связь с различными модулями LORA и Freertos для планирования задач обслуживания.
В исходных файлах этой первой реализации пример для проверки новых функций. Этот пример является реализацией счетчика, отправляющей вещательное сообщение каждые 10 секунд. Чтобы упростить понимание, мы удалим дополнительные функции, которые не необходимы, чтобы микроконтроллер работал с библиотекой Loramesher.
В качестве доказательства концепции мы отправим числовое счетчик над Лорой. Его значение будет увеличено каждые 10 секунд, а затем будет передаваться пакет TE. Для начала нам нужно реализовать тип данных, которые мы будем использовать.
В этом случае мы отправим только uint32_t , который является самим счетчиком.
uint32_t dataCounter = 0;
struct dataPacket {
uint32_t counter = 0;
};
dataPacket* helloPacket = new dataPacket;
Чтобы инициализация новой реализации, вы можете настроить параметры LORA, которые будет использовать библиотеку. Если ваш узел должен получать сообщения в приложение, см. Раздел функции полученных пакетов.
Вы можете настроить различные параметры для конфигурации LORA. Используя LoRaMesherConfig , вы можете настроить следующие параметры (обязательно*):
Вот пример того, как настроить Loramesher, используя эту конфигурацию:
//Get the LoraMesher instance
LoraMesher& radio = LoraMesher::getInstance();
//Get the default configuration
LoraMesher::LoraMesherConfig config = LoraMesher::LoraMesherConfig();
//Change some parameters to the configuration
//(TTGO T-Beam v1.1 pins)
config.loraCS = 18
config.loraRst = 23
config.loraIrq = 26
config.loraIo1 = 33
config.module = LoraMesher::LoraModules::SX1276_MOD;
//Initialize the LoraMesher. You can specify the LoRa parameters here or later with their respective functions
radio.begin(config);
//After initializing you need to start the radio with
radio.start();
//You can pause and resume at any moment with
radio.standby();
//And then
radio.start();
Имейте в виду местные законы, которые применяются к радиочастотам
Если ваш узел должен получать пакеты из других узлов, вы должны выполнить следующие шаги:
Функция, которая получает уведомление каждый раз, когда библиотека получает пакет для приложения, выглядит так:
/**
* @brief Function that process the received packets
*
*/
void processReceivedPackets(void*) {
for (;;) {
/* Wait for the notification of processReceivedPackets and enter blocking */
ulTaskNotifyTake(pdPASS, portMAX_DELAY);
//Iterate through all the packets inside the Received User Packets FiFo
while (radio.getReceivedQueueSize() > 0) {
Serial.println("ReceivedUserData_TaskHandle notify received");
Serial.printf("Queue receiveUserData size: %dn", radio.getReceivedQueueSize());
//Get the first element inside the Received User Packets FiFo
AppPacket<dataPacket>* packet = radio.getNextAppPacket<dataPacket>();
//Print the data packet
printDataPacket(packet);
//Delete the packet when used. It is very important to call this function to release the memory of the packet.
radio.deletePacket(packet);
}
}
}
Есть некоторые важные вещи, о которых мы должны знать:
void* в параметрах.ulTaskNotifyTake(pdPASS,portMAX_DELAY) или эквивалент. Эта функция позволяет библиотеке уведомить функцию об обработке ожидающих пакетов.radio.getReceivedQueueSize() .radio.getNextAppPacket<T>() , где t - тип ваших данных.radio.deletePacket(packet) . Это освободит память, которая была выделена для пакета. Если не выполнить, это может вызвать утечки памяти и ошибки памяти. TaskHandle_t receiveLoRaMessage_Handle = NULL;
/**
* @brief Create a Receive Messages Task and add it to the LoRaMesher
*
*/
void createReceiveMessages() {
int res = xTaskCreate(
processReceivedPackets,
"Receive App Task",
4096,
(void*) 1,
2,
&receiveLoRaMessage_Handle);
if (res != pdPASS) {
Serial.printf("Error: Receive App Task creation gave error: %dn", res);
}
}
radio.setReceiveAppDataTaskHandle(receiveLoRaMessage_Handle);
В этом разделе мы покажем вам, что есть в AppPacket .
class AppPacket {
uint16_t dst; //Destination address, normally it will be local address or BROADCAST_ADDR
uint16_t src; //Source address
uint32_t payloadSize = 0; //Payload size in bytes
T payload[]; //Payload
size_t getPayloadLength() { return this->payloadSize / sizeof(T); }
};
Функциональные возможности для использования после получения пакета с помощью AppPacket<T>* packet = radio.getNextAppPacket<T>() :
packet->getPayloadLength() он принесет вам размер полезной нагрузки по количеству tradio.deletePacket(packet) Он выпустит память, выделенную для этого пакета. В этом разделе мы представим, как вы можете создавать и отправлять пакеты. В этом примере мы будем использовать структуру данных AppPacket .
void loop() {
helloPacket->counter = dataCounter++;
//Create packet and send it.
radio.createPacketAndSend(BROADCAST_ADDR, helloPacket, 1);
//Or if you want to send large and reliable payloads you can call this function too.
radio.sendReliable(dstAddr, helloPacket, 1);
//Wait 10 seconds to send the next packet
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
На предыдущей фигуре мы видим, что мы используем Hellopacket, мы добавляем счетчик в него и создаем и отправляем пакет с помощью Loramesher.
Наиболее важной частью этого фрагмента кода является функция, которую мы называем в radio.createPacketAndSend() :
При получении пакета мы должны понять, что нас вернет. По этой причине, в следующем подразделе, мы объясним, как реализовать простую обработку пакетов.
/**
* @brief Print the counter of the packet
*
* @param data
*/
void printPacket(dataPacket data) {
Serial.printf("Hello Counter received n %dn", data.counter);
}
/**
* @brief Iterate through the payload of the packet and print the counter of the packet
*
* @param packet
*/
void printDataPacket(AppPacket<dataPacket>* packet) {
//Get the payload to iterate through it
dataPacket* dPacket = packet->payload;
size_t payloadLength = packet->getPayloadLength();
for (size_t i = 0; i < payloadLength; i++) {
//Print the packet
printPacket(dPacket[i]);
}
}
processReceivedPackets() мы называем функцию printDataPacket() .packet->payload .packet->getPayloadLength() . Это даст нам знать, насколько большая полезная нагрузка, в типах данных, для данного пакета. В нашем случае мы всегда отправляем только один DataPacket.printPacket(dPacket[i]) , которая будет распечатать полученный счетчик. Пожалуйста, см. В нашу бумагу с открытым доступом «Реализация библиотеки сетки Lora» для подробного описания. Если вы используете библиотеку Loramesher, в академической работе, пожалуйста, укажите следующее:
@ARTICLE{9930341,
author={Solé, Joan Miquel and Centelles, Roger Pueyo and Freitag, Felix and Meseguer, Roc},
journal={IEEE Access},
title={Implementation of a LoRa Mesh Library},
year={2022},
volume={10},
number={},
pages={113158-113171},
doi={10.1109/ACCESS.2022.3217215}}