FOSSASAT-1B
Loading...
Searching...
No Matches
communication.cpp
1#include "communication.h"
2
3void Communication_Receive_Interrupt() {
4 // check interrups are enabled
6 return;
7 }
8
9 // set flag
10 dataReceived = true;
11}
12
13int16_t Communication_Set_Modem(uint8_t modem) {
14 int16_t state = ERR_NONE;
15 FOSSASAT_DEBUG_WRITE(modem);
16
17 // initialize requested modem
18 switch (modem) {
19 case MODEM_LORA:
20 state = radio.begin(LORA_CARRIER_FREQUENCY,
22 LORA_SPREADING_FACTOR,
28 radio.setCRC(true);
29 radio.setCurrentLimit(LORA_CURRENT_LIMIT);
30 break;
31 case MODEM_FSK: {
32 state = radio.beginFSK(FSK_CARRIER_FREQUENCY,
39 uint8_t syncWordFSK[2] = {SYNC_WORD, SYNC_WORD};
40 radio.setSyncWord(syncWordFSK, 2);
41 radio.setCRC(2);
42 radio.setDataShaping(FSK_DATA_SHAPING);
43 radio.setCurrentLimit(FSK_CURRENT_LIMIT);
44 } break;
45 default:
46 return(ERR_UNKNOWN);
47 }
48
49 radio.setWhitening(true, WHITENING_INITIAL);
50
51 // handle possible error codes
52 FOSSASAT_DEBUG_PRINT(F("Init "));
53 FOSSASAT_DEBUG_PRINTLN(state);
54 FOSSASAT_DEBUG_DELAY(10);
55 if (state != ERR_NONE) {
56 // radio chip failed, restart
57 Pin_Interface_Watchdog_Restart();
58 }
59
60 // set spreading factor
61 Communication_Set_SpreadingFactor(spreadingFactorMode);
62
63 // set TCXO
64 radio.setTCXO(TCXO_VOLTAGE);
65
66 // save current modem
67 currentModem = modem;
68 return(state);
69}
70
71int16_t Communication_Set_SpreadingFactor(uint8_t sfMode) {
72 uint8_t sfs[] = {LORA_SPREADING_FACTOR, LORA_SPREADING_FACTOR_ALT};
73
74 // check currently active modem
75 if(currentModem == MODEM_FSK) {
76 return(ERR_WRONG_MODEM);
77 }
78
79 // update standard/alternative spreading factor
80 int16_t state = radio.setSpreadingFactor(sfs[sfMode]);
81
82 // only save current spreading factor mode if the change was successful
83 if(state == ERR_NONE) {
84 spreadingFactorMode = sfMode;
85 }
86
87 return(state);
88}
89
90int16_t Communication_Set_Configuration(uint8_t* optData, uint8_t optDataLen) {
91 // check optDataLen
92 if(!((optDataLen >= 7 + 1) && (optDataLen <= 7 + MAX_STRING_LENGTH))) {
93 return(ERR_PACKET_TOO_LONG);
94 }
95
96 // check bandwidth value (loaded from array - rest of settings are checked by library)
97 if(optData[0] > 7) {
98 return(ERR_INVALID_BANDWIDTH);
99 }
100
101 // attempt to change the settings
102 float bws[] = {7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0};
103 uint16_t preambleLength = 0;
104 memcpy(&preambleLength, optData + 3, sizeof(uint16_t));
105 uint16_t state = radio.begin(LORA_CARRIER_FREQUENCY,
106 bws[optData[0]],
107 optData[1],
108 optData[2],
109 SYNC_WORD,
110 optData[6],
112 preambleLength);
113 if(state != ERR_NONE) {
114 return(state);
115 }
116
117 // set CRC
118 state = radio.setCRC(optData[5]);
119 return(state);
120}
121
122void Communication_Send_Morse_Beacon(float battVoltage) {
123 // initialize Morse client
125
126 // read callsign
128 char callsign[MAX_STRING_LENGTH + 1];
129 System_Info_Get_Callsign(callsign, callsignLen);
130
131 // send start signals
132 for(int8_t i = 0; i < MORSE_PREAMBLE_LENGTH; i++) {
133 morse.startSignal();
134 Pin_Interface_Watchdog_Heartbeat();
135 }
136
137 // send callsign
138 for(uint8_t i = 0; i < callsignLen - 1; i++) {
139 morse.print(callsign[i]);
140 Pin_Interface_Watchdog_Heartbeat();
141 }
142
143 // space
144 morse.print(' ');
145 Pin_Interface_Watchdog_Heartbeat();
146
147 // send battery voltage code
149 morse.println(code);
150 Pin_Interface_Watchdog_Heartbeat();
151}
152
153void Communication_CW_Beep(uint32_t len) {
154 radio.transmitDirect();
155 Power_Control_Delay(len, true);
156 radio.standby();
157}
158
159void Communication_Send_System_Info() {
160 // build response frame
161 static const uint8_t optDataLen = 6*sizeof(uint8_t) + 3*sizeof(int16_t) + sizeof(uint16_t) + sizeof(int8_t) + sizeof(uint32_t);
164
165 #ifdef ENABLE_INA226
166 uint8_t batteryVoltage = Power_Control_Get_Battery_Voltage() * (VOLTAGE_UNIT / VOLTAGE_MULTIPLIER);
167 #else
169 #endif
172
173 #ifdef ENABLE_INA226
174 int16_t batteryChargingCurrent = Power_Control_Get_Charging_Current() * (CURRENT_UNIT / CURRENT_MULTIPLIER);
175 #else
177 #endif
180
181 #ifdef ENABLE_INA226
182 uint8_t batteryChargingVoltage = Power_Control_Get_Charging_Voltage() * (VOLTAGE_UNIT / VOLTAGE_MULTIPLIER);
183 #else
185 #endif
188
189 // set uptimeCounter
192
193 // set powerConfig variable
194 Power_Control_Load_Configuration();
195 FOSSASAT_DEBUG_PRINTLN(powerConfig.val, BIN);
196 memcpy(optDataPtr, &powerConfig.val, sizeof(uint8_t));
197 optDataPtr += sizeof(uint8_t);
198
199 // set resetCounter variable
202
206
207 // set solarCellBVoltage variable
211
212 // set solarCellCVoltage variable
216
217 // set batteryTemperature variable
221
222 // set boardTemperature variable
226
227 // set mcuTemperature variable (read twice since first value is often nonsense)
228 Pin_Interface_Read_Temperature_Internal();
229 int8_t mcuTemperature = Pin_Interface_Read_Temperature_Internal();
232
233 // send as raw bytes
234 Communication_Send_Response(RESP_SYSTEM_INFO, optData, optDataLen);
235}
236
237void Communication_Acknowledge(uint8_t functionId, uint8_t result) {
239 Communication_Send_Response(RESP_ACKNOWLEDGE, optData, 2);
240}
241
242void Communication_Process_Packet() {
243 /*FOSSASAT_DEBUG_PRINT("Communication_Process_Packet ");
244 FOSSASAT_DEBUG_PRINTLN(freeRam());
245 FOSSASAT_DEBUG_DELAY(100);*/
246
247 // disable interrupts
248 interruptsEnabled = false;
249
250 // read data
251 size_t len = radio.getPacketLength();
252 if(len == 0) {
253 dataReceived = false;
254 interruptsEnabled = true;
255 return;
256 }
258 int16_t state = radio.readData(frame, len);
259
260 // check reception state
261 if(state == ERR_NONE) {
262 FOSSASAT_DEBUG_PRINT(F("Frm "));
263 FOSSASAT_DEBUG_PRINTLN(len);
264 FOSSASAT_DEBUG_PRINT_BUFF(frame, len);
265
266 // check callsign
268 char callsign[MAX_STRING_LENGTH + 1];
269 System_Info_Get_Callsign(callsign, callsignLen);
270 if(memcmp(frame, (uint8_t*)callsign, callsignLen - 1) == 0) {
271 // check passed
272 Comunication_Parse_Frame(frame, len);
273 } else {
274 FOSSASAT_DEBUG_PRINTLN(F("CErr"));
275 Persistent_Storage_Increment_Frame_Counter(false);
276 Communication_Acknowledge(0xFF, 0x01);
277 }
278
279 } else {
280 FOSSASAT_DEBUG_PRINT(F("RxErr "));
281 FOSSASAT_DEBUG_PRINT(state);
282 Persistent_Storage_Increment_Frame_Counter(false);
283 Communication_Acknowledge(0xFF, 0x02);
284 }
285
286 // reset flag
287 dataReceived = false;
288
289 // enable interrupts
290 interruptsEnabled = true;
291}
292
293void Comunication_Parse_Frame(uint8_t* frame, size_t len) {
294 /*FOSSASAT_DEBUG_PRINT("Comunication_Parse_Frame ");
295 FOSSASAT_DEBUG_PRINTLN(freeRam());
296 FOSSASAT_DEBUG_DELAY(100);*/
297
298 // read callsign from EEPROM
300 char callsign[MAX_STRING_LENGTH + 1];
301 System_Info_Get_Callsign(callsign, callsignLen);
302
303 // get functionID
305 if(functionId < 0) {
306 FOSSASAT_DEBUG_PRINT(F("IdErr"));
307 FOSSASAT_DEBUG_PRINTLN(functionId);
308 Persistent_Storage_Increment_Frame_Counter(false);
309 Communication_Acknowledge(0xFF, 0x03);
310 return;
311 }
312 FOSSASAT_DEBUG_PRINT(F("FID="));
313 FOSSASAT_DEBUG_PRINTLN(functionId, HEX);
314
315 // check encryption
319 // frame contains encrypted data, decrypt
320
321 // get optional data length
323 if(optDataLen < 0) {
324 FOSSASAT_DEBUG_PRINT(F("DcErr"));
325 FOSSASAT_DEBUG_PRINTLN(optDataLen);
326
327 // decryption failed, increment invalid frame counter and return
328 Persistent_Storage_Increment_Frame_Counter(false);
329 Communication_Acknowledge(0xFF, 0x04);
330 return;
331 }
332
333 // get optional data
334 if(optDataLen > 0) {
336 }
337
338 } else if(functionId < PRIVATE_OFFSET) {
339 // no decryption necessary
340
341 // get optional data length
343 if(optDataLen < 0) {
344 // optional data extraction failed,
345 FOSSASAT_DEBUG_PRINT(F("LenErr"));
346 FOSSASAT_DEBUG_PRINTLN(optDataLen);
347
348 // increment invalid frame counter
349 Persistent_Storage_Increment_Frame_Counter(false);
350 Communication_Acknowledge(0xFF, 0x05);
351 return;
352 }
353
354 // get optional data
355 if(optDataLen > 0) {
357 }
358 } else {
359 // unknown function ID
360 FOSSASAT_DEBUG_PRINT(F("UID"));
361 FOSSASAT_DEBUG_PRINTLN(functionId, HEX);
362 Persistent_Storage_Increment_Frame_Counter(false);
363 Communication_Acknowledge(0xFF, 0x06);
364 return;
365 }
366
367 // check optional data presence
368 if(optDataLen > 0) {
369 // execute with optional data
370 FOSSASAT_DEBUG_PRINT(F("optLen="));
371 FOSSASAT_DEBUG_PRINTLN(optDataLen);
372 FOSSASAT_DEBUG_PRINT_BUFF(optData, (uint8_t)optDataLen);
373 Communication_Execute_Function(functionId, optData, optDataLen);
374
375 } else {
376 // execute without optional data
377 Communication_Execute_Function(functionId);
378 }
379}
380
381void Communication_Execute_Function(uint8_t functionId, uint8_t* optData, size_t optDataLen) {
382 /*FOSSASAT_DEBUG_PRINT("Communication_Execute_Function ");
383 FOSSASAT_DEBUG_PRINTLN(freeRam());
384 FOSSASAT_DEBUG_DELAY(100);*/
385
386 // increment valid frame counter
387 Persistent_Storage_Increment_Frame_Counter(true);
388
389 // acknowledge frame
390 Communication_Acknowledge(functionId, 0x00);
391
392 // execute function based on ID
393 switch(functionId) {
394 case CMD_PING:
395 // send pong
396 Communication_Send_Response(RESP_PONG);
397 break;
398
399 case CMD_RETRANSMIT: {
400 // check message length
402 // respond with the requested data
403 Communication_Send_Response(RESP_REPEATED_MESSAGE, optData, optDataLen);
404 }
405 } break;
406
408 // check message length
409 if((optDataLen >= 8) && (optDataLen <= MAX_STRING_LENGTH + 7)) {
410 // change modem configuration
411 int16_t state = Communication_Set_Configuration(optData, optDataLen);
412
413 // check if the change was successful
414 if(state != ERR_NONE) {
415 FOSSASAT_DEBUG_PRINT(F("CfgErr"));
416 FOSSASAT_DEBUG_PRINTLN(state);
417 } else {
418 // configuration changed successfully, transmit response
419 Communication_Send_Response(RESP_REPEATED_MESSAGE_CUSTOM, optData + 7, optDataLen - 7, true);
420 }
421 }
422 } break;
423
425 // send system info via LoRa
426 Communication_Send_System_Info();
427 break;
428
429 case CMD_GET_PACKET_INFO: {
430 // get last packet info and send it
431 static const uint8_t respOptDataLen = 2*sizeof(uint8_t) + 4*sizeof(uint16_t);
434
435 // SNR
436 int8_t snr = (int8_t)(radio.getSNR() * 4.0);
438
439 // RSSI
440 uint8_t rssi = (uint8_t)(radio.getRSSI() * -2.0);
442
445
448
451
454
455 Communication_Send_Response(RESP_PACKET_INFO, respOptData, respOptDataLen);
456 } break;
457
458 case CMD_GET_STATISTICS: {
459 // check optional data is exactly 1 byte
460 if(Communication_Check_OptDataLen(1, optDataLen)) {
461 // response will have maximum of 34 bytes if all stats are included
465
466 // copy stat flags
467 uint8_t flags = optData[0];
469 respOptDataPtr += sizeof(uint8_t);
470
471 // get required stats from EEPROM
472 if(flags & 0x01) {
473 // charging voltage
477 respOptDataLen += 3;
478 }
479
480 if(flags& 0x02) {
481 // charging current
485 respOptDataLen += 6;
486 }
487
488 if(flags & 0x04) {
489 // battery voltage
493 respOptDataLen += 3;
494 }
495
496 if(flags & 0x08) {
497 // cell A voltage
501 respOptDataLen += 3;
502 }
503
504 if(flags & 0x10) {
505 // cell B voltage
509 respOptDataLen += 3;
510 }
511
512 if(flags & 0x20) {
513 // cell C voltage
517 respOptDataLen += 3;
518 }
519
520 if(flags & 0x40) {
521 // battery temperature
525 respOptDataLen += 6;
526 }
527
528 if(flags & 0x80) {
529 // board temperature
533 respOptDataLen += 6;
534 }
535
536 // send response
537 Communication_Send_Response(RESP_STATISTICS, respOptData, respOptDataLen);
538 }
539 } break;
540
541 // private function IDs
542 case CMD_DEPLOY: {
543 // run deployment sequence
544 Deployment_Deploy();
545
546 // get deployment counter value and send it
548 Communication_Send_Response(RESP_DEPLOYMENT_STATE, &counter, 1);
549 } break;
550
551 case CMD_RESTART:
552 // restart satellite
553 Pin_Interface_Watchdog_Restart();
554 break;
555
556 case CMD_WIPE_EEPROM:
557 // wipe EEPROM and reset all EEPROM variables to default values
558 Persistent_Storage_Wipe();
559 break;
560
562 // check optional data is exactly 1 byte
563 if(Communication_Check_OptDataLen(1, optDataLen)) {
564 // load power config from EEPROM
565 Power_Control_Load_Configuration();
566
567 // update transmit enable flag
568 powerConfig.bits.transmitEnabled = optData[0];
569
570 // save power config from EEPROM
571 Power_Control_Save_Configuration();
572 }
573 } break;
574
575 case CMD_SET_CALLSIGN: {
576 // check optional data is less than limit
578 // get callsign from frame
581 newCallsign[optDataLen] = '\0';
582
583 // update callsign
584 System_Info_Set_Callsign(newCallsign);
585 FOSSASAT_DEBUG_PRINTLN(newCallsign);
586 }
587 } break;
588
589 case CMD_SET_SF_MODE: {
590 // check optional data is exactly 1 byte
591 if(Communication_Check_OptDataLen(1, optDataLen)) {
592 // update spreading factor mode
594 Communication_Set_SpreadingFactor(spreadingFactorMode);
595 }
596 } break;
597
598 case CMD_SET_MPPT_MODE: {
599 // check optional data is exactly 2 bytes
600 if(Communication_Check_OptDataLen(2, optDataLen)) {
601 // load power config from EEPROM
602 Power_Control_Load_Configuration();
603
604 // update MPPT mode
605 powerConfig.bits.mpptTempSwitchEnabled = optData[0];
606 powerConfig.bits.mpptKeepAliveEnabled = optData[1];
607
608 // save power config from EEPROM
609 Power_Control_Save_Configuration();
610 }
611 } break;
612
614 // check optional data is exactly 1 byte
615 if(Communication_Check_OptDataLen(1, optDataLen)) {
616 // load power config from EEPROM
617 Power_Control_Load_Configuration();
618
619 // update low power enable flag
620 powerConfig.bits.lowPowerModeEnabled = optData[0];
621
622 // save power config from EEPROM
623 Power_Control_Save_Configuration();
624 }
625 } break;
626
628 // check optional data is exactly 2 bytes
629 if(Communication_Check_OptDataLen(2, optDataLen)) {
630 // set FSK receive length
632
633 // set LoRa receive length
635
636 // check if there will be still some receive window open
638 FOSSASAT_DEBUG_PRINT(F("Res FSK"));
640 }
641 }
642 } break;
643
645 // check optional data is exactly 3 bytes
646 if(Communication_Check_OptDataLen(3, optDataLen)) {
648
649 // check number of samples is less than limit
650 if(numSamples > 40) {
651 FOSSASAT_DEBUG_PRINT(F(">40"));
652 break;
653 }
654
655 // get sample period
656 uint16_t period = 0;
657 memcpy(&period, optData + 1, 2);
658 FOSSASAT_DEBUG_PRINT(F("Rec"));
659
660 // record all data
663 for(uint16_t i = 0; i < 3 * numSamples; i += 3) {
664 // check if the battery is good enough to continue
665 #ifdef ENABLE_INTERVAL_CONTROL
666 if(!Power_Control_Check_Battery_Limit()) {
667 // battery check failed, stop measurement and send what we have
669 break;
670 }
671 #endif
672
673 // read voltages
675 respOptData[i + 1] = Pin_Interface_Read_Voltage(ANALOG_IN_SOLAR_B_VOLTAGE_PIN) * (VOLTAGE_UNIT / VOLTAGE_MULTIPLIER);
676 respOptData[i + 2] = Pin_Interface_Read_Voltage(ANALOG_IN_SOLAR_C_VOLTAGE_PIN) * (VOLTAGE_UNIT / VOLTAGE_MULTIPLIER);
677
678 // wait for for the next measurement
679 Power_Control_Delay(period * SLEEP_LENGTH_CONSTANT, true, true);
680 }
681
682 // send response
683 Communication_Send_Response(RESP_RECORDED_SOLAR_CELLS, respOptData, respoOptDataLen);
684 }
685 } break;
686
687 case CMD_ROUTE:
688 // just transmit the optional data
689 Communication_Transmit(optData, optDataLen);
690 break;
691 }
692}
693
694int16_t Communication_Send_Response(uint8_t respId, uint8_t* optData, size_t optDataLen, bool overrideModem) {
695 /*FOSSASAT_DEBUG_PRINT("Communication_Send_Response ");
696 FOSSASAT_DEBUG_PRINTLN(freeRam());
697 FOSSASAT_DEBUG_DELAY(100);*/
698
699 // get callsign from EEPROM
701 char callsign[MAX_STRING_LENGTH + 1];
702 System_Info_Get_Callsign(callsign, callsignLen);
703
704 // build response frame
708
709 // delay before responding
710 FOSSASAT_DEBUG_DELAY(100);
711 Power_Control_Delay(RESPONSE_DELAY, true);
712
713 // send response
714 int16_t state = Communication_Transmit(frame, len, overrideModem);
715
716 return(state);
717}
718
719int16_t Communication_Transmit(uint8_t* data, uint8_t len, bool overrideModem) {
720 /*FOSSASAT_DEBUG_PRINT("Communication_Transmit ");
721 FOSSASAT_DEBUG_PRINTLN(freeRam());
722 FOSSASAT_DEBUG_DELAY(100);*/
723
724 // check transmit enable flag
725 #ifdef ENABLE_TRANSMISSION_CONTROL
726 Power_Control_Load_Configuration();
727 if(!powerConfig.bits.transmitEnabled) {
728 FOSSASAT_DEBUG_PRINTLN(F("Tx 0 cmd"));
729 return(ERR_TX_TIMEOUT);
730 }
731 #endif
732
733 // disable receive interrupt
734 radio.clearDio1Action();
735
736 // print frame for debugging
737 FOSSASAT_DEBUG_PRINT(F("Send "));
738 FOSSASAT_DEBUG_PRINTLN(len);
739 FOSSASAT_DEBUG_PRINT_BUFF(data, len);
740
741 // check if modem should be switched - required for transmissions with custom settings
743 FOSSASAT_DEBUG_PRINT(F("Use "));
744 if(overrideModem) {
745 FOSSASAT_DEBUG_WRITE(MODEM_LORA);
746 FOSSASAT_DEBUG_PRINTLN(F(" (ovr)"));
747 Communication_Set_Modem(MODEM_LORA);
748 } else {
749 FOSSASAT_DEBUG_WRITE(modem);
750 FOSSASAT_DEBUG_PRINTLN();
751 }
752
753 // get timeout
754 uint32_t timeout = 0;
755 if(currentModem == MODEM_FSK) {
756 timeout = (float)radio.getTimeOnAir(len) * 5.0;
757 } else {
758 timeout = (float)radio.getTimeOnAir(len) * 1.5;
759 }
760 FOSSASAT_DEBUG_PRINT(F("T/O="));
761 FOSSASAT_DEBUG_PRINTLN(timeout);
762
763 // start transmitting
764 int16_t state = radio.startTransmit(data, len);
765 if(state != ERR_NONE) {
766 FOSSASAT_DEBUG_PRINT(F("TxErr"));
767 FOSSASAT_DEBUG_PRINTLN(state);
768 return(state);
769 }
770
771 // wait for transmission finish
773 uint32_t lastBeat = 0;
774 while(!digitalRead(RADIO_DIO1)) {
775 // pet watchdog every second
777 Pin_Interface_Watchdog_Heartbeat();
778
779 // check whether voltage dropped below low power level
780 #ifdef ENABLE_INTERVAL_CONTROL
781 if(powerConfig.bits.lowPowerModeActive) {
782 // we're below low power level, stop the transmission
783 FOSSASAT_DEBUG_PRINTLN(F("Tx 0 bat"));
784 radio.standby();
785 return(ERR_INVALID_DATA_RATE);
786 }
787 #endif
788
789 lastBeat = micros();
790 }
791
792 // check timeout
793 if(micros() - start > timeout) {
794 // timed out while transmitting
795 radio.standby();
796 Communication_Set_Modem(modem);
797 FOSSASAT_DEBUG_PRINTLN(F("Tx t/o"));
798 return(ERR_TX_TIMEOUT);
799 }
800 }
801
802 // transmission done, set mode standby
803 state = radio.standby();
804
805 // restore modem
806 if(overrideModem) {
807 Communication_Set_Modem(modem);
808 }
809
810 // set receive ISR
811 radio.setDio1Action(Communication_Receive_Interrupt);
812
813 return(state);
814}
815
816bool Communication_Check_OptDataLen(uint8_t expected, uint8_t actual) {
817 if(expected != actual) {
818 // received length of optional data does not match expected
819 return(false);
820 }
821
822 return(true);
823}
This system is the main interface that is used to transmit message, configure the radio and process r...
void Communication_Frame_Add(uint8_t **buffPtr, T val, const char *name)
This function adds frame entry to a frame.
#define EEPROM_LORA_INVALID_COUNTER_ADDR
#define EEPROM_LORA_RECEIVE_LEN_ADDR
#define EEPROM_CHARGING_VOLTAGE_STATS_ADDR
#define EEPROM_BATTERY_VOLTAGE_STATS_ADDR
#define EEPROM_BOARD_TEMP_STATS_ADDR
#define EEPROM_FSK_INVALID_COUNTER_ADDR
#define EEPROM_CALLSIGN_LEN_ADDR
#define EEPROM_UPTIME_COUNTER_ADDR
#define EEPROM_BATTERY_TEMP_STATS_ADDR
#define EEPROM_CELL_B_VOLTAGE_STATS_ADDR
#define EEPROM_CELL_A_VOLTAGE_STATS_ADDR
#define EEPROM_LORA_VALID_COUNTER_ADDR
#define EEPROM_FSK_RECEIVE_LEN_ADDR
#define EEPROM_RESTART_COUNTER_ADDR
#define EEPROM_CHARGING_CURRENT_STATS_ADDR
#define EEPROM_FSK_VALID_COUNTER_ADDR
#define EEPROM_CELL_C_VOLTAGE_STATS_ADDR
#define EEPROM_MCU_TEMP_STATS_ADDR
#define EEPROM_DEPLOYMENT_COUNTER_ADDR
uint8_t spreadingFactorMode
const uint8_t encryptionKey[]
uint8_t currentModem
SX1268 radio
volatile bool dataReceived
const char * password
volatile bool interruptsEnabled
MorseClient morse
#define ANALOG_IN_SOLAR_C_VOLTAGE_PIN
#define ANALOG_IN_SOLAR_B_VOLTAGE_PIN
#define ANALOG_IN_SOLAR_A_VOLTAGE_PIN
#define RADIO_DIO1
#define SLEEP_LENGTH_CONSTANT
#define WATCHDOG_LOOP_HEARTBEAT_PERIOD
#define SYNC_WORD
#define FSK_RECEIVE_WINDOW_LENGTH
#define RESPONSE_DELAY
#define WHITENING_INITIAL
#define TCXO_VOLTAGE
#define LORA_PREAMBLE_LENGTH
#define LORA_BANDWIDTH
#define LORA_CODING_RATE
#define LORA_CURRENT_LIMIT
#define LORA_OUTPUT_POWER
#define LORA_CARRIER_FREQUENCY
#define MORSE_BATTERY_STEP
#define MORSE_BATTERY_MIN
#define MORSE_PREAMBLE_LENGTH
#define MORSE_SPEED
#define FSK_DATA_SHAPING
#define FSK_CARRIER_FREQUENCY
#define FSK_BIT_RATE
#define FSK_OUTPUT_POWER
#define FSK_RX_BANDWIDTH
#define FSK_PREAMBLE_LENGTH
#define FSK_FREQUENCY_DEVIATION
#define FSK_CURRENT_LIMIT
#define MAX_RADIO_BUFFER_LENGTH
#define MAX_STRING_LENGTH
#define MAX_OPT_DATA_LENGTH
#define BOARD_TEMP_SENSOR_ADDR
#define BATTERY_TEMP_SENSOR_ADDR
T Persistent_Storage_Read(uint16_t addr)
This function reads a value of type T from EEPROM.