Loading...
Searching...
No Matches
lorapub.c
1/**************************************************************************************************
2 * @file loracomm.c *
3 * @brief Implements the FreeRTOS tasks and Interrupt Service Routine (ISR) *
4 * responsible for managing LoRa communication. *
5 * *
6 * This file contains the implementation for LoRa transmit and receive tasks. It utilizes a *
7 * publication topic (`loraTopic`) to interface with other parts of the application. *
8 * *
9 * The transmit task waits for messages on the topic's queue and transmits them via the LoRa *
10 * transceiver *
11 * *
12 * The receive task waits for notifications from the ISR (indicating a received packet), reads *
13 * the data from the transceiver, and publishes it to the topic. *
14 * *
15 * The `EXTI1_IRQHandler` handles interrupts from the LoRa module (e.g., Tx Done, Rx Done), *
16 * notifying the appropriate task to proceed. *
17 * *
18 * @{ *
19 **************************************************************************************************/
20
21#include "AustralisConfig.h"
22#include "lorapub.h"
23
24#include "stm32f439xx.h"
25
26#include "FreeRTOS.h"
27#include "event_groups.h"
28#include "message_buffer.h"
29#include "queue.h"
30
31#include "_topic.h"
32#include "gpiopin.h"
33#include "lora.h"
34
35// Create publication topic for LoRa data
36//
37// NOTE:
38// This topic is exposed for reader
39// comments in the public header.
40CREATE_TOPIC(lora, 200, LORA_MSG_LENGTH)
41Topic *loraTopic = (Topic *)&lora;
42
43static TaskHandle_t vLoRaTransmitHandle;
44static TaskHandle_t vLoRaReceiveHandle;
45
46// LoRa transceiver device
47//
48// TODO:
49// Add deviceReady flag to driver API to indicate
50// when a device struct is initialised and populated
51static LoRa_t *transceiver;
52void LoRa_setTransceiver(LoRa_t *transceiver_) {
53 transceiver = transceiver_;
54}
55LoRa_t *LoRa_getTransceiver() { return transceiver; }
56
57// Optional switch for RF frontend
58static GPIOpin_t *rfToggle;
59void LoRa_setRfToggle(GPIOpin_t *rfToggle_) {
60 rfToggle = rfToggle_;
61}
62
63/* ============================================================================================== */
73void vLoRaTransmit(void *argument) {
74 const TickType_t blockTime = portMAX_DELAY;
75 CREATE_MESSAGE(txData, LORA_MSG_LENGTH);
76
77 vLoRaTransmitHandle = xTaskGetCurrentTaskHandle();
78
79 for (;;) {
80 // Don't operate unless transceiver is ready
81 if (transceiver == NULL)
82 continue;
83
84 // Wait to receive message to transmit
85 BaseType_t result = WAIT_COMMENT(
86 lora.public.commentInbox, // Read from LoRa topic comment queue
87 &txData, // Store data in binary array
88 portMAX_DELAY // Block forever until comment is available
89 );
90
91 // Transmit data if successfully retrieved from queue
92 if (result == pdTRUE) {
93
94 if (rfToggle)
95 // Toggle RF front-end for transmit
96 rfToggle->reset(rfToggle);
97
98 // Send data to transmit
99 transceiver->transmit(transceiver, txData.data, txData.length);
100
101 // Wait for notification from ISR
102 xTaskNotifyWaitIndexed(1, 0, 0, NULL, blockTime);
103
104 if (rfToggle)
105 // Toggle RF front-end for receive
106 rfToggle->set(rfToggle);
107
108 // Continue receiving
109 transceiver->startReceive(transceiver);
110 }
111 }
112}
113
114/* ============================================================================================== */
125void vLoRaReceive(void *argument) {
126 const TickType_t blockTime = portMAX_DELAY;
127
128 CREATE_MESSAGE(rxData, LORA_MSG_LENGTH);
129
130 vLoRaReceiveHandle = xTaskGetCurrentTaskHandle();
131
132 for (;;) {
133 // Don't operate unless transceiver is ready
134 if (transceiver == NULL)
135 continue;
136
137 // Wait for notification from ISR
138 xTaskNotifyWaitIndexed(1, 0, 0, NULL, blockTime);
139
140 // Read received packet from transceiver
141 rxData.length = transceiver->readReceive(transceiver, rxData.data, LORA_MSG_LENGTH);
142
143 // Publish packet data to topic
144 Topic_publish((PrivateTopic *)loraTopic, (uint8_t *)&rxData);
145 }
146}
147
148/* ============================================================================================== */
157void pubLoraInterrupt(void) {
158 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
159
160 // Exit if transceiver is not ready
161 if (transceiver == NULL)
162 goto LORA_NOT_READY;
163
164 TaskHandle_t activeHandle = NULL;
165
166 // Assign currently task handle for operation
167 if (transceiver->currentMode == LORA_MODE_TX) {
168 activeHandle = vLoRaTransmitHandle;
169 } else if (transceiver->currentMode == LORA_MODE_RX) {
170 activeHandle = vLoRaReceiveHandle;
171 }
172
173 // Exit if not initialised
174 if (activeHandle == NULL)
175 goto LORA_NOT_READY;
176
177 // Notify active task for unblock
178 xTaskNotifyIndexedFromISR(activeHandle, 1, 0, eNoAction, &xHigherPriorityTaskWoken);
179 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
180
181LORA_NOT_READY:
182 // Clean-up and exit
183 // TODO: Implement specific clear methods for
184 // Tx and Rx IRQs for better abstraction
185 transceiver->clearIRQ(transceiver, 0xFF);
186}
187
bool Topic_publish(PrivateTopic *topic, uint8_t *article)
Publish an "article" to all discovered subscribers of a topic.
Definition topic.c:74
#define CREATE_TOPIC(topic, commentInboxSize, messageSize)
Macro to define and initialize a topic instance.
Definition _topic.h:60
Internal representation of a Topic instance.
Definition _topic.h:73
Definition lora.h:30
Struct definition for a GPIO pin.
Definition gpiopin.h:151
Defines the API for LoRa communication.
#define CREATE_MESSAGE(name, length_)
Macro to define, on the stack, a named message struct.
Definition topic.h:59
Public representation of a Topic.
Definition topic.h:71