star-mesh LoRa network

Dependencies:   sx12xx_hal

start-mesh

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 factorSPREADING_FACTOR
bandwidthBW_KHZ
operating radio frequencyCF_MHZ
gateway or deviceGATEWAY
transmit powerTX_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.

commandargumentsdescription
?list commands
dldestID byte0 byte1 etcsend downlink to device (from gateway)
lslist downstream devices attached
opdBmmanually 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.

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?

UserRevisionLine numberNew 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("ValidHeader ");
Wayne Roberts 0:6015834e4279 114 if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
Wayne Roberts 0:6015834e4279 115 pc.printf("PayloadCrcError ");
Wayne Roberts 0:6015834e4279 116 if (Radio::lora.RegIrqFlags.bits.RxDone)
Wayne Roberts 0:6015834e4279 117 pc.printf("RxDone ");
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("sleep"); break;
Wayne Roberts 0:6015834e4279 275 case RF_OPMODE_STANDBY: pc.printf("stby"); break;
Wayne Roberts 0:6015834e4279 276 case RF_OPMODE_SYNTHESIZER_TX: pc.printf("fstx"); break;
Wayne Roberts 0:6015834e4279 277 case RF_OPMODE_TRANSMITTER: pc.printf("tx"); break;
Wayne Roberts 0:6015834e4279 278 case RF_OPMODE_SYNTHESIZER_RX: pc.printf("fsrx"); break;
Wayne Roberts 0:6015834e4279 279 case RF_OPMODE_RECEIVER: pc.printf("rx"); 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("rxs");
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("cad");
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 */