L14-Click 1.0
STM32WLE5CC LoRaWAN Sensor Platform
Loading...
Searching...
No Matches
mylora_process.c
Go to the documentation of this file.
1/*
2 * mylora_process.c
3 *
4 * Created on: 18. 1. 2026
5 * Author: Milan
6 */
7
8#include "mylora_process.h"
9#include "main.h"
10#include "rtc.h"
11#include "mysensors.h"
12#include "mysensors_base.h"
13#include "sys_app.h"
14#include "stm32_seq.h"
15#include "lora_app.h"
16#include "mymems.h"
17#include "CayenneLpp.h"
18#include "LoRaMac.h"
19#include "nfc.h"
20#include "i2c.h"
21#include "adc_if.h"
22#include <stdio.h>
23
24#define MAX_NOACKREPEATCOUNT 3 // max, because of bitfield :4
25// LoRaWAN data formattin
26
27/**
28 * @brief anonymous global struct for saving of current mylorawan data flow
29 */
30static struct
31{
32 uint8_t MyloraWanAppBit :4; /**< Sequencer bits, CFG_SEQ_Task_MyLora, CFG_SEQ_Task_MyLoraReconect, CFG_SEQ_Task_MyLoraResend - !!! max 4 bits !!! */
33 uint8_t ConnectedCount :5; /**< the connection counter for repeating reconnect after NoAckRepeatCount falled on 0 - max 32, _systemParams.LoRaRepeatTryConnect */
34 uint8_t NoAckRepeatCount :4; /**< the count of repeating to resend data in case if no ACK comes from gateway - max 16 - default */
35 uint8_t IsDataSending :1; /**< data is in process of sending, the memory is blocked, until IsDataSending is ON */
36 uint8_t IsMeasureQueued :1; /**< the measure has been finished, but _IsDataSending is ON and memory is blocked, so current measurement is queued */
37 uint8_t IsConnected :1; /**< the connection to gateway is ON/OFF */
38 uint8_t CurrentSendingDataBuffer[256]; /**< buffer for sending data - max 222, with reserve */
39 uint8_t CurrentSendingDataSz; /**< the count of data in buffer */
40 int8_t FromEndInx :5; /**< the index from end of memory to send data in case if _systemParams.SendInOnePacket - more data in one pack */
41 uint8_t AckFromServer :1; /**< the ACK from server came, data can be processed */
42 loraWanPort_t LoraWanPort; /**< the port for data sending */
43 // ------ additional data processing of request
44 uint16_t DataSendSz; /**< the size of buffer to send, the last buffer is send with port LoraWanPort+1 */
45 uint16_t DataSendInx; /**< the index into DataSendBuffer from the context is copying */
46 const uint8_t *DataSendBuffer; /**< pointer to data for send - if not null, this buffer is processed */
47} _ = {};
48
50{
51 _.DataSendBuffer = NULL;
52 _.DataSendInx = _.DataSendSz = 0;
53 _.LoraWanPort = _systemParams.LoRaPort;
54}
55
56/**
57 * @brief Get the maximum application payload size for the current data rate.
58 * Returns 0 if the query fails or channel is not available.
59 */
60static uint8_t myLoRaWAN_GetMaxPayloadSize(void)
61{
62 LoRaMacTxInfo_t txInfo;
63 LoRaMacStatus_t status = LoRaMacQueryTxPossible(0, &txInfo);
64
65 return (status == LORAMAC_STATUS_OK) ? txInfo.MaxPossibleApplicationDataSize : 51; // 51max
66}
67
68/**
69 * @brief Reconnect to LoRa gateway. In case is measure data are queued, the myloraWan_MeasureFinish is called via sequencer to process current measure data
70 */
72{
73 _.IsConnected = 0; // reconnect - the sending has been canceled
74 _.IsDataSending = 0;
75 _.AckFromServer = 0;
76 if (LORAMAC_HANDLER_SUCCESS != LmHandlerStop())
77 {
78 writeLog("myLoraWan_Reconnect Stop on going ...");
79 }
80 else
81 {
82 writeLog("myLoraWan_Reconnect Start join");
83 LmHandlerJoin(LORAWAN_DEFAULT_ACTIVATION_TYPE, true);
84 }
85 if (_.IsMeasureQueued)
86 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 0), CFG_SEQ_Prio_0); // myloraWan_MeasureFinish, the measure is queued, must be finished
87}
88
89/**
90 * @brief StartReconnect - processing of myLoraWan_Reconnect via sequencer in case ConnectedCount is not falled on 0
91 */
93{
94 writeLog("myLoraWan_StartReconnect - count:%d", (int) _.ConnectedCount);
95 if (_.ConnectedCount)
96 {
97 UTIL_SEQ_SetTask((1 << (_.MyloraWanAppBit + 1)), CFG_SEQ_Prio_0); // myLoraWan_Reconnect
98 _.ConnectedCount--;
99 }
100}
101
102/**
103 * @brief Send confirmed data to LoRaWAN network
104 *
105 * This function sends data that requires acknowledgment from the server.
106 * The server must respond with a downlink acknowledgment. This is useful
107 * for critical data that must be verified as received.
108 *
109 * @param data Pointer to the data buffer to send
110 * @param dataSize Size of the data in bytes (max 242 bytes)
111 * @param port LoRaWAN application port (typically 2)
112 * @return LmHandlerErrorStatus_t Status of the send operation
113 * - LORAMAC_HANDLER_SUCCESS: Data queued for transmission with confirmation
114 * - LORAMAC_HANDLER_ERROR: Failed to queue data
115 * - LORAMAC_HANDLER_BUSY_ERROR: MAC layer is busy
116 * - LORAMAC_HANDLER_NO_NETWORK_JOINED: Not connected to network
117 */
118static LmHandlerErrorStatus_t LoRaWAN_SendConfirmedData(uint8_t *data, uint8_t dataSize, uint8_t port)
119{
120 LmHandlerAppData_t appData;
121 LmHandlerErrorStatus_t status;
122
123 _.IsDataSending = 1; // in OnLoRaWANTxData is reset
124 _.AckFromServer = 0;
125
126 if (data == NULL || dataSize == 0 || dataSize > 242)
127 {
128 writeLog("Invalid data parameters");
129 return LORAMAC_HANDLER_ERROR;
130 }
131
132 appData.Buffer = data;
133 appData.BufferSize = dataSize;
134 appData.Port = port;
135
136 writeLog("Sending confirmed data to LoRaWAN: port=%d, size=%d bytes", port, dataSize);
137
138 // Send as confirmed message (requires ACK from server)
139 status = LmHandlerSend(&appData, LORAMAC_HANDLER_CONFIRMED_MSG, false);
140 switch (status)
141 {
142 case LORAMAC_HANDLER_SUCCESS:
143 writeLog("Confirmed data queued for transmission");
144 break;
145
146 case LORAMAC_HANDLER_NO_NETWORK_JOINED:
147 writeLog("Cannot send: Not joined to network");
148 break;
149
150 case LORAMAC_HANDLER_BUSY_ERROR:
151 writeLog("Cannot send: MAC layer busy");
152 break;
153
154 case LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED:
155 //myLoraWan_StartReconnect(); // try reconnect - This is arguably aggressive
156 // nothis to do, disconnected, the duty has been reached - defined as 1% from hour - 36seconds
157 // see: LORAMAC_STATUS_DUTYCYCLE_RESTRICTED
158 break;
159
160 default:
161 writeLog("Send failed with status: %d", status);
162 break;
163 }
164
165 return status;
166}
167
168/**
169 * @brief the preparing _currentSendingDataBuffer/_currentSendingDataSz from CayennelLpp to send data to LoRaWan gateway
170 * @param data - memory data block, sensors measured values
171 * @param reset - the sending buffer is reset or not(adding for _systemParams.SendInOnePacket == 1)
172 * @param maxSize - the max size of payload for current datarate, 0 - no buffer is checked
173 * @param prevMeasureTime - the time of previous block or 0, if time is unknown or is 1st
174 * @retval 1 - data stored in _currentSendingDataBuffer for send
175 * @retval 0 - not stored, the maximum buffer has been reached
176 */
177static uint8_t myloraWan_PrepareSendingBuffer(const mems_DataBlock_t *data, uint8_t reset, uint8_t maxSize, SysTime_t prevMeasureTime)
178{
179 uint8_t *ptr, sz, isOK = 1;
180
181 if (reset)
182 _.CurrentSendingDataSz = 0;
183
185 ptr = sensors_CayennelFromBckData(&sz, &prevMeasureTime);
186 isOK = (!maxSize || _.CurrentSendingDataSz + sz <= maxSize); // buffer cannot be longer than max, maxSize - 0, is not check
187 if (ptr != NULL && isOK)
188 {
189 memcpy(_.CurrentSendingDataBuffer + _.CurrentSendingDataSz, ptr, sz);
190 _.CurrentSendingDataSz += sz;
191 }
192 return isOK;
193}
194
195/**
196 * @brief the measure has been finished, sensor data save to memory or local buffer(in case if no memory is exist or is not storing set)
197 * @par
198 * <b>_currentSendingDataBuffer</b> - contains data \n
199 * <b>_currentSendingDataSz</b> - size of data in _currentSendingDataBuffer
200 *
201 * the task <b>myLoraWan_LastDataSend</b> is started for start of sending data LIFO direction \n
202 */
204{
205 mems_DataBlock_t *memsData;
206
207 if (_.IsDataSending)
208 {
209 writeLog("myloraWan_MeasureFinish - data is in sending, measure is queued...");
210 _.IsMeasureQueued = 1;
211 }
212 else
213 {
214 writeLog("myloraWan_MeasureFinish - begin, dataCount:%d", (int) _memsMainBlock.Data_CountCurrent);
215 //UTIL_SEQ_WaitEvt(_myloraWanAppBit); // waiting for event - fired from mysensors.c -> tasksensors_Work
216 //UTIL_SEQ_ClrEvt(_myloraWanAppBit);
217 //UTIL_SEQ_SetTask((1 << _myloraWanAppBit), CFG_SEQ_Prio_0); // pokracujem
218
219 memsData = mems_InicBuffer(MEMS_DATATYPE_SENSOR); // prepare working memory buffer
220 if (memsData != NULL)
221 {
222 sensors_CopyToBck(); // copy to backup
223 sensors_WriteFromBckToDataBlock(memsData); // write sensors to memory block from backup
224 memset(_.CurrentSendingDataBuffer, 0, sizeof(_.CurrentSendingDataBuffer)); // because of sharing - and save to NFC
225
226 // buffer sharing pattern
227 // current measure data must be saved in NFC EEPROM on address MEASUREDATANFC_ADDR
228 // because of save of memory here is used the same buffer(shared buffer) for payload for NFC and payload for LoraWan
229 // 1. payload moved on measureDataNFC_t.Data
230 measureDataNFC_t *blk = (measureDataNFC_t*) _.CurrentSendingDataBuffer; // shared buffer
231
232 SysTime_t tim = {}; // empty time - 0, no time is write in payload for current measuring
233
234 // _.CurrentSendingDataBuffer - will be contains:
235 // .UTCMeasureTime - the UTC measure time
236 // .Data - the payload from _.CurrentSendingDataBuffer
237
238 uint8_t addOff = blk->Data - (uint8_t*) blk; // offset address of Data in bytes
239
240 _.CurrentSendingDataSz = addOff; // payload is copy on blk->Data position
241 blk->UTCMeasureTime = sensors_GetTimeFromBlock(memsData).Seconds; // UTC time from measure data
242 myloraWan_PrepareSendingBuffer(memsData, 0, 0, tim); // no reset, no max buffer check and no time and copy the pyload on blk->Data
243
244 // nfc store
245 nfc_WriteMeasureData(&hi2c2, blk); // don't care about result here
246
247 // byte size decrees & copy data on valid position in _.CurrentSendingDataBuffer - ready for LoRaWan send or s
248 _.CurrentSendingDataSz -= addOff;
249 memcpy(_.CurrentSendingDataBuffer, _.CurrentSendingDataBuffer + addOff, _.CurrentSendingDataSz);
250
251 // if the save in memory is OK, the reset of sending data, because of packing process in myLoraWan_LastDataSend
252 // mems_AddData - is
253 if (_systemParams.MemsStoreSensorData && mems_AddData(NULL, 0, 0) == HAL_OK)
254 _.CurrentSendingDataSz = 0; // data stored in memory, will be again pickup in myLoraWan_LastDataSend depend on SendInOnePack
255
256 /*
257 // test only - add next
258 if (_memsMainBlock.Data_CountCurrent <= 1 && _systemParams.StoreSensorData)
259 {
260 int i, m = 10;
261 for (i = 0; i < m && mems_AddData(NULL, 0, 0) == HAL_OK; i++)
262 ;
263
264 writeLog("myloraWan_MeasureFinish - written %dx data, max:%d", i, m);
265 } // */
266 }
267
268 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 2), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend
269 writeLog("myloraWan_MeasureFinish - end");
270 _.IsMeasureQueued = 0;
271 }
272}
273
274/**
275 * @brief take data from LIFO - last data and send. Cannot be nested
276 * only if is LoRa connected
277 */
279{
280 if (_.IsConnected)
281 {
282 if (LoRaMacIsBusy()) // if loramac is busy - repeating, until the MAC is free
283 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 2), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend - but only if the measure is not queued
284 else
285 {
286
287 writeLog("myLoraWan_LastDataSend - begin");
288
289 if (_.IsDataSending == 0)
290 {
291 do // because of low voltage
292 {
293 /*
294 * the reading one(_systemParams.SendInOnePacket == 0) or more(_systemParams.SendInOnePacket == 1) blocks from memory - LIFO
295 * data from memory a prepare CayenneLppBuffer max to 242 bytes from end to begin of memory
296 * _fromEndInx
297 * _fromEndInx+1
298 * _fromEndInx+2
299 * .
300 * .
301 * .
302 * myloraWan_PrepareSendingBuffer prepare buffer from memory
303 * _systemParams.SendInOnePacket = 0 - one data, = 1 more, until are data or maxPayLoad
304 *
305 *
306 Max payload per DR (EU868 region):
307 Data Rate Spreading Factor Max App Payload
308 DR0 SF12 / 125kHz 51 bytes
309 DR1 SF11 / 125kHz 51 bytes
310 DR2 SF10 / 125kHz 51 bytes
311 DR3 SF9 / 125kHz 115 bytes
312 DR4 SF8 / 125kHz 222 bytes
313 DR5 SF7 / 125kHz 222 bytes
314 */
315 if (_.CurrentSendingDataSz == 0) // data ready in buffer, must be send before reading from memory (e.g. in case if not stored in mem or mem failed)
316 {
317 SysTime_t tim = SysTimeGet(); // current time, when is prepare the buffer
318 mems_DataBlock_t *buf = NULL;
319 HAL_StatusTypeDef memsStatus;
320 const uint8_t maxPayLoad = MIN(CayenneLppMaxBuffer(), myLoRaWAN_GetMaxPayloadSize());
321 uint16_t currentBatVoltage = SYS_GetBatteryLevel();
322
323 _.FromEndInx = 0;
324 // the batter check, if the voltage is lower, no process...
325 if (currentBatVoltage >= SYSTEMPARAMS_BATTMINWORK)
326 {
327 writeLog("myLoraWan_LastDataSend: voltage OK, %dmv", (int) currentBatVoltage);
328
329 // the required data are preferred of measure data from past
330 if (_.DataSendBuffer != NULL && _.DataSendSz > 0)
331 {
332 // the data processed from Data buffer
333 writeLog("DataSendBuffer: sz:%d, inx:%d", (int) _.DataSendSz, (int) _.DataSendInx);
334 _.CurrentSendingDataSz = MIN(maxPayLoad, _.DataSendSz);
335 memcpy(_.CurrentSendingDataBuffer, _.DataSendBuffer + _.DataSendInx, _.CurrentSendingDataSz);
336 _.DataSendSz -= _.CurrentSendingDataSz;
337 _.DataSendInx += _.CurrentSendingDataSz;
338 if (_.DataSendSz == 0)
339 {
340 // last chunk
341 _.DataSendInx = 0;
342 _.DataSendBuffer = NULL;
343 _.LoraWanPort++; // last chunk - via port
344 writeLog("DataSendBuffer last");
345 }
346 else
347 writeLog("DataSendBuffer still: %d", (int) _.DataSendSz);
348 }
349 else
350 {
351 do
352 {
353 memsStatus = mems_GetLastData(&buf, _.FromEndInx);
354 switch (memsStatus)
355 {
356 case HAL_OK: // data available
357 // change of _currentSendingDataSz
358 if (myloraWan_PrepareSendingBuffer(buf, _.FromEndInx == 0, maxPayLoad, tim)) // reset buffer, if 1st is going & max check
359 {
360 writeLog("myLoraWan_LastDataSend - mems sent data, still:%d", (int) _memsMainBlock.Data_CountCurrent - _.FromEndInx);
361 tim = sensors_GetTimeFromBlock(buf); // time for next data in _systemParams.SendInOnePacket
362 }
363 else
364 {
365 writeLog("myLoraWan_LastDataSend - maximum data payload reached:%d", (int) maxPayLoad);
366 if (_.FromEndInx)
367 --_.FromEndInx;
368 memsStatus = HAL_BUSY;
369 }
370 break;
371 case HAL_BUSY: // no more data
372 writeLog("myLoraWan_LastDataSend - mems no more data");
373 break;
374 default: // error
375 writeLog("myLoraWan_LastDataSend - mems error");
376 }
377 } while (_systemParams.SensSendInOnePacket && memsStatus == HAL_OK && ++_.FromEndInx);
378 }
379 }
380 else
381 {
382 writeLog("myLoraWan_LastDataSend - low voltage: %dmV, exit", (int) currentBatVoltage);
383 break;
384 }
385 }
386 // data ready to send
387 if (_.CurrentSendingDataSz > 0)
388 {
389 LoRaWAN_SendConfirmedData(_.CurrentSendingDataBuffer, _.CurrentSendingDataSz, _.LoraWanPort); // from local buffer
390 writeLog("myLoraWan_LastDataSend - sendConfirmedData:%d", (int) _.CurrentSendingDataSz);
391 }
392 else
393 {
394 writeLog("myLoraWan_LastDataSend - sendConfirmedData: no data");
395 }
396 } while (0);
397 }
398 else
399 writeLog("myLoraWan_LastDataSend - busy");
400 writeLog("myLoraWan_LastDataSend - end");
401 }
402 }
403 else
404 writeLog("myLoraWan_LastDataSend - not connected");
405}
406
407////////////////////////////////// public /////////////////////////////
408
409/**
410 * @brief Called after LoRaWAN successfully connects to the server
411 *
412 * This function is called when the LoRaWAN join process completes successfully.
413 * It performs time synchronization with the LoRaWAN server by requesting the
414 * device time, which updates the RTC with the server's time.
415 */
417{
418 writeLog("LoRaWAN connected successfully!");
419
420 /* Request time synchronization from the LoRaWAN server */
421 /* This will trigger the DeviceTimeReq MAC command */
422 /* The response will automatically update the system time via OnSysTimeUpdate callback */
423 LmHandlerErrorStatus_t status = LmHandlerDeviceTimeReq();
424
425 if (status == LORAMAC_HANDLER_SUCCESS)
426 {
427 writeLog("Time synchronization request sent");
428 }
429 else
430 {
431 writeLog("Failed to send time synchronization request");
432 }
433 _.ConnectedCount = _systemParams.LoRaRepeatTryConnect;
434 _.NoAckRepeatCount = MAX_NOACKREPEATCOUNT;
435 _.IsConnected = 1;
436 _.AckFromServer = 0;
437 myLoraWan_ResetDataDefault(); // _.LoraWanPort = LORAWANPORT_DATA; // default port NR
438 UTIL_SEQ_SetTask((1 << (_.MyloraWanAppBit + 2)), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend, can be send from buffer, the connection is established
439}
440
441/**
442 * @brief Called after date/time has been synchronized from LoRaWAN
443 *
444 * This function is called when the device receives a time synchronization
445 * response (DeviceTimeAns) from the LoRaWAN server. The RTC has already
446 * been updated with the server's time when this function is called.
447 *
448 * Add your custom code here to perform actions after time synchronization,
449 * such as updating time-dependent schedules, logging the sync event, or
450 * triggering time-based operations.
451 */
453{
454 // 1st must be check, if time is valid
455 uint8_t timeSync = systemParams_CorrectSystemTime();
456
457 writeLog("Time synchronized: systemParams_CorrectSystemTime returns: %d", (int) timeSync);
458
459 SysTime_t sysTime = SysTimeGet();
460 struct tm localTime;
461
462 SysTimeLocalTime(sysTime.Seconds, &localTime);
463 writeLog("Time synchronized: %04d-%02d-%02d %02d:%02d:%02d", localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday, localTime.tm_hour, localTime.tm_min,
464 localTime.tm_sec);
465}
466
467/**
468 * @brief Handle received downlink data from LoRaWAN server
469 *
470 * This callback function is triggered when the device receives data from the
471 * LoRaWAN server. This can be a response to a confirmed uplink or an
472 * application-level downlink message.
473 *
474 * @param appData Received application data including buffer and port
475 * @param params Receive parameters including RSSI, SNR, and downlink counter
476 */
477void OnLoRaWANRxData(LmHandlerAppData_t *appData, LmHandlerRxParams_t *params)
478{
479 if (appData == NULL || params == NULL)
480 {
481 writeLog("Invalid RX data parameters");
482 return;
483 }
484
485 writeLog("Received data from server:");
486 writeLog(" Port: %d", appData->Port);
487 writeLog(" Size: %d bytes", appData->BufferSize);
488 writeLog(" RSSI: %d dBm", params->Rssi);
489 writeLog(" SNR: %d dB", params->Snr);
490 writeLog(" Downlink Counter: %lu", params->DownlinkCounter);
491
492 if (_.AckFromServer)
493 {
494 // last data send OK
495 mems_RemoveLastData(_.FromEndInx);
496 _.CurrentSendingDataSz = 0;
497 _.FromEndInx = 0;
498 _.IsConnected = 1; // if ACK - the connetion must be
499 if (_.IsMeasureQueued)
500 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 0), CFG_SEQ_Prio_0); // myloraWan_MeasureFinish, the measure is queued, must be finished before myLoraWan_LastDataSend
501 else
502 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 2), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend - but only if the measure is not queued
503 writeLog(" Status: next data is going to send");
504 _.AckFromServer = 0;
505 }
506
507 switch (appData->Port)
508 {
509 case 0:
510 break;
511
513 {
514 // the system params is required
516
517 writeLog("LORAWANPORT_CONFIG_GET: crc:%d %s", (int)_systemParams.Crc, (systemParams_CheckCRC(&_systemParams) ? "ok" : "failed"));
518
519 _systemParamsBck = _systemParams; // copy to backup to no change
520 _.DataSendBuffer = (const uint8_t*) &_systemParamsBck;
521 _.DataSendSz = sizeof(_systemParamsBck);
522 _.DataSendInx = 0;
523 _.LoraWanPort = appData->Port;
524 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 2), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend - but only if the measure is not queued
525 }
526 break;
528 break;
529
531 systemParams_SetFromPart(appData->Buffer, appData->BufferSize); // setting of new params
532 break;
533 }
534
535 /*
536 // Process received data based on port
537 if (appData->BufferSize > 0)
538 {
539 // Handle specific commands from server
540 switch (appData->Port)
541 {
542 case 2: // Application data port
543 // Process application-specific commands
544 if (appData->BufferSize >= 1)
545 {
546 uint8_t command = appData->Buffer[0];
547 writeLog(" Command received: 0x%02X", command);
548
549 // Example: handle different commands
550 switch (command)
551 {
552 case 0x01:
553 writeLog(" -> Command: Request immediate sensor reading");
554 // Trigger immediate sensor read
555 break;
556 case 0x02:
557 writeLog(" -> Command: Change reporting interval");
558 if (appData->BufferSize >= 3)
559 {
560 uint16_t interval = (appData->Buffer[1] << 8) | appData->Buffer[2];
561 writeLog(" -> New interval: %d seconds", interval);
562 }
563 break;
564 default:
565 writeLog(" -> Unknown command");
566 break;
567 }
568 }
569 break;
570
571 case 3: // Configuration port
572 writeLog(" Configuration data received");
573 break;
574
575 default:
576 writeLog(" Data on unknown port");
577 break;
578 }
579 } */
580
581 // Check if this was an ACK for a confirmed uplink
582 // IsMcpsIndication == 0 means this is a MAC layer response (ACK), not an application data indication
583 if (params->IsMcpsIndication == 0)
584 {
585 writeLog(" This is an ACK for confirmed uplink");
586 }
587}
588
589/**
590 * @brief Handle transmission event callback
591 *
592 * This callback is triggered after a transmission attempt, whether successful or not.
593 * It provides information about whether an ACK was received for confirmed messages.
594 *
595 * @param params Transmission parameters including status and ACK received flag
596 */
597void OnLoRaWANTxData(LmHandlerTxParams_t *params)
598{
599 if (_.CurrentSendingDataSz > 0 && params != NULL)
600 {
601 writeLog("Transmission completed:");
602 writeLog(" Uplink Counter: %lu", params->UplinkCounter);
603 writeLog(" Datarate: DR%d", params->Datarate);
604 writeLog(" TX Power: %d dBm", params->TxPower);
605 writeLog(" Channel: %d", params->Channel);
606
607 if (params->MsgType == LORAMAC_HANDLER_CONFIRMED_MSG)
608 {
609 if (params->AckReceived)
610 {
611 writeLog(" Status: ACK received from server");
612 _.AckFromServer = 1; // we have ACK
613 _.NoAckRepeatCount = MAX_NOACKREPEATCOUNT;
614 if (_.DataSendBuffer == NULL)
615 myLoraWan_ResetDataDefault(); // _.LoraWanPort = LORAWANPORT_DATA; // no data send -> back to measure data
616 }
617 else
618 {
619 writeLog(" Status: No ACK received (will retry)");
620 if (_.NoAckRepeatCount)
621 {
622 writeLog(" Retrying send, retries left: %d", (int) _.NoAckRepeatCount);
623 UTIL_SEQ_SetTask(1 << (_.MyloraWanAppBit + 2), CFG_SEQ_Prio_0); // myLoraWan_LastDataSend
624 --_.NoAckRepeatCount;
625 }
626 else
627 {
628 writeLog(" All retries exhausted, reconnecting...");
630 }
631 }
632 }
633 else
634 {
635 writeLog(" Status: Unconfirmed message sent");
636 }
637
638 if (params->Status != LORAMAC_EVENT_INFO_STATUS_OK)
639 {
640 writeLog(" TX Error: %d", params->Status);
641 }
642 }
643 _.IsDataSending = 0; // sending has been finished - confirmed or not
644}
645
646void myloraWan_Init(uint8_t myloraWanAppBit)
647{
648 _.MyloraWanAppBit = myloraWanAppBit;
649 UTIL_SEQ_RegTask((1 << (_.MyloraWanAppBit + 0)), UTIL_SEQ_RFU, myloraWan_MeasureFinish); // CFG_SEQ_Task_MyLora
650 UTIL_SEQ_RegTask((1 << (_.MyloraWanAppBit + 1)), UTIL_SEQ_RFU, myLoraWan_Reconnect); // CFG_SEQ_Task_MyLora + 1
651 UTIL_SEQ_RegTask((1 << (_.MyloraWanAppBit + 2)), UTIL_SEQ_RFU, myLoraWan_LastDataSend); // CFG_SEQ_Task_MyLora + 2
652}
uint8_t CayenneLppMaxBuffer()
Definition CayenneLpp.c:412
Implements the Cayenne Low Power Protocol.
Header for ADC interface configuration.
uint16_t SYS_GetBatteryLevel(void)
Get the current battery level.
Definition adc_if.c:139
This file contains all the function prototypes for the i2c.c file.
I2C_HandleTypeDef hi2c2
Definition i2c.c:27
Header of application of the LRWAN Middleware.
#define LORAWAN_DEFAULT_ACTIVATION_TYPE
Definition lora_app.h:100
static struct @042147022327042232212126043022001043033342036075 _
: Header for main.c file. This file contains the common defines of the application....
void writeLog(const char *format,...)
Format and send a log message over UART (printf-style). Available only when WRITELOG is defined; comp...
Definition main.c:105
static void myloraWan_MeasureFinish()
the measure has been finished, sensor data save to memory or local buffer(in case if no memory is exi...
int8_t FromEndInx
static void myLoraWan_ResetDataDefault()
uint8_t CurrentSendingDataSz
static void myLoraWan_LastDataSend()
take data from LIFO - last data and send. Cannot be nested only if is LoRa connected
uint8_t AckFromServer
uint8_t NoAckRepeatCount
uint16_t DataSendSz
void OnTimeSynchronized(void)
Called after date/time has been synchronized from LoRaWAN.
uint8_t MyloraWanAppBit
uint8_t ConnectedCount
static uint8_t myloraWan_PrepareSendingBuffer(const mems_DataBlock_t *data, uint8_t reset, uint8_t maxSize, SysTime_t prevMeasureTime)
the preparing _currentSendingDataBuffer/_currentSendingDataSz from CayennelLpp to send data to LoRaWa...
uint8_t IsMeasureQueued
static uint8_t myLoRaWAN_GetMaxPayloadSize(void)
Get the maximum application payload size for the current data rate. Returns 0 if the query fails or c...
uint8_t IsConnected
loraWanPort_t LoraWanPort
void OnLoRaWANRxData(LmHandlerAppData_t *appData, LmHandlerRxParams_t *params)
Handle received downlink data from LoRaWAN server.
static void myLoraWan_Reconnect()
Reconnect to LoRa gateway. In case is measure data are queued, the myloraWan_MeasureFinish is called ...
uint8_t CurrentSendingDataBuffer[256]
void OnLoRaWanConnected(void)
Called after LoRaWAN successfully connects to the server.
#define MAX_NOACKREPEATCOUNT
static void myLoraWan_StartReconnect()
StartReconnect - processing of myLoraWan_Reconnect via sequencer in case ConnectedCount is not falled...
void OnLoRaWANTxData(LmHandlerTxParams_t *params)
Handle transmission event callback.
static LmHandlerErrorStatus_t LoRaWAN_SendConfirmedData(uint8_t *data, uint8_t dataSize, uint8_t port)
Send confirmed data to LoRaWAN network.
void myloraWan_Init(uint8_t myloraWanAppBit)
initialization of myloraWan process, sequencer
uint8_t IsDataSending
const uint8_t * DataSendBuffer
uint16_t DataSendInx
void mems_RemoveLastData(uint8_t fromEndTo)
remove last data
Definition mymems.c:269
HAL_StatusTypeDef mems_GetLastData(mems_DataBlock_t **memBlock, uint8_t inxFromEnd)
Get the last sensor data if exists. The data and mem block is stored in work buffer,...
Definition mymems.c:221
mems_MainBlock_t _memsMainBlock
Global instance of the main flash control block; loaded by mems_ReadMainBlock().
Definition mymems.c:29
HAL_StatusTypeDef mems_AddData(const void *data, mems_DataType_t type, uint8_t size)
write new data of sensor at the end of queue, if is no space, the most older data start to rewrites
Definition mymems.c:195
mems_DataBlock_t * mems_InicBuffer(mems_DataType_t type)
Initialize the work buffer - _memsDataBlock.
Definition mymems.c:187
@ MEMS_DATATYPE_SENSOR
Definition mymems.h:71
uint8_t * sensors_CayennelFromBckData(uint8_t *sizeOut, SysTime_t *prevMeasureTime)
collecting sensor data into CayenneLppGetBuffer buffer for sending them via LoRaWan,...
Definition mysensors.c:488
void sensors_WriteFromBckToDataBlock(mems_DataBlock_t *data)
filling the data block from sensor data - store to memory the methods works with _bck_XXXXX senzor,...
Definition mysensors.c:604
SysTime_t sensors_GetTimeFromBlock(const mems_DataBlock_t *data)
getting the SysTime_t from block data of memory
Definition mysensors.c:683
void sensors_CopyToBck()
The copying data from current sensors buffer to backUp - _bck_XXXXX.
Definition mysensors.c:463
uint8_t sensors_ReadToBckFromDataBlock(const mems_DataBlock_t *data)
reading from memory block and filling specified sensor from memory - ready for sensors_CayennelData t...
Definition mysensors.c:646
systemParams_t _systemParams
uint8_t systemParams_CorrectSystemTime()
setting/correction of the system time from _systemParams.MqttTime, if contains valid UNIX time(low ui...
void systemParams_SetCRCSystemParams()
Recalculate and store the CRC in _systemParams.Crc. Call this after modifying any field of _systemPar...
void systemParams_SetFromPart(const uint8_t *buffer, uint8_t bufSize)
The setting of systemParams_t from server dowlink. The buffer contains the combination for setting of...
systemParams_t _systemParamsBck
uint8_t systemParams_CheckCRC(const systemParams_t *par)
Verify the CRC field of a systemParams_t structure.
#define SYSTEMPARAMS_BATTMINWORK
the voltage (mV) for processing. The system goes to OFF mode, if current votage is lower SYSTEMPARAMS...
loraWanPort_t
the list of LORAWAN port.
@ LORAWANPORT_CONFIG_GET
@ LORAWANPORT_CONFIG_GET_LAST
@ LORAWANPORT_CONFIG_SET_PART
HAL_StatusTypeDef nfc_WriteMeasureData(I2C_HandleTypeDef *hi2c, const measureDataNFC_t *data)
write the measure data paylod in measureDataNFC_t to NFC on next free position - in circular queue
Definition nfc.c:208
This file contains all the function prototypes for the rtc.c file.
block of one measure data in CayennelLPP payload format The Data field contains the same payload as i...
uint8_t Data[(4+(4+3)+0+0+(4+0)+0+0)]
Sensor data record stored as one element in the flash circular queue.
Definition mymems.h:82
Function prototypes for sys_app.c file.
@ CFG_SEQ_Prio_0