Synchronous wireless star LoRa network, central device.

Dependencies:   SX127x sx12xx_hal

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
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 SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.


Alternate to this project gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Synchronous Star Network

This project acts as central node for LoRaWAN-like network operating on single radio channel. Intended for use where network infrastructure would never exist due to cost and/or complexity of standard network. This project uses the class-B method of beacon generation to synchronize the end nodes with the gateway. OTA mode must be used. End-node will be allocated an uplink time slot upon joining. End node may transmit uplink at this assigned timeslot, if it desires to do so. This time slot is always referenced to the beacon sent by gateway.

LoRaWAN server is not necessary. All network control is implemented by this project. User can observe network activity on the mbed serial port. Downlinks can be scheduled using command on serial port.

This implementation must not be used on radio channels requiring duty-cycle transmit limiting.

alterations from LoRaWAN specification

This mode of operation uses a single datarate on single radio channel. ADR is not implemented, because datarate cannot be changed. OTA mode must be used. When join-accept is sent by gateway, it will have appended (instead of CFlist) the beacon timing answer to inform of when next beacon occurs, and two timing values: the time slot allocated to this end-node and the periodicity of the network. Periodicity means how often the end-node may again transmit. /media/uploads/dudmuck/class-b-single.png Beacon is sent for purpose of providing timing reference to end-nodes. The beacon payload may contain a broadcast command to end nodes. Time value is not sent in beacon payload. The time at which beacon is sent provides timing reference: every 128 seconds as standard.

Rx2 receive window is not implemented. Only Rx1 is used because a single radio channel is used. Rx1 delay is reduced to 100 milliseconds. Original LoRaWAN has 1000 millisecond Rx1 delay to accommodate internet latency.

LoRaWAN standard class-B beacon requires GPS timing reference. This implementation does not use GPS, instead a hardware timer peripheral generates interrupts to send beacons. Absolute accuracy is not required, only relative crystal drift between gateway and end-nodes is considered.

Timing values are always specified as 30ms per step as in LoRaWAN standard. Each beacon period has 4096 30ms steps per beacon period.

join OTA procedure

The join procedure has changed the join-accept delay to 100 milliseconds (standard is 5 seconds). This allows end-node to hunt for gateway on several channels during joining. When gateway starts, it will scan available channels for the optimal choice based on ambient noise on the channels. End node will retry join request until it finds the gateway. Gateway might change channel during operation if it deems current channel too busy.

configuration of network

End nodes must be provisioned by editing file Comissioning.h. The array motes lists every end node permitted on network. It contains appEui, devEUI and appKey just as specified in standard LoRaWAN. All provisioning is hard-coded; changing provisioning requires reprogramming gateway. When changing number of motes, N_MOTES definition must be changed in lorawan.h.

lorawan.h

#define N_MOTES     8
extern ota_mote_t motes[N_MOTES];   /* from Comissioning.h */

configuring number of end-nodes vs transmit rate

Trade-off can be selected between number of end-nodes on network vs. how often each end-node can transmit.
In this example, where DR_13 is SF7 at 500KHz:

lorawan.cpp

    #elif (LORAMAC_DEFAULT_DATARATE == DR_13)
        #define TX_SLOT_STEPPING        8  //approx 0.25 seconds
        #define PERIODICITY_SLOTS       (TX_SLOT_STEPPING * 6)
    #endif

Here, each end-node is given time of 240ms = 8 * 30ms; accommodating maximum payload length for both uplink and downlink.
6 in this code is the maximum count of end nodes using this gateway. Each end-node can transmit every 1.44 seconds, in this example.
If you wanted to change 6 to 20 end-nodes, each would be able to use network every 4.8 seconds.
Another example: If you wanted to use DR_12 = SF8, you would have approx 2.5 to 3dB more gain compared to SF7, but each end-node must be given double time, resulting in 20 nodes able to use network every 9.6 seconds at DR_12.

network capacity limitation

The number of end-nodes which can be supported is determined by number of SLOT_STEPPING's which can occur during BEACON_PERIOD. Beacon guard is implemented same as standard LoRaWAN, which is 3 seconds prior to beacon start and 2.12 seconds after beacon start, which gives 122.88 seconds for network traffic for each beacon period.

gateway configuration

spreading factor is declared at #define LORAMAC_DEFAULT_DATARATE in lorawan.h, valid rates are DR_8 to DR_13 (sf12 to sf7). In the end-node, the same definition must be configured in LoRaMac-definitions.h. This network operates at this constant datarate for all packets.
Band plan can be selected by defining USE_BAND_* in lorawan.h. 434MHz can be used on SX1276 shield. TypeABZ module and sx1272 only support 800/900MHz channels band.

end-node provisioning

Security permits only matching DevEUI / AppEui to join the network, due to unique AES root key for each end device; in this case the DevEUI must be programmed in advance into gateway. However, if the same AES root key could be used for each end device , then any number of end devices could be added at a later time, without checking DevEUI on the gateway when an end device joins the network. On the gateway, the end device join acceptance is performed in file lorawan.cpp LoRaWan::parse_receive() where MType == MTYPE_JOIN_REQ. A memcmp() is performed on both DevEUI and AppEUI.

If you wish to allow any DevEUI to join, define ANY_DEVEUI at top of lorawan.cpp . In this configuration, all end devices must use same AppEUI and AES key. N_MOTES must be defined to the maximum number of end devices expected. Test end device by commenting BoardGetUniqueId() in end node, and replace DevEui[] with 8 arbitrary bytes to verify gateway permits any DevEUI to join.

RAM usage

For gateway CPU, recommend to consider larger RAM size depending on number of end devices required. ota_motes_t has size of 123 bytes. Each end device has one of these, however if less RAM usage is required for more end-devices, the MAC command queue size may be reduced.

hardware support

The radio driver supports both SX1272 and SX1276, sx126x kit, sx126x radio-only shield, and sx128x 2.4GHz.. The selection of radio chip type is made by your choice of importing radio driver library.



Beacon generation requires low power ticker to be clocked from crystal, not internal RC oscillator.

Gateway Serial Interface

Gateway serial port operates at 115200bps.

commandargumentdescription
list-list joined end nodes
?-list available commands
dl<mote-hex-dev-addr> <hex-payload>send downlink, sent after uplink received
gpo<mote-hex-dev-addr> <0 or 1>set output PC6 pin level on end device
b32bit hex valueset beacon payload to be sent at next beacon
. (period)-print current status
opdBmconfigure TX power of gateway
sbcountskip sending beacons, for testing end node
fhex devAddrprinter filtering, show only single end node
hm-print filtering, hide MAC layer printing
hp-print filtering, hide APP layer printing
sa-print filtering, show all, undo hm and hp

Any received uplink will be printed with DevAddr and decrypted payload.

