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}}