Loramesher库实现了距离矢量路由协议,用于在Lora节点之间传达消息。对于与Lora无线电芯片的互动,我们利用Radiolib,这是一个多功能通信库,支持不同的Lora系列模块。
目前,Loramesher已在以下模块中进行了测试:
您可以通过打开一个问题请求将另一个模块添加到库中。
您可以查看library.json以获取更多详细信息。基本上,我们使用Radiolib将低级通信与不同的LORA模块和Freertos实现,以安排维护任务。
在第一个实现的源文件中,有一个测试新功能的示例。此示例是计数器的实现,每10秒发送一次广播消息。为了使更容易理解,我们将删除使MicroController与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()它将为您提供t数量的有效载荷大小radio.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()迭代。这将使我们知道给定数据包中有效载荷有多大。在我们的情况下,我们总是只发送一个数据包装。printPacket(dPacket[i])功能,该功能将打印收到的计数器。 请参阅我们的开放式访问论文“实施洛拉网格库”,以获取详细说明。如果您在学术工作中使用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}}