Committer:
Wayne Roberts
Date:
Thu Dec 13 16:53:37 2018 -0800
Revision:
22:dd3023aac3b1
Parent:
21:1ac5ffad2726
Child:
23:801d4bd6dccc
add sx1280, add beacon duration to join accept

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:2ff18de8d48b 1 #include "lorawan.h"
dudmuck 8:307f7faeb594 2 #include "commands.h"
Wayne Roberts 21:1ac5ffad2726 3 #include "TimeoutAbs.h"
Wayne Roberts 21:1ac5ffad2726 4 #include "SPIu.h"
dudmuck 13:fa2095be01c4 5 #define __STDC_FORMAT_MACROS
dudmuck 13:fa2095be01c4 6 #include <inttypes.h>
dudmuck 0:2ff18de8d48b 7
Wayne Roberts 21:1ac5ffad2726 8 #define PREAMBLE_SYMBS 8
Wayne Roberts 21:1ac5ffad2726 9
Wayne Roberts 21:1ac5ffad2726 10 #define BEACON_PRELOAD_us 500000
Wayne Roberts 22:dd3023aac3b1 11 #define BEACON_INTERVAL_SECONDS_us /*16000000*/ 128000000 /*8000000*/
Wayne Roberts 21:1ac5ffad2726 12 volatile us_timestamp_t beaconAt;
Wayne Roberts 21:1ac5ffad2726 13 TimeoutAbs load_beaconTimer;
Wayne Roberts 21:1ac5ffad2726 14 TimeoutAbs send_beaconTimer;
Wayne Roberts 21:1ac5ffad2726 15
dudmuck 4:7e743e402681 16 RawSerial pc(USBTX, USBRX);
dudmuck 0:2ff18de8d48b 17 Timer timer;
dudmuck 0:2ff18de8d48b 18
dudmuck 0:2ff18de8d48b 19 char pcbuf[64];
dudmuck 0:2ff18de8d48b 20 int pcbuf_len;
dudmuck 9:a0ce66c18ec0 21 uint8_t beacon_payload[4];
dudmuck 0:2ff18de8d48b 22
dudmuck 0:2ff18de8d48b 23 unsigned int skip_beacon_cnt;
dudmuck 0:2ff18de8d48b 24
dudmuck 12:9a8c13c4298b 25 float starting_bg_rssi;
Wayne Roberts 22:dd3023aac3b1 26 volatile uint32_t usingChHz;
dudmuck 0:2ff18de8d48b 27
dudmuck 0:2ff18de8d48b 28 #define N_SAMPLES 64
dudmuck 0:2ff18de8d48b 29 void channel_scan()
dudmuck 0:2ff18de8d48b 30 {
dudmuck 0:2ff18de8d48b 31 int min_ch, ch;
dudmuck 0:2ff18de8d48b 32 uint32_t hz = LORAMAC_FIRST_CHANNEL;
dudmuck 0:2ff18de8d48b 33 int acc[LORA_MAX_NB_CHANNELS];
dudmuck 0:2ff18de8d48b 34
Wayne Roberts 21:1ac5ffad2726 35 Radio::Standby( );
Wayne Roberts 21:1ac5ffad2726 36 wait(0.02);
dudmuck 0:2ff18de8d48b 37
dudmuck 0:2ff18de8d48b 38 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 39 int i;
Wayne Roberts 21:1ac5ffad2726 40 Radio::SetChannel(hz);
Wayne Roberts 21:1ac5ffad2726 41 Radio::Rx(0);
dudmuck 0:2ff18de8d48b 42 acc[ch] = 0;
dudmuck 0:2ff18de8d48b 43 for (i = 0; i < N_SAMPLES; i++) {
Wayne Roberts 21:1ac5ffad2726 44 int rssi = Radio::GetRssiInst();
dudmuck 0:2ff18de8d48b 45 acc[ch] += rssi;
dudmuck 0:2ff18de8d48b 46 wait(0.01);
dudmuck 0:2ff18de8d48b 47 }
Wayne Roberts 21:1ac5ffad2726 48 Radio::Standby( );
Wayne Roberts 21:1ac5ffad2726 49 pc.printf("ch%u: %f\r\n", ch, acc[ch] / (float)N_SAMPLES);
dudmuck 0:2ff18de8d48b 50 hz += LORAMAC_STEPWIDTH_CHANNEL;
Wayne Roberts 21:1ac5ffad2726 51 wait(0.02);
Wayne Roberts 21:1ac5ffad2726 52 Radio::SetChannel(hz);
dudmuck 0:2ff18de8d48b 53 }
dudmuck 0:2ff18de8d48b 54
dudmuck 0:2ff18de8d48b 55 int min = 0x7fffffff;
dudmuck 0:2ff18de8d48b 56 min_ch = 0;
dudmuck 0:2ff18de8d48b 57 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 58 if (acc[ch] < min) {
dudmuck 0:2ff18de8d48b 59 min = acc[ch];
dudmuck 0:2ff18de8d48b 60 min_ch = ch;
dudmuck 0:2ff18de8d48b 61 }
dudmuck 0:2ff18de8d48b 62 }
dudmuck 0:2ff18de8d48b 63 hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
Wayne Roberts 21:1ac5ffad2726 64 pc.printf("using ch%u, %luhz\r\n", min_ch, hz);
Wayne Roberts 21:1ac5ffad2726 65 Radio::SetChannel(hz);
Wayne Roberts 22:dd3023aac3b1 66 usingChHz = hz;
dudmuck 12:9a8c13c4298b 67
dudmuck 12:9a8c13c4298b 68 starting_bg_rssi = acc[min_ch] / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 69 }
dudmuck 12:9a8c13c4298b 70
dudmuck 12:9a8c13c4298b 71 void measure_ambient()
dudmuck 12:9a8c13c4298b 72 {
dudmuck 12:9a8c13c4298b 73 int i, acc = 0;
dudmuck 12:9a8c13c4298b 74 float bg_rssi;
dudmuck 12:9a8c13c4298b 75 float diff;
dudmuck 12:9a8c13c4298b 76 static unsigned cnt = 0;
dudmuck 12:9a8c13c4298b 77
dudmuck 12:9a8c13c4298b 78 for (i = 0; i < N_SAMPLES; i++) {
Wayne Roberts 21:1ac5ffad2726 79 int rssi = Radio::GetRssiInst();
dudmuck 12:9a8c13c4298b 80 acc += rssi;
dudmuck 12:9a8c13c4298b 81 wait(0.01);
dudmuck 12:9a8c13c4298b 82 }
dudmuck 12:9a8c13c4298b 83 bg_rssi = acc / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 84 diff = bg_rssi - starting_bg_rssi;
Wayne Roberts 21:1ac5ffad2726 85 pc.printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
dudmuck 12:9a8c13c4298b 86 if (diff > 10) {
dudmuck 12:9a8c13c4298b 87 if (++cnt > 3) {
dudmuck 12:9a8c13c4298b 88 /* find better channel */
dudmuck 12:9a8c13c4298b 89 channel_scan();
Wayne Roberts 21:1ac5ffad2726 90 Radio::Rx(0);
dudmuck 12:9a8c13c4298b 91 cnt = 0;
dudmuck 12:9a8c13c4298b 92 }
dudmuck 12:9a8c13c4298b 93 } else
dudmuck 12:9a8c13c4298b 94 cnt = 0;
dudmuck 0:2ff18de8d48b 95 }
dudmuck 0:2ff18de8d48b 96
dudmuck 0:2ff18de8d48b 97 void init_radio()
dudmuck 0:2ff18de8d48b 98 {
Wayne Roberts 21:1ac5ffad2726 99 Radio::Standby( );
dudmuck 0:2ff18de8d48b 100
Wayne Roberts 21:1ac5ffad2726 101 #ifdef SX126x_H
Wayne Roberts 21:1ac5ffad2726 102 if (Radio::chipType == CHIP_TYPE_SX1262)
Wayne Roberts 21:1ac5ffad2726 103 Radio::set_tx_dbm(22);
Wayne Roberts 21:1ac5ffad2726 104 else
Wayne Roberts 21:1ac5ffad2726 105 Radio::set_tx_dbm(17);
Wayne Roberts 21:1ac5ffad2726 106 #elif defined(SX127x_H)
Wayne Roberts 21:1ac5ffad2726 107 Radio::set_tx_dbm(17);
Wayne Roberts 21:1ac5ffad2726 108 #elif defined(SX128x_H)
Wayne Roberts 21:1ac5ffad2726 109 Radio::set_tx_dbm(5);
Wayne Roberts 21:1ac5ffad2726 110 #endif
Wayne Roberts 21:1ac5ffad2726 111
Wayne Roberts 21:1ac5ffad2726 112 Radio::LoRaModemConfig(BANDWIDTH_KHZ, LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE], 1);
Wayne Roberts 21:1ac5ffad2726 113 pc.printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
Wayne Roberts 21:1ac5ffad2726 114 Radio::SetPublicNetwork(true);
dudmuck 0:2ff18de8d48b 115
dudmuck 0:2ff18de8d48b 116 channel_scan();
dudmuck 0:2ff18de8d48b 117
Wayne Roberts 21:1ac5ffad2726 118 Radio::SetRxMaxPayloadLength(255);
dudmuck 0:2ff18de8d48b 119 }
dudmuck 0:2ff18de8d48b 120
Wayne Roberts 21:1ac5ffad2726 121 #if defined SX127x_H
dudmuck 0:2ff18de8d48b 122 void printLoraIrqs(bool clear)
dudmuck 0:2ff18de8d48b 123 {
Wayne Roberts 21:1ac5ffad2726 124 pc.printf("\r\nIrqFlags:");
Wayne Roberts 21:1ac5ffad2726 125 if (Radio::lora.RegIrqFlags.bits.CadDetected)
Wayne Roberts 21:1ac5ffad2726 126 pc.printf("CadDetected ");
Wayne Roberts 21:1ac5ffad2726 127 if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) {
Wayne Roberts 21:1ac5ffad2726 128 pc.printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
dudmuck 0:2ff18de8d48b 129 }
Wayne Roberts 21:1ac5ffad2726 130 if (Radio::lora.RegIrqFlags.bits.CadDone)
Wayne Roberts 21:1ac5ffad2726 131 pc.printf("CadDone ");
Wayne Roberts 21:1ac5ffad2726 132 if (Radio::lora.RegIrqFlags.bits.TxDone)
Wayne Roberts 21:1ac5ffad2726 133 pc.printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
Wayne Roberts 21:1ac5ffad2726 134 if (Radio::lora.RegIrqFlags.bits.ValidHeader)
Wayne Roberts 21:1ac5ffad2726 135 pc.printf("ValidHeader ");
Wayne Roberts 21:1ac5ffad2726 136 if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
Wayne Roberts 21:1ac5ffad2726 137 pc.printf("PayloadCrcError ");
Wayne Roberts 21:1ac5ffad2726 138 if (Radio::lora.RegIrqFlags.bits.RxDone)
Wayne Roberts 21:1ac5ffad2726 139 pc.printf("RxDone ");
Wayne Roberts 21:1ac5ffad2726 140 if (Radio::lora.RegIrqFlags.bits.RxTimeout)
Wayne Roberts 21:1ac5ffad2726 141 pc.printf("RxTimeout ");
dudmuck 0:2ff18de8d48b 142
Wayne Roberts 21:1ac5ffad2726 143 pc.printf("\r\n");
dudmuck 0:2ff18de8d48b 144
dudmuck 0:2ff18de8d48b 145 if (clear)
Wayne Roberts 21:1ac5ffad2726 146 Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet);
dudmuck 0:2ff18de8d48b 147 }
dudmuck 0:2ff18de8d48b 148
dudmuck 0:2ff18de8d48b 149 void printOpMode()
dudmuck 0:2ff18de8d48b 150 {
Wayne Roberts 21:1ac5ffad2726 151 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 21:1ac5ffad2726 152 switch (Radio::radio.RegOpMode.bits.Mode) {
Wayne Roberts 21:1ac5ffad2726 153 case RF_OPMODE_SLEEP: pc.printf("sleep"); break;
Wayne Roberts 21:1ac5ffad2726 154 case RF_OPMODE_STANDBY: pc.printf("stby"); break;
Wayne Roberts 21:1ac5ffad2726 155 case RF_OPMODE_SYNTHESIZER_TX: pc.printf("fstx"); break;
Wayne Roberts 21:1ac5ffad2726 156 case RF_OPMODE_TRANSMITTER: pc.printf("tx"); break;
Wayne Roberts 21:1ac5ffad2726 157 case RF_OPMODE_SYNTHESIZER_RX: pc.printf("fsrx"); break;
Wayne Roberts 21:1ac5ffad2726 158 case RF_OPMODE_RECEIVER: pc.printf("rx"); break;
dudmuck 0:2ff18de8d48b 159 case 6:
Wayne Roberts 21:1ac5ffad2726 160 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 21:1ac5ffad2726 161 pc.printf("rxs");
dudmuck 0:2ff18de8d48b 162 else
Wayne Roberts 21:1ac5ffad2726 163 pc.printf("-6-");
dudmuck 0:2ff18de8d48b 164 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 165 case 7:
Wayne Roberts 21:1ac5ffad2726 166 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 21:1ac5ffad2726 167 pc.printf("cad");
dudmuck 0:2ff18de8d48b 168 else
Wayne Roberts 21:1ac5ffad2726 169 pc.printf("-7-");
dudmuck 0:2ff18de8d48b 170 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 171 }
dudmuck 0:2ff18de8d48b 172 }
Wayne Roberts 21:1ac5ffad2726 173 #endif /* SX127x_H */
dudmuck 0:2ff18de8d48b 174
dudmuck 16:67fa19bc6331 175 void decrypted_uplink(uint32_t dev_addr, uint8_t* buf, uint8_t buflen, uint8_t port)
dudmuck 9:a0ce66c18ec0 176 {
dudmuck 9:a0ce66c18ec0 177 if (port == SENSOR_PORT) {
dudmuck 17:763412df6872 178 uint8_t i = 0;
dudmuck 17:763412df6872 179 uint16_t lum = buf[i++] << 8;
dudmuck 17:763412df6872 180 lum += buf[i++];
dudmuck 19:c20591c95746 181 LoRaWan::filtered_printf(dev_addr, MAC, "SENSOR lum:%u", lum);
dudmuck 19:c20591c95746 182
dudmuck 17:763412df6872 183 while (i < buflen) {
dudmuck 18:806cf9b7a904 184 uint16_t seq, a_a, a_b, p;
dudmuck 18:806cf9b7a904 185 seq = buf[i++] << 8;
dudmuck 18:806cf9b7a904 186 seq += buf[i++];
dudmuck 17:763412df6872 187 a_a = buf[i++] << 8;
dudmuck 17:763412df6872 188 a_a += buf[i++];
dudmuck 17:763412df6872 189 a_b = buf[i++] << 8;
dudmuck 17:763412df6872 190 a_b += buf[i++];
dudmuck 17:763412df6872 191 p = buf[i++];
dudmuck 19:c20591c95746 192 if (!LoRaWan::flags.show_mac)
dudmuck 19:c20591c95746 193 LoRaWan::filtered_printf(dev_addr, APP, "%x", dev_addr);
dudmuck 19:c20591c95746 194
dudmuck 19:c20591c95746 195 LoRaWan::filtered_printf(dev_addr, APP, ", %u, %u, %u, %u, %u",
dudmuck 18:806cf9b7a904 196 seq,
dudmuck 17:763412df6872 197 a_a, /* analog */
dudmuck 17:763412df6872 198 a_b, /* analog */
dudmuck 17:763412df6872 199 (p & 2) >> 1, /* digital in */
dudmuck 17:763412df6872 200 p & 1 /* digital out */
dudmuck 17:763412df6872 201 );
dudmuck 19:c20591c95746 202
dudmuck 19:c20591c95746 203 if (!LoRaWan::flags.show_mac && i < buflen)
dudmuck 19:c20591c95746 204 LoRaWan::filtered_printf(dev_addr, APP, "\r\n");
dudmuck 17:763412df6872 205 }
dudmuck 9:a0ce66c18ec0 206 } else {
dudmuck 9:a0ce66c18ec0 207 int i;
dudmuck 19:c20591c95746 208 LoRaWan::filtered_printf(dev_addr, APP, "port%u: ", port);
dudmuck 9:a0ce66c18ec0 209 for (i = 0; i < buflen; i++)
dudmuck 19:c20591c95746 210 LoRaWan::filtered_printf(dev_addr, APP, "%02x ", buf[i]);
dudmuck 9:a0ce66c18ec0 211 }
dudmuck 9:a0ce66c18ec0 212 }
dudmuck 9:a0ce66c18ec0 213
dudmuck 0:2ff18de8d48b 214 EventQueue queue;
dudmuck 3:7c01b8978638 215
dudmuck 0:2ff18de8d48b 216
dudmuck 0:2ff18de8d48b 217 void send_downlink()
dudmuck 0:2ff18de8d48b 218 {
Wayne Roberts 22:dd3023aac3b1 219 if (!LoRaWan::flags.do_downlink) {
Wayne Roberts 22:dd3023aac3b1 220 pc.printf("\e[31mno downlink to send\e[0m\r\n");
Wayne Roberts 22:dd3023aac3b1 221 return;
Wayne Roberts 22:dd3023aac3b1 222 }
Wayne Roberts 22:dd3023aac3b1 223
Wayne Roberts 22:dd3023aac3b1 224 LoRaWan::flags.do_downlink = false;
Wayne Roberts 21:1ac5ffad2726 225
Wayne Roberts 22:dd3023aac3b1 226 if (LoRaWan::flags.beacon_guard) {
Wayne Roberts 22:dd3023aac3b1 227 pc.printf("\e[33mdownlink during beacon_guard\e[0m\r\n");
Wayne Roberts 22:dd3023aac3b1 228 return;
Wayne Roberts 22:dd3023aac3b1 229 }
Wayne Roberts 21:1ac5ffad2726 230
Wayne Roberts 22:dd3023aac3b1 231 Radio::Standby( );
Wayne Roberts 22:dd3023aac3b1 232
Wayne Roberts 22:dd3023aac3b1 233 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 22:dd3023aac3b1 234 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, false, true);
Wayne Roberts 22:dd3023aac3b1 235
Wayne Roberts 22:dd3023aac3b1 236 Radio::Send(LoRaWan::_tmp_payload_length, 0, 0, 0);
dudmuck 0:2ff18de8d48b 237 }
dudmuck 0:2ff18de8d48b 238
Wayne Roberts 21:1ac5ffad2726 239 uint16_t tim_get_current_slot()
Wayne Roberts 21:1ac5ffad2726 240 {
Wayne Roberts 22:dd3023aac3b1 241 us_timestamp_t us_until = beaconAt - send_beaconTimer.read_us();
Wayne Roberts 21:1ac5ffad2726 242 return us_until / 30000;
Wayne Roberts 21:1ac5ffad2726 243 }
Wayne Roberts 21:1ac5ffad2726 244
Wayne Roberts 21:1ac5ffad2726 245 static void OnRadioRxDone(uint8_t size, float rssi, float snr)
Wayne Roberts 21:1ac5ffad2726 246 {
Wayne Roberts 21:1ac5ffad2726 247 LoRaWan::rx_slot = tim_get_current_slot();
Wayne Roberts 21:1ac5ffad2726 248 LoRaWan::rx_ms = timer.read_ms();
Wayne Roberts 21:1ac5ffad2726 249
Wayne Roberts 21:1ac5ffad2726 250 LoRaWan::parse_receive(size, rssi, snr);
Wayne Roberts 21:1ac5ffad2726 251
Wayne Roberts 21:1ac5ffad2726 252 if (!LoRaWan::flags.do_downlink) {
Wayne Roberts 21:1ac5ffad2726 253 /* if not sending downlink, start receiver now */
Wayne Roberts 21:1ac5ffad2726 254 Radio::Rx(0);
Wayne Roberts 21:1ac5ffad2726 255 }
Wayne Roberts 21:1ac5ffad2726 256 }
Wayne Roberts 21:1ac5ffad2726 257
dudmuck 12:9a8c13c4298b 258
dudmuck 0:2ff18de8d48b 259 volatile float prev_beacon_send_at;
dudmuck 0:2ff18de8d48b 260 volatile float beacon_send_at;
dudmuck 0:2ff18de8d48b 261
Wayne Roberts 21:1ac5ffad2726 262 volatile us_timestamp_t sbAt;
dudmuck 0:2ff18de8d48b 263 void
dudmuck 0:2ff18de8d48b 264 send_beacon()
dudmuck 0:2ff18de8d48b 265 {
dudmuck 0:2ff18de8d48b 266 prev_beacon_send_at = beacon_send_at;
dudmuck 0:2ff18de8d48b 267 beacon_send_at = timer.read();
Wayne Roberts 21:1ac5ffad2726 268 sbAt = send_beaconTimer.read_us();
dudmuck 0:2ff18de8d48b 269
dudmuck 18:806cf9b7a904 270 if (!LoRaWan::flags.beacon_loaded)
dudmuck 0:2ff18de8d48b 271 return;
dudmuck 0:2ff18de8d48b 272
Wayne Roberts 22:dd3023aac3b1 273 LoRaWan::flags.beacon_loaded = false;
Wayne Roberts 21:1ac5ffad2726 274 Radio::Send(LoRaWan::_tmp_payload_length, 0, 0, 0);
dudmuck 0:2ff18de8d48b 275 }
dudmuck 0:2ff18de8d48b 276
dudmuck 0:2ff18de8d48b 277 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:2ff18de8d48b 278 {
dudmuck 0:2ff18de8d48b 279 // The CRC calculation follows CCITT
dudmuck 0:2ff18de8d48b 280 const uint16_t polynom = 0x1021;
dudmuck 0:2ff18de8d48b 281 // CRC initial value
dudmuck 0:2ff18de8d48b 282 uint16_t crc = 0x0000;
dudmuck 0:2ff18de8d48b 283
dudmuck 0:2ff18de8d48b 284 if( buffer == NULL )
dudmuck 0:2ff18de8d48b 285 {
dudmuck 0:2ff18de8d48b 286 return 0;
dudmuck 0:2ff18de8d48b 287 }
dudmuck 0:2ff18de8d48b 288
dudmuck 0:2ff18de8d48b 289 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:2ff18de8d48b 290 {
dudmuck 0:2ff18de8d48b 291 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:2ff18de8d48b 292 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:2ff18de8d48b 293 {
dudmuck 0:2ff18de8d48b 294 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:2ff18de8d48b 295 }
dudmuck 0:2ff18de8d48b 296 }
dudmuck 0:2ff18de8d48b 297
dudmuck 0:2ff18de8d48b 298 return crc;
dudmuck 0:2ff18de8d48b 299 }
dudmuck 0:2ff18de8d48b 300
dudmuck 0:2ff18de8d48b 301 void
dudmuck 3:7c01b8978638 302 _load_beacon()
dudmuck 0:2ff18de8d48b 303 {
Wayne Roberts 21:1ac5ffad2726 304 bool inv_iq = false;
dudmuck 0:2ff18de8d48b 305 uint16_t crc;
Wayne Roberts 21:1ac5ffad2726 306 Radio::Standby( );
dudmuck 0:2ff18de8d48b 307
dudmuck 0:2ff18de8d48b 308 if (skip_beacon_cnt > 0) {
Wayne Roberts 21:1ac5ffad2726 309 inv_iq = true;
dudmuck 0:2ff18de8d48b 310 skip_beacon_cnt--;
dudmuck 0:2ff18de8d48b 311 }
Wayne Roberts 21:1ac5ffad2726 312 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 313 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, inv_iq);
dudmuck 0:2ff18de8d48b 314
Wayne Roberts 22:dd3023aac3b1 315 LoRaWan::_tmp_payload_length = BEACON_SIZE;
Wayne Roberts 22:dd3023aac3b1 316 Radio::SetFixedPayloadLength(LoRaWan::_tmp_payload_length);
Wayne Roberts 22:dd3023aac3b1 317
Wayne Roberts 21:1ac5ffad2726 318 Radio::radio.tx_buf[0] = beacon_payload[0];
Wayne Roberts 21:1ac5ffad2726 319 Radio::radio.tx_buf[1] = beacon_payload[1];
Wayne Roberts 21:1ac5ffad2726 320 Radio::radio.tx_buf[2] = beacon_payload[2];
Wayne Roberts 21:1ac5ffad2726 321 Radio::radio.tx_buf[3] = beacon_payload[3];
dudmuck 9:a0ce66c18ec0 322 beacon_payload[0] = CMD_NONE;
dudmuck 9:a0ce66c18ec0 323
Wayne Roberts 21:1ac5ffad2726 324 crc = beacon_crc(Radio::radio.tx_buf, 4);
Wayne Roberts 21:1ac5ffad2726 325 Radio::radio.tx_buf[4] = crc & 0xff;
Wayne Roberts 21:1ac5ffad2726 326 Radio::radio.tx_buf[5] = crc >> 8;
dudmuck 0:2ff18de8d48b 327
dudmuck 18:806cf9b7a904 328 LoRaWan::flags.beacon_loaded = true;
dudmuck 0:2ff18de8d48b 329 }
dudmuck 0:2ff18de8d48b 330
dudmuck 3:7c01b8978638 331 void load_beacon()
dudmuck 3:7c01b8978638 332 {
dudmuck 18:806cf9b7a904 333 LoRaWan::flags.beacon_guard = true;
dudmuck 12:9a8c13c4298b 334 queue.call_in(200, _load_beacon);
dudmuck 3:7c01b8978638 335 }
dudmuck 3:7c01b8978638 336
dudmuck 0:2ff18de8d48b 337 void get_time_till_beacon()
dudmuck 0:2ff18de8d48b 338 {
dudmuck 0:2ff18de8d48b 339 uint16_t slots = tim_get_current_slot();
Wayne Roberts 21:1ac5ffad2726 340 pc.printf("slots:%u\r\n", slots);
dudmuck 0:2ff18de8d48b 341 }
dudmuck 0:2ff18de8d48b 342
dudmuck 4:7e743e402681 343 void rx_isr()
dudmuck 0:2ff18de8d48b 344 {
dudmuck 0:2ff18de8d48b 345 static uint8_t pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 346 static uint8_t prev_len = 0;;
dudmuck 0:2ff18de8d48b 347 char c = pc.getc();
dudmuck 0:2ff18de8d48b 348
dudmuck 0:2ff18de8d48b 349 if (c == 8) {
dudmuck 0:2ff18de8d48b 350 if (pcbuf_idx > 0) {
dudmuck 0:2ff18de8d48b 351 pc.putc(8);
dudmuck 0:2ff18de8d48b 352 pc.putc(' ');
dudmuck 0:2ff18de8d48b 353 pc.putc(8);
dudmuck 0:2ff18de8d48b 354 pcbuf_idx--;
dudmuck 0:2ff18de8d48b 355 }
dudmuck 0:2ff18de8d48b 356 } else if (c == 3) { // ctrl-C
dudmuck 0:2ff18de8d48b 357 pcbuf_len = -1;
dudmuck 0:2ff18de8d48b 358 } else if (c == '\r') {
dudmuck 0:2ff18de8d48b 359 if (pcbuf_idx == 0) {
dudmuck 0:2ff18de8d48b 360 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 361 } else {
dudmuck 0:2ff18de8d48b 362 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:2ff18de8d48b 363 prev_len = pcbuf_idx;
dudmuck 0:2ff18de8d48b 364 pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 365 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 366 }
dudmuck 0:2ff18de8d48b 367 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:2ff18de8d48b 368 pcbuf[pcbuf_idx++] = c;
dudmuck 0:2ff18de8d48b 369 pc.putc(c);
dudmuck 0:2ff18de8d48b 370 }
dudmuck 0:2ff18de8d48b 371 }
dudmuck 0:2ff18de8d48b 372
dudmuck 0:2ff18de8d48b 373 void cmd_skip_beacon(uint8_t idx)
dudmuck 0:2ff18de8d48b 374 {
dudmuck 0:2ff18de8d48b 375 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:2ff18de8d48b 376 sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 377 }
Wayne Roberts 21:1ac5ffad2726 378 pc.printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 379 }
dudmuck 0:2ff18de8d48b 380
dudmuck 0:2ff18de8d48b 381 void cmd_list_motes(uint8_t idx)
dudmuck 0:2ff18de8d48b 382 {
dudmuck 0:2ff18de8d48b 383 int i;
dudmuck 0:2ff18de8d48b 384 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 385 if (motes[i].dev_addr != DEVADDR_NONE) {
dudmuck 13:fa2095be01c4 386 LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
Wayne Roberts 21:1ac5ffad2726 387 pc.printf(" %" PRIx32 "\r\n", motes[i].dev_addr);
dudmuck 0:2ff18de8d48b 388 }
dudmuck 0:2ff18de8d48b 389 }
dudmuck 0:2ff18de8d48b 390 }
dudmuck 0:2ff18de8d48b 391
dudmuck 0:2ff18de8d48b 392 void
dudmuck 0:2ff18de8d48b 393 cmd_beacon_payload(uint8_t idx)
dudmuck 0:2ff18de8d48b 394 {
dudmuck 9:a0ce66c18ec0 395 uint32_t i;
dudmuck 9:a0ce66c18ec0 396 uint32_t* ptr;
dudmuck 13:fa2095be01c4 397 sscanf(pcbuf+idx, "%" PRIx32, &i);
Wayne Roberts 21:1ac5ffad2726 398 pc.printf("beacon_payload:%08" PRIx32 "\r\n", i);
dudmuck 9:a0ce66c18ec0 399 ptr = (uint32_t*)beacon_payload;
dudmuck 9:a0ce66c18ec0 400 *ptr = i;
dudmuck 8:307f7faeb594 401 }
dudmuck 8:307f7faeb594 402
dudmuck 0:2ff18de8d48b 403 void
dudmuck 0:2ff18de8d48b 404 cmd_send_downlink(uint8_t idx)
dudmuck 0:2ff18de8d48b 405 {
dudmuck 0:2ff18de8d48b 406 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 407 int i;
dudmuck 0:2ff18de8d48b 408 unsigned int dev_addr;
dudmuck 0:2ff18de8d48b 409 sscanf(pcbuf+idx, "%x", &dev_addr);
dudmuck 0:2ff18de8d48b 410 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 411 if (motes[i].dev_addr == dev_addr) {
dudmuck 0:2ff18de8d48b 412 break;
dudmuck 0:2ff18de8d48b 413 }
dudmuck 0:2ff18de8d48b 414 }
dudmuck 0:2ff18de8d48b 415 if (i == N_MOTES) {
Wayne Roberts 21:1ac5ffad2726 416 pc.printf("mote %x not found\r\n", dev_addr);
dudmuck 0:2ff18de8d48b 417 return;
dudmuck 0:2ff18de8d48b 418 }
dudmuck 0:2ff18de8d48b 419 mote = &motes[i];
dudmuck 0:2ff18de8d48b 420
dudmuck 0:2ff18de8d48b 421 while (pcbuf[idx] != ' ') {
dudmuck 0:2ff18de8d48b 422 if (pcbuf[++idx] == 0) {
Wayne Roberts 21:1ac5ffad2726 423 pc.printf("hit end\r\n");
dudmuck 0:2ff18de8d48b 424 return;
dudmuck 0:2ff18de8d48b 425 }
dudmuck 0:2ff18de8d48b 426 }
dudmuck 0:2ff18de8d48b 427 idx++; // step past space
dudmuck 0:2ff18de8d48b 428
dudmuck 0:2ff18de8d48b 429 mote->user_downlink_length = 0;
dudmuck 0:2ff18de8d48b 430 while (pcbuf[idx] > ' ') {
dudmuck 0:2ff18de8d48b 431 int o;
dudmuck 0:2ff18de8d48b 432 sscanf(pcbuf+idx, "%02x", &o);
dudmuck 0:2ff18de8d48b 433 LoRaWan::user_downlink[mote->user_downlink_length++] = o;
dudmuck 0:2ff18de8d48b 434 idx += 2;
dudmuck 0:2ff18de8d48b 435 }
dudmuck 0:2ff18de8d48b 436
Wayne Roberts 21:1ac5ffad2726 437 pc.printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
dudmuck 0:2ff18de8d48b 438 }
dudmuck 0:2ff18de8d48b 439
Wayne Roberts 21:1ac5ffad2726 440 #if 0
dudmuck 9:a0ce66c18ec0 441 void cmd_rx_restart(uint8_t idx)
dudmuck 9:a0ce66c18ec0 442 {
dudmuck 9:a0ce66c18ec0 443 /*radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 21:1ac5ffad2726 444 pc.printf("standby\r\n");*/
dudmuck 9:a0ce66c18ec0 445 radio.set_opmode(RF_OPMODE_SLEEP);
Wayne Roberts 21:1ac5ffad2726 446 pc.printf("sleep\r\n");
dudmuck 9:a0ce66c18ec0 447 wait(0.05);
dudmuck 9:a0ce66c18ec0 448 radio.set_opmode(RF_OPMODE_RECEIVER);
Wayne Roberts 21:1ac5ffad2726 449 pc.printf("receive\r\n");
dudmuck 9:a0ce66c18ec0 450 }
Wayne Roberts 21:1ac5ffad2726 451 #endif /* if 0 */
dudmuck 9:a0ce66c18ec0 452
dudmuck 9:a0ce66c18ec0 453 void cmd_beacon_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 454 {
dudmuck 9:a0ce66c18ec0 455 int gpo;
dudmuck 9:a0ce66c18ec0 456 sscanf(pcbuf+idx, "%d", &gpo);
dudmuck 9:a0ce66c18ec0 457 beacon_payload[0] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 458 beacon_payload[1] = gpo;
Wayne Roberts 21:1ac5ffad2726 459 pc.printf("beacon gpo: %d\r\n", gpo);
dudmuck 9:a0ce66c18ec0 460 }
dudmuck 9:a0ce66c18ec0 461
dudmuck 9:a0ce66c18ec0 462 void cmd_beacon_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 463 {
dudmuck 9:a0ce66c18ec0 464 int r, g ,b;
dudmuck 9:a0ce66c18ec0 465 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 9:a0ce66c18ec0 466 beacon_payload[0] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 467 beacon_payload[1] = r;
dudmuck 9:a0ce66c18ec0 468 beacon_payload[2] = g;
dudmuck 9:a0ce66c18ec0 469 beacon_payload[3] = b;
Wayne Roberts 21:1ac5ffad2726 470 pc.printf("beacon rgb: %d %d %d\r\n", r, g, b);
dudmuck 9:a0ce66c18ec0 471 }
dudmuck 9:a0ce66c18ec0 472
dudmuck 9:a0ce66c18ec0 473 void cmd_downlink_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 474 {
dudmuck 9:a0ce66c18ec0 475 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 476 int i, r, g ,b;
dudmuck 9:a0ce66c18ec0 477 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 478 sscanf(pcbuf+idx, "%x %d %d %d", &dev_addr, &r, &g, &b);
dudmuck 9:a0ce66c18ec0 479 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 480 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 481 break;
dudmuck 9:a0ce66c18ec0 482 }
dudmuck 9:a0ce66c18ec0 483 }
dudmuck 9:a0ce66c18ec0 484 if (i == N_MOTES) {
Wayne Roberts 21:1ac5ffad2726 485 pc.printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 486 return;
dudmuck 9:a0ce66c18ec0 487 }
dudmuck 9:a0ce66c18ec0 488 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 489
dudmuck 9:a0ce66c18ec0 490 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 491 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 492 LoRaWan::user_downlink[mote->user_downlink_length++] = r;
dudmuck 9:a0ce66c18ec0 493 LoRaWan::user_downlink[mote->user_downlink_length++] = g;
dudmuck 9:a0ce66c18ec0 494 LoRaWan::user_downlink[mote->user_downlink_length++] = b;
dudmuck 9:a0ce66c18ec0 495
Wayne Roberts 21:1ac5ffad2726 496 pc.printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 497 }
dudmuck 9:a0ce66c18ec0 498
dudmuck 9:a0ce66c18ec0 499 void cmd_downlink_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 500 {
dudmuck 9:a0ce66c18ec0 501 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 502 int i, gpo;
dudmuck 9:a0ce66c18ec0 503 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 504 sscanf(pcbuf+idx, "%x %d", &dev_addr, &gpo);
dudmuck 9:a0ce66c18ec0 505 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 506 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 507 break;
dudmuck 9:a0ce66c18ec0 508 }
dudmuck 9:a0ce66c18ec0 509 }
dudmuck 9:a0ce66c18ec0 510 if (i == N_MOTES) {
Wayne Roberts 21:1ac5ffad2726 511 pc.printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 512 return;
dudmuck 9:a0ce66c18ec0 513 }
dudmuck 9:a0ce66c18ec0 514 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 515
dudmuck 9:a0ce66c18ec0 516 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 517 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 518 LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
dudmuck 9:a0ce66c18ec0 519
Wayne Roberts 21:1ac5ffad2726 520 pc.printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 521 }
dudmuck 9:a0ce66c18ec0 522
dudmuck 0:2ff18de8d48b 523 void cmd_status(uint8_t idx)
dudmuck 0:2ff18de8d48b 524 {
Wayne Roberts 22:dd3023aac3b1 525 pc.printf(" %uHz do_downlink:%u, ", usingChHz, LoRaWan::flags.do_downlink);
Wayne Roberts 21:1ac5ffad2726 526 pc.printf("rssi:%f\r\n", Radio::GetRssiInst());
Wayne Roberts 21:1ac5ffad2726 527 pc.printf("\r\nskip_beacon_cnt:%u, curSlot:%u\r\n", skip_beacon_cnt, tim_get_current_slot());
Wayne Roberts 21:1ac5ffad2726 528 #ifdef SX128x_H
Wayne Roberts 21:1ac5ffad2726 529 status_t status;
Wayne Roberts 21:1ac5ffad2726 530 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 21:1ac5ffad2726 531 switch (status.bits.cmdStatus) {
Wayne Roberts 21:1ac5ffad2726 532 case 1: pc.printf("success"); break;
Wayne Roberts 21:1ac5ffad2726 533 case 2: pc.printf("dataAvail"); break;
Wayne Roberts 21:1ac5ffad2726 534 case 3: pc.printf("cmdTimeout"); break;
Wayne Roberts 21:1ac5ffad2726 535 case 4: pc.printf("cmdErr"); break;
Wayne Roberts 21:1ac5ffad2726 536 case 5: pc.printf("exeFail"); break;
Wayne Roberts 21:1ac5ffad2726 537 case 6: pc.printf("txdone"); break;
Wayne Roberts 21:1ac5ffad2726 538 default: pc.printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
Wayne Roberts 21:1ac5ffad2726 539 }
Wayne Roberts 21:1ac5ffad2726 540 pc.printf(" ");
Wayne Roberts 21:1ac5ffad2726 541 switch (status.bits.chipMode) {
Wayne Roberts 21:1ac5ffad2726 542 case 2: pc.printf("stdby_rc"); break;
Wayne Roberts 21:1ac5ffad2726 543 case 3: pc.printf("stdby_xosc"); break;
Wayne Roberts 21:1ac5ffad2726 544 case 4: pc.printf("fs"); break;
Wayne Roberts 21:1ac5ffad2726 545 case 5: pc.printf("\e[32mrx\e[0m"); break;
Wayne Roberts 21:1ac5ffad2726 546 case 6: pc.printf("\e[31mtx\e[0m"); break;
Wayne Roberts 21:1ac5ffad2726 547 default: pc.printf("chipMode:<%u>", status.bits.chipMode); break;
Wayne Roberts 21:1ac5ffad2726 548 }
Wayne Roberts 21:1ac5ffad2726 549 LoRaPktPar0_t LoRaPktPar0;
Wayne Roberts 21:1ac5ffad2726 550 LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
Wayne Roberts 21:1ac5ffad2726 551 pc.printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
Wayne Roberts 21:1ac5ffad2726 552 pc.printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 21:1ac5ffad2726 553 #elif defined SX126x_H
Wayne Roberts 21:1ac5ffad2726 554 status_t status;
Wayne Roberts 21:1ac5ffad2726 555 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 21:1ac5ffad2726 556 switch (status.bits.chipMode) {
Wayne Roberts 21:1ac5ffad2726 557 case 2: pc.printf("STBY_RC"); break;
Wayne Roberts 21:1ac5ffad2726 558 case 3: pc.printf("STBY_XOSC"); break;
Wayne Roberts 21:1ac5ffad2726 559 case 4: pc.printf("FS"); break;
Wayne Roberts 22:dd3023aac3b1 560 case 5: pc.printf("\e[32mRX\e[0m"); break;
Wayne Roberts 22:dd3023aac3b1 561 case 6: pc.printf("\e[31mTX\e[0m"); break;
Wayne Roberts 21:1ac5ffad2726 562 default: pc.printf("%u", status.bits.chipMode); break;
Wayne Roberts 21:1ac5ffad2726 563 }
Wayne Roberts 21:1ac5ffad2726 564 pc.printf(" ");
Wayne Roberts 21:1ac5ffad2726 565 switch (status.bits.cmdStatus) {
Wayne Roberts 21:1ac5ffad2726 566 case 1: pc.printf("rfu"); break;
Wayne Roberts 21:1ac5ffad2726 567 case 2: pc.printf("dataAvail"); break;
Wayne Roberts 21:1ac5ffad2726 568 case 3: pc.printf("timeout"); break;
Wayne Roberts 21:1ac5ffad2726 569 case 4: pc.printf("err"); break;
Wayne Roberts 21:1ac5ffad2726 570 case 5: pc.printf("fail"); break;
Wayne Roberts 21:1ac5ffad2726 571 case 6: pc.printf("txdone"); break;
Wayne Roberts 21:1ac5ffad2726 572 default: pc.printf("%u", status.bits.cmdStatus); break;
Wayne Roberts 21:1ac5ffad2726 573 }
Wayne Roberts 21:1ac5ffad2726 574 loraConfig0_t conf0;
Wayne Roberts 21:1ac5ffad2726 575 conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
Wayne Roberts 21:1ac5ffad2726 576 // bw7=125 bw8=250 b9=500
Wayne Roberts 21:1ac5ffad2726 577 pc.printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
Wayne Roberts 21:1ac5ffad2726 578 loraConfig1_t conf1;
Wayne Roberts 21:1ac5ffad2726 579 conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
Wayne Roberts 21:1ac5ffad2726 580 pc.printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
Wayne Roberts 21:1ac5ffad2726 581 pc.printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 21:1ac5ffad2726 582 #elif defined SX127x_H
Wayne Roberts 21:1ac5ffad2726 583 Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG);
Wayne Roberts 21:1ac5ffad2726 584 if (Radio::radio.RegPaConfig.bits.PaSelect)
Wayne Roberts 21:1ac5ffad2726 585 pc.printf("PA_BOOST ");
dudmuck 14:c6284654d1b0 586 else
Wayne Roberts 21:1ac5ffad2726 587 pc.printf("RFO ");
dudmuck 14:c6284654d1b0 588
Wayne Roberts 21:1ac5ffad2726 589 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 21:1ac5ffad2726 590 pc.printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
Wayne Roberts 21:1ac5ffad2726 591 pc.printf("dio0pin:%u ", Radio::radio.dio0.read());
dudmuck 0:2ff18de8d48b 592 printOpMode();
Wayne Roberts 21:1ac5ffad2726 593 if (!Radio::radio.RegOpMode.bits.LongRangeMode) {
Wayne Roberts 21:1ac5ffad2726 594 pc.printf("FSK\r\n");
dudmuck 0:2ff18de8d48b 595 return;
dudmuck 0:2ff18de8d48b 596 }
dudmuck 0:2ff18de8d48b 597
Wayne Roberts 21:1ac5ffad2726 598 Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS);
dudmuck 0:2ff18de8d48b 599 printLoraIrqs(false);
dudmuck 0:2ff18de8d48b 600
Wayne Roberts 21:1ac5ffad2726 601 Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33); // invert_i_q
Wayne Roberts 21:1ac5ffad2726 602 Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT);
Wayne Roberts 21:1ac5ffad2726 603 pc.printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
Wayne Roberts 21:1ac5ffad2726 604 Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1);
Wayne Roberts 21:1ac5ffad2726 605 pc.printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), Radio::radio.RegDioMapping1.bits.Dio0Mapping);
Wayne Roberts 21:1ac5ffad2726 606 pc.printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
Wayne Roberts 21:1ac5ffad2726 607 #endif
dudmuck 0:2ff18de8d48b 608 }
dudmuck 0:2ff18de8d48b 609
dudmuck 16:67fa19bc6331 610 void cmd_filter(uint8_t idx)
dudmuck 16:67fa19bc6331 611 {
dudmuck 16:67fa19bc6331 612 if (sscanf(pcbuf+idx, "%lx", &LoRaWan::dev_addr_filter) != 1) {
dudmuck 16:67fa19bc6331 613 LoRaWan::dev_addr_filter = 0;
Wayne Roberts 21:1ac5ffad2726 614 pc.printf("filter off\r\n");
dudmuck 16:67fa19bc6331 615 } else
Wayne Roberts 21:1ac5ffad2726 616 pc.printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
dudmuck 16:67fa19bc6331 617 }
dudmuck 16:67fa19bc6331 618
dudmuck 11:50d0558a4e37 619 void cmd_op(uint8_t idx)
dudmuck 11:50d0558a4e37 620 {
Wayne Roberts 21:1ac5ffad2726 621 int dbm;
Wayne Roberts 21:1ac5ffad2726 622 if (sscanf(pcbuf+idx, "%d", &dbm) == 1) {
Wayne Roberts 21:1ac5ffad2726 623 Radio::set_tx_dbm(dbm);
Wayne Roberts 21:1ac5ffad2726 624 pc.printf("OutputPower:%ddBm\r\n", dbm);
dudmuck 11:50d0558a4e37 625 }
dudmuck 11:50d0558a4e37 626 }
dudmuck 11:50d0558a4e37 627
dudmuck 14:c6284654d1b0 628 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 629 void cmd_pa_select(uint8_t idx)
dudmuck 14:c6284654d1b0 630 {
dudmuck 14:c6284654d1b0 631 radio.RegPaConfig.bits.PaSelect ^= 1;
dudmuck 14:c6284654d1b0 632 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 14:c6284654d1b0 633 if (radio.RegPaConfig.bits.PaSelect)
Wayne Roberts 21:1ac5ffad2726 634 pc.printf("PA_BOOST\r\n");
dudmuck 14:c6284654d1b0 635 else
Wayne Roberts 21:1ac5ffad2726 636 pc.printf("RFO\r\n");
dudmuck 14:c6284654d1b0 637 }
dudmuck 14:c6284654d1b0 638 #endif /* TYPE_ABZ */
dudmuck 14:c6284654d1b0 639
dudmuck 12:9a8c13c4298b 640 void cmd_set_time(uint8_t idx)
dudmuck 12:9a8c13c4298b 641 {
dudmuck 12:9a8c13c4298b 642 set_time(0);
Wayne Roberts 21:1ac5ffad2726 643 pc.printf("time:%" PRIu32 "\r\n", time(NULL));
dudmuck 12:9a8c13c4298b 644 }
dudmuck 12:9a8c13c4298b 645
dudmuck 13:fa2095be01c4 646
dudmuck 13:fa2095be01c4 647 void cmd_pwm(uint8_t idx)
dudmuck 12:9a8c13c4298b 648 {
dudmuck 13:fa2095be01c4 649 ota_mote_t* mote;
dudmuck 12:9a8c13c4298b 650 int i;
dudmuck 13:fa2095be01c4 651 unsigned dev_addr, p, d;
dudmuck 13:fa2095be01c4 652
dudmuck 13:fa2095be01c4 653 if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
Wayne Roberts 21:1ac5ffad2726 654 pc.printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 655 return;
dudmuck 13:fa2095be01c4 656 }
dudmuck 12:9a8c13c4298b 657 for (i = 0; i < N_MOTES; i++) {
dudmuck 12:9a8c13c4298b 658 if (motes[i].dev_addr == dev_addr) {
dudmuck 12:9a8c13c4298b 659 break;
dudmuck 12:9a8c13c4298b 660 }
dudmuck 12:9a8c13c4298b 661 }
dudmuck 12:9a8c13c4298b 662 if (i == N_MOTES) {
Wayne Roberts 21:1ac5ffad2726 663 pc.printf("mote %x not found\r\n", dev_addr);
dudmuck 12:9a8c13c4298b 664 return;
dudmuck 12:9a8c13c4298b 665 }
dudmuck 12:9a8c13c4298b 666
dudmuck 12:9a8c13c4298b 667 mote = &motes[i];
dudmuck 12:9a8c13c4298b 668
dudmuck 12:9a8c13c4298b 669 mote->user_downlink_length = 0;
dudmuck 13:fa2095be01c4 670 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_PWM;
dudmuck 13:fa2095be01c4 671 LoRaWan::user_downlink[mote->user_downlink_length++] = p;
dudmuck 13:fa2095be01c4 672 LoRaWan::user_downlink[mote->user_downlink_length++] = d;
dudmuck 12:9a8c13c4298b 673
Wayne Roberts 21:1ac5ffad2726 674 pc.printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
dudmuck 13:fa2095be01c4 675 }
dudmuck 13:fa2095be01c4 676
dudmuck 13:fa2095be01c4 677 void cmd_beacon_pwm(uint8_t idx)
dudmuck 13:fa2095be01c4 678 {
dudmuck 13:fa2095be01c4 679 unsigned p, d;
dudmuck 13:fa2095be01c4 680 if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
Wayne Roberts 21:1ac5ffad2726 681 pc.printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 682 return;
dudmuck 13:fa2095be01c4 683 }
dudmuck 13:fa2095be01c4 684
dudmuck 13:fa2095be01c4 685 beacon_payload[0] = CMD_PWM;
dudmuck 13:fa2095be01c4 686 beacon_payload[1] = p;
dudmuck 13:fa2095be01c4 687 beacon_payload[2] = d;
dudmuck 13:fa2095be01c4 688
Wayne Roberts 21:1ac5ffad2726 689 pc.printf("period:%u duty:%u\r\n", p, d);
dudmuck 12:9a8c13c4298b 690 }
dudmuck 12:9a8c13c4298b 691
dudmuck 14:c6284654d1b0 692 void cmd_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 693 {
dudmuck 14:c6284654d1b0 694 ota_mote_t* mote;
dudmuck 14:c6284654d1b0 695 int i;
dudmuck 14:c6284654d1b0 696 unsigned dev_addr, txi;
dudmuck 14:c6284654d1b0 697
dudmuck 14:c6284654d1b0 698 if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
Wayne Roberts 21:1ac5ffad2726 699 pc.printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 700 return;
dudmuck 14:c6284654d1b0 701 }
dudmuck 14:c6284654d1b0 702 for (i = 0; i < N_MOTES; i++) {
dudmuck 14:c6284654d1b0 703 if (motes[i].dev_addr == dev_addr) {
dudmuck 14:c6284654d1b0 704 break;
dudmuck 14:c6284654d1b0 705 }
dudmuck 14:c6284654d1b0 706 }
dudmuck 14:c6284654d1b0 707 if (i == N_MOTES) {
Wayne Roberts 21:1ac5ffad2726 708 pc.printf("mote %x not found\r\n", dev_addr);
dudmuck 14:c6284654d1b0 709 return;
dudmuck 14:c6284654d1b0 710 }
dudmuck 14:c6284654d1b0 711
dudmuck 14:c6284654d1b0 712 mote = &motes[i];
dudmuck 14:c6284654d1b0 713
dudmuck 14:c6284654d1b0 714 mote->user_downlink_length = 0;
dudmuck 14:c6284654d1b0 715 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 716 LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
dudmuck 14:c6284654d1b0 717
Wayne Roberts 21:1ac5ffad2726 718 pc.printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
dudmuck 14:c6284654d1b0 719 }
dudmuck 14:c6284654d1b0 720
dudmuck 19:c20591c95746 721 void cmd_hide_mac(uint8_t idx)
dudmuck 18:806cf9b7a904 722 {
dudmuck 19:c20591c95746 723 LoRaWan::flags.show_mac = 0;
Wayne Roberts 21:1ac5ffad2726 724 pc.printf("!show_mac\r\n");
dudmuck 18:806cf9b7a904 725 }
dudmuck 18:806cf9b7a904 726
dudmuck 19:c20591c95746 727 void cmd_hide_payload(uint8_t idx)
dudmuck 18:806cf9b7a904 728 {
dudmuck 19:c20591c95746 729 LoRaWan::flags.show_app = 0;
Wayne Roberts 21:1ac5ffad2726 730 pc.printf("!show_app\r\n");
dudmuck 18:806cf9b7a904 731 }
dudmuck 18:806cf9b7a904 732
dudmuck 19:c20591c95746 733 void cmd_show_all(uint8_t idx)
dudmuck 18:806cf9b7a904 734 {
dudmuck 19:c20591c95746 735 LoRaWan::flags.show_mac = 1;
dudmuck 19:c20591c95746 736 LoRaWan::flags.show_app = 1;
Wayne Roberts 21:1ac5ffad2726 737 pc.printf("show-all\r\n");
dudmuck 18:806cf9b7a904 738 }
dudmuck 18:806cf9b7a904 739
dudmuck 14:c6284654d1b0 740 void cmd_beacon_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 741 {
dudmuck 14:c6284654d1b0 742 unsigned txi;
dudmuck 14:c6284654d1b0 743 if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
Wayne Roberts 21:1ac5ffad2726 744 pc.printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 745 return;
dudmuck 14:c6284654d1b0 746 }
dudmuck 14:c6284654d1b0 747
dudmuck 14:c6284654d1b0 748 beacon_payload[0] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 749 beacon_payload[1] = txi;
dudmuck 14:c6284654d1b0 750
Wayne Roberts 21:1ac5ffad2726 751 pc.printf("txp index:%u\r\n", txi);
dudmuck 14:c6284654d1b0 752 }
dudmuck 14:c6284654d1b0 753
dudmuck 0:2ff18de8d48b 754 void cmd_help(uint8_t);
dudmuck 0:2ff18de8d48b 755
dudmuck 0:2ff18de8d48b 756 typedef struct {
dudmuck 0:2ff18de8d48b 757 const char* const cmd;
dudmuck 0:2ff18de8d48b 758 void (*handler)(uint8_t args_at);
dudmuck 0:2ff18de8d48b 759 const char* const arg_descr;
dudmuck 0:2ff18de8d48b 760 const char* const description;
dudmuck 0:2ff18de8d48b 761 } menu_item_t;
dudmuck 0:2ff18de8d48b 762
dudmuck 0:2ff18de8d48b 763 const menu_item_t menu_items[] =
dudmuck 0:2ff18de8d48b 764 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:2ff18de8d48b 765 { "?", cmd_help, "","show available commands"},
dudmuck 0:2ff18de8d48b 766 { ".", cmd_status, "","read status"},
dudmuck 16:67fa19bc6331 767 { "f", cmd_filter, "%x","set dev_addr print filter"},
dudmuck 0:2ff18de8d48b 768 { "b", cmd_beacon_payload, "<%x>","set beacon payload"},
dudmuck 0:2ff18de8d48b 769 { "sb", cmd_skip_beacon, "<%d>","skip beacons"},
dudmuck 0:2ff18de8d48b 770 { "list", cmd_list_motes, "","list active motes"},
dudmuck 0:2ff18de8d48b 771 { "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
Wayne Roberts 21:1ac5ffad2726 772 //{ "rxr", cmd_rx_restart, "", "restart RX"},
dudmuck 9:a0ce66c18ec0 773 { "brgb", cmd_beacon_rgb, "%u %u %u", "load RGB command into next beacon" },
dudmuck 9:a0ce66c18ec0 774 { "rgb", cmd_downlink_rgb, "%x %u %u %u", "load RGB command to mote"},
dudmuck 9:a0ce66c18ec0 775 { "bgpo", cmd_beacon_gpo, "%d", "load output pin command into next beacon"},
dudmuck 9:a0ce66c18ec0 776 { "gpo", cmd_downlink_gpo, "%x %d", "load output pin command to mote"},
dudmuck 12:9a8c13c4298b 777 { "op", cmd_op, "<dBm>","(TX) get/set TX power"},
dudmuck 14:c6284654d1b0 778 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 779 { "pas", cmd_pa_select, "","(TX) toggle PaSelect"},
dudmuck 14:c6284654d1b0 780 #endif
dudmuck 13:fa2095be01c4 781 { "tz", cmd_set_time, "", "set seconds to zero"},
dudmuck 13:fa2095be01c4 782 { "p", cmd_pwm, "%x %u %u", "send pwm period, duty to dev_addr"},
dudmuck 13:fa2095be01c4 783 { "bp", cmd_beacon_pwm, "%u %u", "send pwm period, duty on beacon"},
dudmuck 14:c6284654d1b0 784 { "ntxp", cmd_endnode_txp, "%x %u", "send txpower index to dev_addr"},
dudmuck 14:c6284654d1b0 785 { "bntxp", cmd_beacon_endnode_txp, "%u", "send txpower index on beacon"},
dudmuck 19:c20591c95746 786 { "hm", cmd_hide_mac, "", "hide mac layer printing "},
dudmuck 19:c20591c95746 787 { "hp", cmd_hide_payload, "", "hide payload printing"},
dudmuck 19:c20591c95746 788 { "sa", cmd_show_all, "", "show both mac and app layers"},
dudmuck 0:2ff18de8d48b 789 { NULL, NULL, NULL, NULL }
dudmuck 0:2ff18de8d48b 790 };
dudmuck 0:2ff18de8d48b 791
dudmuck 0:2ff18de8d48b 792 void cmd_help(uint8_t args_at)
dudmuck 0:2ff18de8d48b 793 {
dudmuck 0:2ff18de8d48b 794 int i;
dudmuck 0:2ff18de8d48b 795
dudmuck 0:2ff18de8d48b 796 for (i = 0; menu_items[i].cmd != NULL ; i++) {
Wayne Roberts 21:1ac5ffad2726 797 pc.printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:2ff18de8d48b 798 }
dudmuck 0:2ff18de8d48b 799
dudmuck 0:2ff18de8d48b 800 }
dudmuck 0:2ff18de8d48b 801
dudmuck 0:2ff18de8d48b 802 void
dudmuck 0:2ff18de8d48b 803 console()
dudmuck 0:2ff18de8d48b 804 {
dudmuck 0:2ff18de8d48b 805 int i;
dudmuck 0:2ff18de8d48b 806 uint8_t user_cmd_len;
dudmuck 0:2ff18de8d48b 807
dudmuck 0:2ff18de8d48b 808 if (pcbuf_len < 0) { // ctrl-C
Wayne Roberts 21:1ac5ffad2726 809 //pc.printf("abort\r\n");
dudmuck 0:2ff18de8d48b 810 return;
dudmuck 0:2ff18de8d48b 811 }
dudmuck 0:2ff18de8d48b 812 if (pcbuf_len == 0)
dudmuck 0:2ff18de8d48b 813 return;
dudmuck 0:2ff18de8d48b 814
Wayne Roberts 21:1ac5ffad2726 815 pc.printf("\r\n");
dudmuck 0:2ff18de8d48b 816
dudmuck 0:2ff18de8d48b 817 /* get end of user-entered command */
dudmuck 0:2ff18de8d48b 818 user_cmd_len = 1; // first character can be any character
dudmuck 0:2ff18de8d48b 819 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:2ff18de8d48b 820 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:2ff18de8d48b 821 user_cmd_len = i;
dudmuck 0:2ff18de8d48b 822 break;
dudmuck 0:2ff18de8d48b 823 }
dudmuck 0:2ff18de8d48b 824 }
dudmuck 0:2ff18de8d48b 825
dudmuck 0:2ff18de8d48b 826 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 827 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:2ff18de8d48b 828
dudmuck 0:2ff18de8d48b 829 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:2ff18de8d48b 830 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:2ff18de8d48b 831 mi_len++;
dudmuck 0:2ff18de8d48b 832 menu_items[i].handler(mi_len);
dudmuck 0:2ff18de8d48b 833 break;
dudmuck 0:2ff18de8d48b 834 }
dudmuck 0:2ff18de8d48b 835 }
dudmuck 0:2ff18de8d48b 836
dudmuck 0:2ff18de8d48b 837 pcbuf_len = 0;
Wayne Roberts 21:1ac5ffad2726 838 pc.printf("> ");
dudmuck 0:2ff18de8d48b 839 fflush(stdout);
dudmuck 0:2ff18de8d48b 840 }
dudmuck 0:2ff18de8d48b 841
Wayne Roberts 21:1ac5ffad2726 842 static void OnRadioTxDone()
Wayne Roberts 21:1ac5ffad2726 843 {
Wayne Roberts 22:dd3023aac3b1 844 if (LoRaWan::flags.beacon_test) {
Wayne Roberts 22:dd3023aac3b1 845 LoRaWan::flags.beacon_test = 0;
Wayne Roberts 22:dd3023aac3b1 846 return;
Wayne Roberts 22:dd3023aac3b1 847 }
Wayne Roberts 22:dd3023aac3b1 848
Wayne Roberts 21:1ac5ffad2726 849 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 850 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 21:1ac5ffad2726 851
Wayne Roberts 21:1ac5ffad2726 852 Radio::Rx(0);
Wayne Roberts 21:1ac5ffad2726 853
Wayne Roberts 21:1ac5ffad2726 854 if (LoRaWan::flags.beacon_guard) { // beacon done transmitting
Wayne Roberts 21:1ac5ffad2726 855 measure_ambient();
Wayne Roberts 21:1ac5ffad2726 856 LoRaWan::flags.beacon_guard = false;
Wayne Roberts 21:1ac5ffad2726 857
Wayne Roberts 21:1ac5ffad2726 858 beaconAt += BEACON_INTERVAL_SECONDS_us;
Wayne Roberts 21:1ac5ffad2726 859 load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 21:1ac5ffad2726 860 send_beaconTimer.attach_us(send_beacon, beaconAt);
Wayne Roberts 21:1ac5ffad2726 861 }
Wayne Roberts 21:1ac5ffad2726 862 }
Wayne Roberts 21:1ac5ffad2726 863
Wayne Roberts 21:1ac5ffad2726 864 void tim_init()
Wayne Roberts 21:1ac5ffad2726 865 {
Wayne Roberts 21:1ac5ffad2726 866 beaconAt = send_beaconTimer.read_us() + BEACON_INTERVAL_SECONDS_us;
Wayne Roberts 21:1ac5ffad2726 867 load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 21:1ac5ffad2726 868 send_beaconTimer.attach_us(send_beacon, beaconAt);
Wayne Roberts 21:1ac5ffad2726 869 }
Wayne Roberts 21:1ac5ffad2726 870
Wayne Roberts 21:1ac5ffad2726 871
Wayne Roberts 21:1ac5ffad2726 872 const RadioEvents_t rev = {
Wayne Roberts 21:1ac5ffad2726 873 /* Dio0_top_half */ NULL,
Wayne Roberts 21:1ac5ffad2726 874 /* TxDone_topHalf */ NULL,
Wayne Roberts 21:1ac5ffad2726 875 /* TxDone_botHalf */ OnRadioTxDone,
Wayne Roberts 21:1ac5ffad2726 876 /* TxTimeout */ NULL,
Wayne Roberts 21:1ac5ffad2726 877 /* RxDone */ OnRadioRxDone,
Wayne Roberts 21:1ac5ffad2726 878 /* RxTimeout */ NULL,
Wayne Roberts 21:1ac5ffad2726 879 /* RxError */ NULL,
Wayne Roberts 21:1ac5ffad2726 880 /* FhssChangeChannel */NULL,
Wayne Roberts 21:1ac5ffad2726 881 /* CadDone */ NULL
Wayne Roberts 21:1ac5ffad2726 882 };
Wayne Roberts 21:1ac5ffad2726 883
dudmuck 0:2ff18de8d48b 884 int main()
dudmuck 0:2ff18de8d48b 885 {
dudmuck 0:2ff18de8d48b 886 Thread eventThread;
Wayne Roberts 21:1ac5ffad2726 887 pc.baud(115200);
Wayne Roberts 21:1ac5ffad2726 888 pc.printf("\r\nreset\r\n");
dudmuck 11:50d0558a4e37 889 set_time(0);
dudmuck 0:2ff18de8d48b 890
Wayne Roberts 21:1ac5ffad2726 891 Radio::Init(&rev);
dudmuck 0:2ff18de8d48b 892
dudmuck 0:2ff18de8d48b 893 init_radio();
dudmuck 0:2ff18de8d48b 894
Wayne Roberts 22:dd3023aac3b1 895 {
Wayne Roberts 22:dd3023aac3b1 896 us_timestamp_t txStartAt;
Wayne Roberts 22:dd3023aac3b1 897 _load_beacon();
Wayne Roberts 22:dd3023aac3b1 898 send_beacon();
Wayne Roberts 22:dd3023aac3b1 899 txStartAt = Radio::lpt.read_us();
Wayne Roberts 22:dd3023aac3b1 900 LoRaWan::flags.beacon_test = 1;
Wayne Roberts 22:dd3023aac3b1 901 while (LoRaWan::flags.beacon_test)
Wayne Roberts 22:dd3023aac3b1 902 Radio::service();
Wayne Roberts 22:dd3023aac3b1 903
Wayne Roberts 22:dd3023aac3b1 904 LoRaWan::beaconDur = Radio::irqAt - txStartAt;
Wayne Roberts 22:dd3023aac3b1 905 pc.printf("beaconDur:%u, 0x%x\r\n", LoRaWan::beaconDur, LoRaWan::beaconDur);
Wayne Roberts 22:dd3023aac3b1 906 }
Wayne Roberts 22:dd3023aac3b1 907
Wayne Roberts 21:1ac5ffad2726 908 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 909 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 21:1ac5ffad2726 910 Radio::Rx(0);
dudmuck 0:2ff18de8d48b 911
dudmuck 0:2ff18de8d48b 912 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
dudmuck 0:2ff18de8d48b 913 LoRaWan::init();
dudmuck 0:2ff18de8d48b 914
dudmuck 0:2ff18de8d48b 915 timer.start();
dudmuck 0:2ff18de8d48b 916 tim_init();
dudmuck 4:7e743e402681 917
dudmuck 4:7e743e402681 918 pc.attach(&rx_isr);
dudmuck 9:a0ce66c18ec0 919
dudmuck 19:c20591c95746 920 /* default to printing both mac layer and application layer */
dudmuck 19:c20591c95746 921 LoRaWan::flags.show_mac = 1;
dudmuck 19:c20591c95746 922 LoRaWan::flags.show_app = 1;
dudmuck 0:2ff18de8d48b 923
dudmuck 0:2ff18de8d48b 924 for (;;) {
dudmuck 0:2ff18de8d48b 925 console();
Wayne Roberts 21:1ac5ffad2726 926
Wayne Roberts 21:1ac5ffad2726 927 Radio::service();
dudmuck 0:2ff18de8d48b 928 } // ..for(;;)
dudmuck 0:2ff18de8d48b 929 }