star-mesh LoRa network
radio chip selection
Radio chip driver is not included, because options are available.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.
In this network, devices repeat messages to/from devices out of range of central gateway device. Appropriate for use when slightly larger batteries cost less than extra LoRaWAN gateways. This network uses LoRa transceiver directly and is not LoRaWAN. This network is appropriate for use where extra latency added from store-and-forward is of minimal consequence.
network implementation
Network achieves low-power operation by device waking up at regular intervals to check if LoRa preamble exists. If so, packet is received, otherwise devices sleeps. In this type of operation, trade-off is made between transmitter sending long preamble, and receiver waking up to receive this preamble along with associate message at the end of preamble. This long preamble is only used for request packets: the reply packet will have normal 8-symbol preamble length. This is known as asynchronous low-power operation, permitting an arbitrary number of devices to operate.
Devices start operation on the network by sending a discovery request to any devices that can hear it. Any devices which hears this discovery request will then send a discovery reply at randomized time offset relative to the request. After a pre-established time limit, the discovering device will decide which device to attach to depending on signal quality and how many hops away from the central gateway the device resides.
After device has attached to network, downlinks and uplinks can be sent to/from device. To facilitate downlinks, the devices closer to central gateway will be sent a new-device-notification to inform all devices between the central gateway and the newly attached device, which devices the new device can be reached via.
All devices have two logical interfaces to the network: An upstream interface, and a downstream interface. However, the central gateway device only has a downstream interface, because the "upstream" is only a UART interface to the user handling the user payloads on central gateway.
All devices on network are programmed with same firmware, except for gateway. In main.h #define GATEWAY
is commented-out for devices on network, or is defined for central gateway device. Only one central gateway must exist on this network. The unique identifying address of device is derived from CPU unique ID registers, of which 4 byte ID number is used on this network. Using this CPU serial number permits the same binary file to be programmed into any number of devices.
network configuration
Network is configured in main.h
define in main.h | ||
spreading factor | SPREADING_FACTOR | |
bandwidth | BW_KHZ | |
operating radio frequency | CF_MHZ | |
gateway or device | GATEWAY | |
transmit power | TX_DBM |
MAC layer timing scales according to LoRa symbol period. When spreading factor and/or bandwidth is changed, all network timing is scaled accordingly by MAC layer.
The transceivers used with the project operate at one datarate. This datarate is fixed, and must be defined at compile time for all devices and gateway.
low power operation
This MAC layer uses mbed eventqueue for scheduling. To enable low power operation, events.use-lowpower-timer-ticker
is defined in mbed_app.json
. This requires bare-metal operation to have eventqueue use low power timer, permitting deep sleep. LoRa applications such as this do not require RTOS: bare-metal mode is preferred for typical LoRa use.
application layer
User payloads are handled in app_endDevice.cpp
.
Uplinks are send from application layer by calling uplink(uint8_t *buffer_ptr, uint8_t length)
Downlinks are handled in callback function app_downlink()
For gateway, app_gateway.cpp
handles user payloads.
For downlinks, an example is provided in cmd_downlink()
where destination and payload is entered on serial port.
All uplinks are handled in callback function gateway_uplink()
.
Header file app.h
contains definitions common to application layer on both network central control and end device.
Note
This page describes how to use the network, for more detailed description of implementation, see details page.
serial terminal user interface
The STDIO UART is used to send and receive user-payload on the gateway, but is also available on end-devices. This serial port is configured at 115200 : 8,N,1.
command | arguments | description |
---|---|---|
? | list commands | |
dl | destID byte0 byte1 etc | send downlink to device (from gateway) |
ls | list downstream devices attached | |
op | dBm | manually change transmit power |
For the list of downstream devices, on start each row is printed directly attached device. If devices are attached further downstream, they will be subsequently printed on the same row.
testing / evaluation
Use 3 devices for testing: one gateway and two devices.
Three devices required for checking message repeating (relaying) function.
The gateway device must be installed at some distance to prevent both devices from connecting directly to gateway.
Gateway needs to be located far enough away, so signal strength preference overrides hop count from gateway.
app_sx127x.cpp@1:fcd4c56fc56c, 2019-12-03 (annotated)
- Committer:
- Wayne Roberts
- Date:
- Tue Dec 03 09:50:00 2019 -0800
- Revision:
- 1:fcd4c56fc56c
- Parent:
- 0:6015834e4279
remove radio driver
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Wayne Roberts |
0:6015834e4279 | 1 | #include "sx12xx.h" |
Wayne Roberts |
0:6015834e4279 | 2 | #ifdef SX127x_H |
Wayne Roberts |
0:6015834e4279 | 3 | #include "main.h" |
Wayne Roberts |
0:6015834e4279 | 4 | |
Wayne Roberts |
0:6015834e4279 | 5 | void lora_print_dio() |
Wayne Roberts |
0:6015834e4279 | 6 | { |
Wayne Roberts |
0:6015834e4279 | 7 | Radio::radio.RegDioMapping2.octet = Radio::radio.read_reg(REG_DIOMAPPING2); |
Wayne Roberts |
0:6015834e4279 | 8 | pc.printf("DIO5:"); |
Wayne Roberts |
0:6015834e4279 | 9 | switch (Radio::radio.RegDioMapping2.bits.Dio5Mapping) { |
Wayne Roberts |
0:6015834e4279 | 10 | case 0: pc.printf("ModeReady"); break; |
Wayne Roberts |
0:6015834e4279 | 11 | case 1: pc.printf("ClkOut"); break; |
Wayne Roberts |
0:6015834e4279 | 12 | case 2: pc.printf("ClkOut"); break; |
Wayne Roberts |
0:6015834e4279 | 13 | } |
Wayne Roberts |
0:6015834e4279 | 14 | pc.printf(" DIO4:"); |
Wayne Roberts |
0:6015834e4279 | 15 | switch (Radio::radio.RegDioMapping2.bits.Dio4Mapping) { |
Wayne Roberts |
0:6015834e4279 | 16 | case 0: pc.printf("CadDetected"); break; |
Wayne Roberts |
0:6015834e4279 | 17 | case 1: pc.printf("PllLock"); break; |
Wayne Roberts |
0:6015834e4279 | 18 | case 2: pc.printf("PllLock"); break; |
Wayne Roberts |
0:6015834e4279 | 19 | } |
Wayne Roberts |
0:6015834e4279 | 20 | Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1); |
Wayne Roberts |
0:6015834e4279 | 21 | pc.printf(" DIO3:"); |
Wayne Roberts |
0:6015834e4279 | 22 | switch (Radio::radio.RegDioMapping1.bits.Dio3Mapping) { |
Wayne Roberts |
0:6015834e4279 | 23 | case 0: pc.printf("CadDone"); break; |
Wayne Roberts |
0:6015834e4279 | 24 | case 1: pc.printf("ValidHeader"); break; |
Wayne Roberts |
0:6015834e4279 | 25 | case 2: pc.printf("PayloadCrcError"); break; |
Wayne Roberts |
0:6015834e4279 | 26 | } |
Wayne Roberts |
0:6015834e4279 | 27 | pc.printf(" DIO2:"); |
Wayne Roberts |
0:6015834e4279 | 28 | switch (Radio::radio.RegDioMapping1.bits.Dio2Mapping) { |
Wayne Roberts |
0:6015834e4279 | 29 | case 0: |
Wayne Roberts |
0:6015834e4279 | 30 | case 1: |
Wayne Roberts |
0:6015834e4279 | 31 | case 2: |
Wayne Roberts |
0:6015834e4279 | 32 | pc.printf("FhssChangeChannel"); |
Wayne Roberts |
0:6015834e4279 | 33 | break; |
Wayne Roberts |
0:6015834e4279 | 34 | } |
Wayne Roberts |
0:6015834e4279 | 35 | pc.printf(" DIO1:"); |
Wayne Roberts |
0:6015834e4279 | 36 | switch (Radio::radio.RegDioMapping1.bits.Dio1Mapping) { |
Wayne Roberts |
0:6015834e4279 | 37 | case 0: pc.printf("RxTimeout"); break; |
Wayne Roberts |
0:6015834e4279 | 38 | case 1: pc.printf("FhssChangeChannel"); break; |
Wayne Roberts |
0:6015834e4279 | 39 | case 2: pc.printf("CadDetected"); break; |
Wayne Roberts |
0:6015834e4279 | 40 | } |
Wayne Roberts |
0:6015834e4279 | 41 | pc.printf(" DIO0:"); |
Wayne Roberts |
0:6015834e4279 | 42 | switch (Radio::radio.RegDioMapping1.bits.Dio0Mapping) { |
Wayne Roberts |
0:6015834e4279 | 43 | case 0: pc.printf("RxDone"); break; |
Wayne Roberts |
0:6015834e4279 | 44 | case 1: pc.printf("TxDone"); break; |
Wayne Roberts |
0:6015834e4279 | 45 | case 2: pc.printf("CadDone"); break; |
Wayne Roberts |
0:6015834e4279 | 46 | } |
Wayne Roberts |
0:6015834e4279 | 47 | |
Wayne Roberts |
0:6015834e4279 | 48 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 49 | } |
Wayne Roberts |
0:6015834e4279 | 50 | |
Wayne Roberts |
0:6015834e4279 | 51 | void lora_printAgcAutoOn() |
Wayne Roberts |
0:6015834e4279 | 52 | { |
Wayne Roberts |
0:6015834e4279 | 53 | pc.printf("AgcAutoOn:%d", Radio::lora.getAgcAutoOn()); |
Wayne Roberts |
0:6015834e4279 | 54 | } |
Wayne Roberts |
0:6015834e4279 | 55 | |
Wayne Roberts |
0:6015834e4279 | 56 | void lora_printBw() |
Wayne Roberts |
0:6015834e4279 | 57 | { |
Wayne Roberts |
0:6015834e4279 | 58 | (void)Radio::lora.getBw(); |
Wayne Roberts |
0:6015834e4279 | 59 | |
Wayne Roberts |
0:6015834e4279 | 60 | pc.printf("Bw:"); |
Wayne Roberts |
0:6015834e4279 | 61 | if (Radio::radio.type == SX1276) { |
Wayne Roberts |
0:6015834e4279 | 62 | switch (Radio::lora.RegModemConfig.sx1276bits.Bw) { |
Wayne Roberts |
0:6015834e4279 | 63 | case 0: pc.printf("7.8KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 64 | case 1: pc.printf("10.4KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 65 | case 2: pc.printf("15.6KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 66 | case 3: pc.printf("20.8KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 67 | case 4: pc.printf("31.25KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 68 | case 5: pc.printf("41.7KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 69 | case 6: pc.printf("62.5KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 70 | case 7: pc.printf("125KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 71 | case 8: pc.printf("250KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 72 | case 9: pc.printf("500KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 73 | default: pc.printf("%x ", Radio::lora.RegModemConfig.sx1276bits.Bw); break; |
Wayne Roberts |
0:6015834e4279 | 74 | } |
Wayne Roberts |
0:6015834e4279 | 75 | } else if (Radio::radio.type == SX1272) { |
Wayne Roberts |
0:6015834e4279 | 76 | switch (Radio::lora.RegModemConfig.sx1272bits.Bw) { |
Wayne Roberts |
0:6015834e4279 | 77 | case 0: pc.printf("125KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 78 | case 1: pc.printf("250KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 79 | case 2: pc.printf("500KHz "); break; |
Wayne Roberts |
0:6015834e4279 | 80 | case 3: pc.printf("11b "); break; |
Wayne Roberts |
0:6015834e4279 | 81 | } |
Wayne Roberts |
0:6015834e4279 | 82 | } |
Wayne Roberts |
0:6015834e4279 | 83 | } |
Wayne Roberts |
0:6015834e4279 | 84 | |
Wayne Roberts |
0:6015834e4279 | 85 | void lora_printSf() |
Wayne Roberts |
0:6015834e4279 | 86 | { |
Wayne Roberts |
0:6015834e4279 | 87 | // spreading factor same between sx127[26] |
Wayne Roberts |
0:6015834e4279 | 88 | pc.printf("sf:%d ", Radio::lora.getSf()); |
Wayne Roberts |
0:6015834e4279 | 89 | } |
Wayne Roberts |
0:6015834e4279 | 90 | |
Wayne Roberts |
0:6015834e4279 | 91 | void lora_printTxContinuousMode() |
Wayne Roberts |
0:6015834e4279 | 92 | { |
Wayne Roberts |
0:6015834e4279 | 93 | pc.printf("TxContinuousMode:%d ", Radio::lora.RegModemConfig2.sx1276bits.TxContinuousMode); // same for sx1272 and sx1276 |
Wayne Roberts |
0:6015834e4279 | 94 | } |
Wayne Roberts |
0:6015834e4279 | 95 | |
Wayne Roberts |
0:6015834e4279 | 96 | void radio_printLoraIrqs(bool clear) |
Wayne Roberts |
0:6015834e4279 | 97 | { |
Wayne Roberts |
0:6015834e4279 | 98 | //RegIrqFlags_t RegIrqFlags; |
Wayne Roberts |
0:6015834e4279 | 99 | |
Wayne Roberts |
0:6015834e4279 | 100 | Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS); |
Wayne Roberts |
0:6015834e4279 | 101 | pc.printf("\r\nIrqFlags:"); |
Wayne Roberts |
0:6015834e4279 | 102 | if (Radio::lora.RegIrqFlags.bits.CadDetected) |
Wayne Roberts |
0:6015834e4279 | 103 | pc.printf("CadDetected "); |
Wayne Roberts |
0:6015834e4279 | 104 | if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) { |
Wayne Roberts |
0:6015834e4279 | 105 | //radio.RegHopChannel.octet = Radio::radio.read_reg(REG_LR_HOPCHANNEL); |
Wayne Roberts |
0:6015834e4279 | 106 | pc.printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel); |
Wayne Roberts |
0:6015834e4279 | 107 | } |
Wayne Roberts |
0:6015834e4279 | 108 | if (Radio::lora.RegIrqFlags.bits.CadDone) |
Wayne Roberts |
0:6015834e4279 | 109 | pc.printf("CadDone "); |
Wayne Roberts |
0:6015834e4279 | 110 | if (Radio::lora.RegIrqFlags.bits.TxDone) |
Wayne Roberts |
0:6015834e4279 | 111 | pc.printf("TxDone "); |
Wayne Roberts |
0:6015834e4279 | 112 | if (Radio::lora.RegIrqFlags.bits.ValidHeader) |
Wayne Roberts |
0:6015834e4279 | 113 | pc.printf("[42mValidHeader[0m "); |
Wayne Roberts |
0:6015834e4279 | 114 | if (Radio::lora.RegIrqFlags.bits.PayloadCrcError) |
Wayne Roberts |
0:6015834e4279 | 115 | pc.printf("[41mPayloadCrcError[0m "); |
Wayne Roberts |
0:6015834e4279 | 116 | if (Radio::lora.RegIrqFlags.bits.RxDone) |
Wayne Roberts |
0:6015834e4279 | 117 | pc.printf("[42mRxDone[0m "); |
Wayne Roberts |
0:6015834e4279 | 118 | if (Radio::lora.RegIrqFlags.bits.RxTimeout) |
Wayne Roberts |
0:6015834e4279 | 119 | pc.printf("RxTimeout "); |
Wayne Roberts |
0:6015834e4279 | 120 | |
Wayne Roberts |
0:6015834e4279 | 121 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 122 | |
Wayne Roberts |
0:6015834e4279 | 123 | if (clear) |
Wayne Roberts |
0:6015834e4279 | 124 | Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet); |
Wayne Roberts |
0:6015834e4279 | 125 | |
Wayne Roberts |
0:6015834e4279 | 126 | } |
Wayne Roberts |
0:6015834e4279 | 127 | |
Wayne Roberts |
0:6015834e4279 | 128 | void lora_printHeaderMode() |
Wayne Roberts |
0:6015834e4279 | 129 | { |
Wayne Roberts |
0:6015834e4279 | 130 | if (Radio::lora.getHeaderMode()) |
Wayne Roberts |
0:6015834e4279 | 131 | pc.printf("implicit "); |
Wayne Roberts |
0:6015834e4279 | 132 | else |
Wayne Roberts |
0:6015834e4279 | 133 | pc.printf("explicit "); |
Wayne Roberts |
0:6015834e4279 | 134 | } |
Wayne Roberts |
0:6015834e4279 | 135 | |
Wayne Roberts |
0:6015834e4279 | 136 | void lora_printRxPayloadCrcOn() |
Wayne Roberts |
0:6015834e4279 | 137 | { |
Wayne Roberts |
0:6015834e4279 | 138 | bool on = Radio::lora.getRxPayloadCrcOn(); |
Wayne Roberts |
0:6015834e4279 | 139 | pc.printf("RxPayloadCrcOn:%d = ", on); |
Wayne Roberts |
0:6015834e4279 | 140 | if (Radio::lora.getHeaderMode()) |
Wayne Roberts |
0:6015834e4279 | 141 | pc.printf("Rx/"); // implicit mode |
Wayne Roberts |
0:6015834e4279 | 142 | |
Wayne Roberts |
0:6015834e4279 | 143 | if (on) |
Wayne Roberts |
0:6015834e4279 | 144 | pc.printf("Tx CRC Enabled\r\n"); |
Wayne Roberts |
0:6015834e4279 | 145 | else |
Wayne Roberts |
0:6015834e4279 | 146 | pc.printf("Tx CRC disabled\r\n"); |
Wayne Roberts |
0:6015834e4279 | 147 | } |
Wayne Roberts |
0:6015834e4279 | 148 | |
Wayne Roberts |
0:6015834e4279 | 149 | void lora_printCodingRate(bool from_rx) |
Wayne Roberts |
0:6015834e4279 | 150 | { |
Wayne Roberts |
0:6015834e4279 | 151 | uint8_t d = Radio::lora.getCodingRate(from_rx); |
Wayne Roberts |
0:6015834e4279 | 152 | pc.printf("CodingRate:"); |
Wayne Roberts |
0:6015834e4279 | 153 | switch (d) { |
Wayne Roberts |
0:6015834e4279 | 154 | case 1: pc.printf("4/5 "); break; |
Wayne Roberts |
0:6015834e4279 | 155 | case 2: pc.printf("4/6 "); break; |
Wayne Roberts |
0:6015834e4279 | 156 | case 3: pc.printf("4/7 "); break; |
Wayne Roberts |
0:6015834e4279 | 157 | case 4: pc.printf("4/8 "); break; |
Wayne Roberts |
0:6015834e4279 | 158 | default: |
Wayne Roberts |
0:6015834e4279 | 159 | pc.printf("%d ", d); |
Wayne Roberts |
0:6015834e4279 | 160 | break; |
Wayne Roberts |
0:6015834e4279 | 161 | } |
Wayne Roberts |
0:6015834e4279 | 162 | } |
Wayne Roberts |
0:6015834e4279 | 163 | |
Wayne Roberts |
0:6015834e4279 | 164 | void lora_print_status() |
Wayne Roberts |
0:6015834e4279 | 165 | { |
Wayne Roberts |
0:6015834e4279 | 166 | Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); |
Wayne Roberts |
0:6015834e4279 | 167 | if (!Radio::radio.RegOpMode.bits.LongRangeMode) { |
Wayne Roberts |
0:6015834e4279 | 168 | pc.printf("FSK\r\n"); |
Wayne Roberts |
0:6015834e4279 | 169 | return; |
Wayne Roberts |
0:6015834e4279 | 170 | } |
Wayne Roberts |
0:6015834e4279 | 171 | |
Wayne Roberts |
0:6015834e4279 | 172 | //lora_print_dio(); |
Wayne Roberts |
0:6015834e4279 | 173 | pc.printf("LoRa "); |
Wayne Roberts |
0:6015834e4279 | 174 | |
Wayne Roberts |
0:6015834e4279 | 175 | // printing LoRa registers at 0x0d -> 0x3f |
Wayne Roberts |
0:6015834e4279 | 176 | |
Wayne Roberts |
0:6015834e4279 | 177 | Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG); |
Wayne Roberts |
0:6015834e4279 | 178 | Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2); |
Wayne Roberts |
0:6015834e4279 | 179 | |
Wayne Roberts |
0:6015834e4279 | 180 | lora_printCodingRate(false); // false: transmitted coding rate |
Wayne Roberts |
0:6015834e4279 | 181 | lora_printHeaderMode(); |
Wayne Roberts |
0:6015834e4279 | 182 | lora_printBw(); |
Wayne Roberts |
0:6015834e4279 | 183 | lora_printSf(); |
Wayne Roberts |
0:6015834e4279 | 184 | lora_printRxPayloadCrcOn(); |
Wayne Roberts |
0:6015834e4279 | 185 | // RegModemStat |
Wayne Roberts |
0:6015834e4279 | 186 | //pc.printf("ModemStat:0x%02x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT)); |
Wayne Roberts |
0:6015834e4279 | 187 | |
Wayne Roberts |
0:6015834e4279 | 188 | // fifo ptrs: |
Wayne Roberts |
0:6015834e4279 | 189 | Radio::lora.RegPayloadLength = Radio::radio.read_reg(REG_LR_PAYLOADLENGTH); |
Wayne Roberts |
0:6015834e4279 | 190 | Radio::lora.RegRxMaxPayloadLength = Radio::radio.read_reg(REG_LR_RX_MAX_PAYLOADLENGTH); |
Wayne Roberts |
0:6015834e4279 | 191 | /* pc.printf("fifoptr=0x%02x txbase=0x%02x rxbase=0x%02x payloadLength=0x%02x maxlen=0x%02x", |
Wayne Roberts |
0:6015834e4279 | 192 | Radio::radio.read_reg(REG_LR_FIFOADDRPTR), |
Wayne Roberts |
0:6015834e4279 | 193 | Radio::radio.read_reg(REG_LR_FIFOTXBASEADDR), |
Wayne Roberts |
0:6015834e4279 | 194 | Radio::radio.read_reg(REG_LR_FIFORXBASEADDR), |
Wayne Roberts |
0:6015834e4279 | 195 | Radio::lora.RegPayloadLength, |
Wayne Roberts |
0:6015834e4279 | 196 | Radio::lora.RegRxMaxPayloadLength |
Wayne Roberts |
0:6015834e4279 | 197 | );*/ |
Wayne Roberts |
0:6015834e4279 | 198 | |
Wayne Roberts |
0:6015834e4279 | 199 | pc.printf("dio0pin:%u ", Radio::radio.dio0.read()); |
Wayne Roberts |
0:6015834e4279 | 200 | Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS); |
Wayne Roberts |
0:6015834e4279 | 201 | radio_printLoraIrqs(false); |
Wayne Roberts |
0:6015834e4279 | 202 | |
Wayne Roberts |
0:6015834e4279 | 203 | /* Radio::lora.RegHopPeriod = Radio::radio.read_reg(REG_LR_HOPPERIOD); |
Wayne Roberts |
0:6015834e4279 | 204 | if (Radio::lora.RegHopPeriod != 0) { |
Wayne Roberts |
0:6015834e4279 | 205 | pc.printf("\r\nHopPeriod:0x%02x\r\n", Radio::lora.RegHopPeriod); |
Wayne Roberts |
0:6015834e4279 | 206 | }*/ |
Wayne Roberts |
0:6015834e4279 | 207 | |
Wayne Roberts |
0:6015834e4279 | 208 | pc.printf("SymbTimeout:%d ", Radio::radio.read_u16(REG_LR_MODEMCONFIG2) & 0x3ff); |
Wayne Roberts |
0:6015834e4279 | 209 | |
Wayne Roberts |
0:6015834e4279 | 210 | Radio::lora.RegPreamble = Radio::radio.read_u16(REG_LR_PREAMBLEMSB); |
Wayne Roberts |
0:6015834e4279 | 211 | pc.printf("PreambleLength:%d ", Radio::lora.RegPreamble); |
Wayne Roberts |
0:6015834e4279 | 212 | |
Wayne Roberts |
0:6015834e4279 | 213 | if (Radio::radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || Radio::radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE) { |
Wayne Roberts |
0:6015834e4279 | 214 | pc.printf("rssi:%ddBm ", Radio::lora.get_current_rssi()); |
Wayne Roberts |
0:6015834e4279 | 215 | } |
Wayne Roberts |
0:6015834e4279 | 216 | |
Wayne Roberts |
0:6015834e4279 | 217 | //lora_printTxContinuousMode(); |
Wayne Roberts |
0:6015834e4279 | 218 | |
Wayne Roberts |
0:6015834e4279 | 219 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 220 | //lora_printAgcAutoOn(); |
Wayne Roberts |
0:6015834e4279 | 221 | if (Radio::radio.type == SX1272) { |
Wayne Roberts |
0:6015834e4279 | 222 | pc.printf(" LowDataRateOptimize:%d\r\n", Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize); |
Wayne Roberts |
0:6015834e4279 | 223 | } |
Wayne Roberts |
0:6015834e4279 | 224 | |
Wayne Roberts |
0:6015834e4279 | 225 | /*pc.printf("\r\nHeaderCount:%d PacketCount:%d, ", |
Wayne Roberts |
0:6015834e4279 | 226 | Radio::radio.read_u16(REG_LR_RXHEADERCNTVALUE_MSB), Radio::radio.read_u16(REG_LR_RXPACKETCNTVALUE_MSB)); |
Wayne Roberts |
0:6015834e4279 | 227 | */ |
Wayne Roberts |
0:6015834e4279 | 228 | |
Wayne Roberts |
0:6015834e4279 | 229 | /*pc.printf("Lora detection threshold:%02x\r\n", Radio::radio.read_reg(REG_LR_DETECTION_THRESHOLD)); |
Wayne Roberts |
0:6015834e4279 | 230 | Radio::lora.RegTest31.octet = Radio::radio.read_reg(REG_LR_TEST31); |
Wayne Roberts |
0:6015834e4279 | 231 | pc.printf("detect_trig_same_peaks_nb:%d\r\n", Radio::lora.RegTest31.bits.detect_trig_same_peaks_nb);*/ |
Wayne Roberts |
0:6015834e4279 | 232 | |
Wayne Roberts |
0:6015834e4279 | 233 | if (Radio::radio.type == SX1272) { |
Wayne Roberts |
0:6015834e4279 | 234 | Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG); |
Wayne Roberts |
0:6015834e4279 | 235 | pc.printf("LowDataRateOptimize:%d ", Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize); |
Wayne Roberts |
0:6015834e4279 | 236 | } else if (Radio::radio.type == SX1276) { |
Wayne Roberts |
0:6015834e4279 | 237 | Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3); |
Wayne Roberts |
0:6015834e4279 | 238 | pc.printf("LowDataRateOptimize:%d ", Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize); |
Wayne Roberts |
0:6015834e4279 | 239 | } |
Wayne Roberts |
0:6015834e4279 | 240 | |
Wayne Roberts |
0:6015834e4279 | 241 | pc.printf(" invert: rx=%d tx=%d\r\n", Radio::lora.RegTest33.bits.invert_i_q, !Radio::lora.RegTest33.bits.chirp_invert_tx); |
Wayne Roberts |
0:6015834e4279 | 242 | |
Wayne Roberts |
0:6015834e4279 | 243 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 244 | } |
Wayne Roberts |
0:6015834e4279 | 245 | |
Wayne Roberts |
0:6015834e4279 | 246 | void |
Wayne Roberts |
0:6015834e4279 | 247 | printPa() |
Wayne Roberts |
0:6015834e4279 | 248 | { |
Wayne Roberts |
0:6015834e4279 | 249 | Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG); |
Wayne Roberts |
0:6015834e4279 | 250 | if (Radio::radio.RegPaConfig.bits.PaSelect) { |
Wayne Roberts |
0:6015834e4279 | 251 | float output_dBm = 17 - (15-Radio::radio.RegPaConfig.bits.OutputPower); |
Wayne Roberts |
0:6015834e4279 | 252 | pc.printf(" PABOOST OutputPower=%.1fdBm", output_dBm); |
Wayne Roberts |
0:6015834e4279 | 253 | } else { |
Wayne Roberts |
0:6015834e4279 | 254 | float pmax = (0.6*Radio::radio.RegPaConfig.bits.MaxPower) + 10.8; |
Wayne Roberts |
0:6015834e4279 | 255 | float output_dBm = pmax - (15-Radio::radio.RegPaConfig.bits.OutputPower); |
Wayne Roberts |
0:6015834e4279 | 256 | #ifdef TARGET_MTS_MDOT_F411RE |
Wayne Roberts |
0:6015834e4279 | 257 | pc.printf(" \x1b[31mRFO pmax=%.1fdBm OutputPower=%.1fdBm\x1b[0m", pmax, output_dBm); // not connected |
Wayne Roberts |
0:6015834e4279 | 258 | #else |
Wayne Roberts |
0:6015834e4279 | 259 | pc.printf(" RFO pmax=%.1fdBm OutputPower=%.1fdBm", pmax, output_dBm); |
Wayne Roberts |
0:6015834e4279 | 260 | #endif |
Wayne Roberts |
0:6015834e4279 | 261 | } |
Wayne Roberts |
0:6015834e4279 | 262 | } |
Wayne Roberts |
0:6015834e4279 | 263 | |
Wayne Roberts |
0:6015834e4279 | 264 | bool isRadioRxing() |
Wayne Roberts |
0:6015834e4279 | 265 | { |
Wayne Roberts |
0:6015834e4279 | 266 | Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); |
Wayne Roberts |
0:6015834e4279 | 267 | return Radio::radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || Radio::radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE; |
Wayne Roberts |
0:6015834e4279 | 268 | } |
Wayne Roberts |
0:6015834e4279 | 269 | |
Wayne Roberts |
0:6015834e4279 | 270 | void radio_printOpMode() |
Wayne Roberts |
0:6015834e4279 | 271 | { |
Wayne Roberts |
0:6015834e4279 | 272 | Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); |
Wayne Roberts |
0:6015834e4279 | 273 | switch (Radio::radio.RegOpMode.bits.Mode) { |
Wayne Roberts |
0:6015834e4279 | 274 | case RF_OPMODE_SLEEP: pc.printf("[7msleep[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 275 | case RF_OPMODE_STANDBY: pc.printf("[7mstby[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 276 | case RF_OPMODE_SYNTHESIZER_TX: pc.printf("[33mfstx[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 277 | case RF_OPMODE_TRANSMITTER: pc.printf("[31mtx[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 278 | case RF_OPMODE_SYNTHESIZER_RX: pc.printf("[33mfsrx[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 279 | case RF_OPMODE_RECEIVER: pc.printf("[32mrx[0m"); break; |
Wayne Roberts |
0:6015834e4279 | 280 | case 6: |
Wayne Roberts |
0:6015834e4279 | 281 | if (Radio::radio.RegOpMode.bits.LongRangeMode) |
Wayne Roberts |
0:6015834e4279 | 282 | pc.printf("[42mrxs[0m"); |
Wayne Roberts |
0:6015834e4279 | 283 | else |
Wayne Roberts |
0:6015834e4279 | 284 | pc.printf("-6-"); |
Wayne Roberts |
0:6015834e4279 | 285 | break; // todo: different lora/fsk |
Wayne Roberts |
0:6015834e4279 | 286 | case 7: |
Wayne Roberts |
0:6015834e4279 | 287 | if (Radio::radio.RegOpMode.bits.LongRangeMode) |
Wayne Roberts |
0:6015834e4279 | 288 | pc.printf("[45mcad[0m"); |
Wayne Roberts |
0:6015834e4279 | 289 | else |
Wayne Roberts |
0:6015834e4279 | 290 | pc.printf("-7-"); |
Wayne Roberts |
0:6015834e4279 | 291 | break; // todo: different lora/fsk |
Wayne Roberts |
0:6015834e4279 | 292 | } |
Wayne Roberts |
0:6015834e4279 | 293 | } |
Wayne Roberts |
0:6015834e4279 | 294 | |
Wayne Roberts |
0:6015834e4279 | 295 | void /* things always present, whether lora or fsk */ |
Wayne Roberts |
0:6015834e4279 | 296 | common_print_status() |
Wayne Roberts |
0:6015834e4279 | 297 | { |
Wayne Roberts |
0:6015834e4279 | 298 | pc.printf("version:0x%02x %.3fMHz ", Radio::radio.read_reg(REG_VERSION), Radio::radio.get_frf_MHz()); |
Wayne Roberts |
0:6015834e4279 | 299 | radio_printOpMode(); |
Wayne Roberts |
0:6015834e4279 | 300 | |
Wayne Roberts |
0:6015834e4279 | 301 | printPa(); |
Wayne Roberts |
0:6015834e4279 | 302 | |
Wayne Roberts |
0:6015834e4279 | 303 | Radio::radio.RegOcp.octet = Radio::radio.read_reg(REG_OCP); |
Wayne Roberts |
0:6015834e4279 | 304 | if (Radio::radio.RegOcp.bits.OcpOn) { |
Wayne Roberts |
0:6015834e4279 | 305 | int imax = 0; |
Wayne Roberts |
0:6015834e4279 | 306 | if (Radio::radio.RegOcp.bits.OcpTrim < 16) |
Wayne Roberts |
0:6015834e4279 | 307 | imax = 45 + (5 * Radio::radio.RegOcp.bits.OcpTrim); |
Wayne Roberts |
0:6015834e4279 | 308 | else if (Radio::radio.RegOcp.bits.OcpTrim < 28) |
Wayne Roberts |
0:6015834e4279 | 309 | imax = -30 + (10 * Radio::radio.RegOcp.bits.OcpTrim); |
Wayne Roberts |
0:6015834e4279 | 310 | else |
Wayne Roberts |
0:6015834e4279 | 311 | imax = 240; |
Wayne Roberts |
0:6015834e4279 | 312 | pc.printf(" OcpOn %dmA ", imax); |
Wayne Roberts |
0:6015834e4279 | 313 | } else |
Wayne Roberts |
0:6015834e4279 | 314 | pc.printf(" OcpOFF "); |
Wayne Roberts |
0:6015834e4279 | 315 | |
Wayne Roberts |
0:6015834e4279 | 316 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 317 | |
Wayne Roberts |
0:6015834e4279 | 318 | #if 0 |
Wayne Roberts |
0:6015834e4279 | 319 | if (per_en) { |
Wayne Roberts |
0:6015834e4279 | 320 | if (cadper_enable) { |
Wayne Roberts |
0:6015834e4279 | 321 | pc.printf("cadper %" PRIu32 ", ", num_cads); |
Wayne Roberts |
0:6015834e4279 | 322 | } |
Wayne Roberts |
0:6015834e4279 | 323 | pc.printf("per_tx_delay:%f\r\n", per_tx_delay); |
Wayne Roberts |
0:6015834e4279 | 324 | pc.printf("PER device ID:%d\r\n", per_id); |
Wayne Roberts |
0:6015834e4279 | 325 | } |
Wayne Roberts |
0:6015834e4279 | 326 | |
Wayne Roberts |
0:6015834e4279 | 327 | if (poll_irq_en) { |
Wayne Roberts |
0:6015834e4279 | 328 | pc.printf("poll_irq_en\r\n"); |
Wayne Roberts |
0:6015834e4279 | 329 | if (!Radio::radio.RegOpMode.bits.LongRangeMode) { |
Wayne Roberts |
0:6015834e4279 | 330 | pc.printf("saved irqs: %02x %02x\r\n", fsk_RegIrqFlags1_prev.octet, fsk_RegIrqFlags2_prev.octet); |
Wayne Roberts |
0:6015834e4279 | 331 | } |
Wayne Roberts |
0:6015834e4279 | 332 | } |
Wayne Roberts |
0:6015834e4279 | 333 | #endif /* if 0 */ |
Wayne Roberts |
0:6015834e4279 | 334 | |
Wayne Roberts |
0:6015834e4279 | 335 | } |
Wayne Roberts |
0:6015834e4279 | 336 | |
Wayne Roberts |
0:6015834e4279 | 337 | void radio_print_status() |
Wayne Roberts |
0:6015834e4279 | 338 | { |
Wayne Roberts |
0:6015834e4279 | 339 | if (Radio::radio.type == SX1276) { |
Wayne Roberts |
0:6015834e4279 | 340 | #if defined(TARGET_MTS_MDOT_F411RE) |
Wayne Roberts |
0:6015834e4279 | 341 | pc.printf("\r\nSX1276 "); |
Wayne Roberts |
0:6015834e4279 | 342 | #else |
Wayne Roberts |
0:6015834e4279 | 343 | /*if (shield_type == SHIELD_TYPE_LAS) |
Wayne Roberts |
0:6015834e4279 | 344 | pc.printf("\r\nSX1276LAS "); |
Wayne Roberts |
0:6015834e4279 | 345 | if (shield_type == SHIELD_TYPE_MAS) |
Wayne Roberts |
0:6015834e4279 | 346 | pc.printf("\r\nSX1276MAS ");*/ |
Wayne Roberts |
0:6015834e4279 | 347 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 348 | #endif /* !TARGET_MTS_MDOT_F411RE */ |
Wayne Roberts |
0:6015834e4279 | 349 | } else if (Radio::radio.type == SX1272) |
Wayne Roberts |
0:6015834e4279 | 350 | pc.printf("\r\nSX1272 "); |
Wayne Roberts |
0:6015834e4279 | 351 | |
Wayne Roberts |
0:6015834e4279 | 352 | Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE); |
Wayne Roberts |
0:6015834e4279 | 353 | if (Radio::radio.RegOpMode.bits.LongRangeMode) |
Wayne Roberts |
0:6015834e4279 | 354 | lora_print_status(); |
Wayne Roberts |
0:6015834e4279 | 355 | /*else |
Wayne Roberts |
0:6015834e4279 | 356 | fsk_print_status();*/ |
Wayne Roberts |
0:6015834e4279 | 357 | common_print_status(); |
Wayne Roberts |
0:6015834e4279 | 358 | } |
Wayne Roberts |
0:6015834e4279 | 359 | |
Wayne Roberts |
0:6015834e4279 | 360 | void tx_dbm_print() |
Wayne Roberts |
0:6015834e4279 | 361 | { |
Wayne Roberts |
0:6015834e4279 | 362 | int dbm; |
Wayne Roberts |
0:6015834e4279 | 363 | RegPdsTrim1_t pds_trim; |
Wayne Roberts |
0:6015834e4279 | 364 | uint8_t adr, pa_test_adr; |
Wayne Roberts |
0:6015834e4279 | 365 | |
Wayne Roberts |
0:6015834e4279 | 366 | if (Radio::radio.type == SX1276) { |
Wayne Roberts |
0:6015834e4279 | 367 | adr = REG_PDSTRIM1_SX1276; |
Wayne Roberts |
0:6015834e4279 | 368 | pa_test_adr = REG_PATEST_SX1276; |
Wayne Roberts |
0:6015834e4279 | 369 | } else { |
Wayne Roberts |
0:6015834e4279 | 370 | adr = REG_PDSTRIM1_SX1272; |
Wayne Roberts |
0:6015834e4279 | 371 | pa_test_adr = REG_PATEST_SX1272; |
Wayne Roberts |
0:6015834e4279 | 372 | } |
Wayne Roberts |
0:6015834e4279 | 373 | |
Wayne Roberts |
0:6015834e4279 | 374 | if (Radio::radio.read_reg(pa_test_adr) & 0x20) { |
Wayne Roberts |
0:6015834e4279 | 375 | pds_trim.octet = Radio::radio.read_reg(adr); |
Wayne Roberts |
0:6015834e4279 | 376 | |
Wayne Roberts |
0:6015834e4279 | 377 | Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG); |
Wayne Roberts |
0:6015834e4279 | 378 | if (Radio::radio.RegPaConfig.bits.PaSelect) { |
Wayne Roberts |
0:6015834e4279 | 379 | dbm = Radio::radio.RegPaConfig.bits.OutputPower + pds_trim.bits.prog_txdac - 2; |
Wayne Roberts |
0:6015834e4279 | 380 | } else { |
Wayne Roberts |
0:6015834e4279 | 381 | dbm = Radio::radio.RegPaConfig.bits.OutputPower - 1; |
Wayne Roberts |
0:6015834e4279 | 382 | } |
Wayne Roberts |
0:6015834e4279 | 383 | } else { |
Wayne Roberts |
0:6015834e4279 | 384 | dbm = PA_OFF_DBM; |
Wayne Roberts |
0:6015834e4279 | 385 | } |
Wayne Roberts |
0:6015834e4279 | 386 | pc.printf("%d", dbm); |
Wayne Roberts |
0:6015834e4279 | 387 | } |
Wayne Roberts |
0:6015834e4279 | 388 | |
Wayne Roberts |
0:6015834e4279 | 389 | bool tx_dbm_write(int i) |
Wayne Roberts |
0:6015834e4279 | 390 | { |
Wayne Roberts |
0:6015834e4279 | 391 | uint8_t v, adr, pa_test_adr; |
Wayne Roberts |
0:6015834e4279 | 392 | RegPdsTrim1_t pds_trim; |
Wayne Roberts |
0:6015834e4279 | 393 | |
Wayne Roberts |
0:6015834e4279 | 394 | if (Radio::radio.type == SX1276) { |
Wayne Roberts |
0:6015834e4279 | 395 | adr = REG_PDSTRIM1_SX1276; |
Wayne Roberts |
0:6015834e4279 | 396 | pa_test_adr = REG_PATEST_SX1276; |
Wayne Roberts |
0:6015834e4279 | 397 | } else { |
Wayne Roberts |
0:6015834e4279 | 398 | adr = REG_PDSTRIM1_SX1272; |
Wayne Roberts |
0:6015834e4279 | 399 | pa_test_adr = REG_PATEST_SX1272; |
Wayne Roberts |
0:6015834e4279 | 400 | } |
Wayne Roberts |
0:6015834e4279 | 401 | |
Wayne Roberts |
0:6015834e4279 | 402 | v = Radio::radio.read_reg(pa_test_adr); |
Wayne Roberts |
0:6015834e4279 | 403 | |
Wayne Roberts |
0:6015834e4279 | 404 | if (i == PA_OFF_DBM) { |
Wayne Roberts |
0:6015834e4279 | 405 | /* for bench testing: prevent overloading receiving station (very low TX power) */ |
Wayne Roberts |
0:6015834e4279 | 406 | v &= ~0x20; // turn off pu_regpa_n: disable PA |
Wayne Roberts |
0:6015834e4279 | 407 | Radio::radio.write_reg(pa_test_adr, v); |
Wayne Roberts |
0:6015834e4279 | 408 | return false; |
Wayne Roberts |
0:6015834e4279 | 409 | } else if ((v & 0x20) == 0) { |
Wayne Roberts |
0:6015834e4279 | 410 | v |= 0x20; // turn on pu_regpa_n: enable PA |
Wayne Roberts |
0:6015834e4279 | 411 | Radio::radio.write_reg(pa_test_adr, v); |
Wayne Roberts |
0:6015834e4279 | 412 | } |
Wayne Roberts |
0:6015834e4279 | 413 | |
Wayne Roberts |
0:6015834e4279 | 414 | pds_trim.octet = Radio::radio.read_reg(adr); |
Wayne Roberts |
0:6015834e4279 | 415 | |
Wayne Roberts |
0:6015834e4279 | 416 | if (Radio::radio.RegPaConfig.bits.PaSelect) { |
Wayne Roberts |
0:6015834e4279 | 417 | /* PABOOST used: +2dbm to +17, or +20 */ |
Wayne Roberts |
0:6015834e4279 | 418 | if (i == 20) { |
Wayne Roberts |
0:6015834e4279 | 419 | pc.printf("+20dBm PADAC bias\r\n"); |
Wayne Roberts |
0:6015834e4279 | 420 | i -= 3; |
Wayne Roberts |
0:6015834e4279 | 421 | pds_trim.bits.prog_txdac = 7; |
Wayne Roberts |
0:6015834e4279 | 422 | Radio::radio.write_reg(adr, pds_trim.octet); |
Wayne Roberts |
0:6015834e4279 | 423 | } |
Wayne Roberts |
0:6015834e4279 | 424 | if (i > 1) |
Wayne Roberts |
0:6015834e4279 | 425 | Radio::radio.RegPaConfig.bits.OutputPower = i - 2; |
Wayne Roberts |
0:6015834e4279 | 426 | } else { |
Wayne Roberts |
0:6015834e4279 | 427 | /* RFO used: -1 to +14dbm */ |
Wayne Roberts |
0:6015834e4279 | 428 | if (i < 15) |
Wayne Roberts |
0:6015834e4279 | 429 | Radio::radio.RegPaConfig.bits.OutputPower = i + 1; |
Wayne Roberts |
0:6015834e4279 | 430 | } |
Wayne Roberts |
0:6015834e4279 | 431 | Radio::radio.write_reg(REG_PACONFIG, Radio::radio.RegPaConfig.octet); |
Wayne Roberts |
0:6015834e4279 | 432 | |
Wayne Roberts |
0:6015834e4279 | 433 | return false; |
Wayne Roberts |
0:6015834e4279 | 434 | } |
Wayne Roberts |
0:6015834e4279 | 435 | |
Wayne Roberts |
0:6015834e4279 | 436 | void cmd_op(uint8_t argsAt) |
Wayne Roberts |
0:6015834e4279 | 437 | { |
Wayne Roberts |
0:6015834e4279 | 438 | int dbm; |
Wayne Roberts |
0:6015834e4279 | 439 | if (sscanf(pcbuf+argsAt, "%d", &dbm) == 1) { |
Wayne Roberts |
0:6015834e4279 | 440 | tx_dbm_write(dbm); |
Wayne Roberts |
0:6015834e4279 | 441 | } |
Wayne Roberts |
0:6015834e4279 | 442 | |
Wayne Roberts |
0:6015834e4279 | 443 | tx_dbm_print(); |
Wayne Roberts |
0:6015834e4279 | 444 | } |
Wayne Roberts |
0:6015834e4279 | 445 | #endif /* ..SX127x_H */ |