point-2-point demo

Dependencies:   sx12xx_hal

radio chip selection

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

TX trigger selection

Edit main.h to define DIGITAL_TRIGGER or ANALOG_TRIGGER to chose whether transmit is initiated by digital pin (button/jumper) or analog pin(s) level change.

This project is intended to be used on two LoRa shields.

Each board sits in continuous RX mode, waiting for request packet.
If the received packet has good CRC, the packet is acknowledged along with read of ADC sample from the replying device.
The original request packet also contains instruction to set level of output pin.

Both sides of the link are running the same code, and each can initiate a transmission at any time.
No addressing is used, so only two nodes can operate on the radio channel.

Committer:
dudmuck
Date:
Fri Nov 10 17:42:50 2017 +0000
Revision:
2:5131512b4eb9
Parent:
1:d95d135a4fb4
Child:
3:cd312fc32558
add reception packet rssi and snr printing

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:1d8d218c5cc5 1 #include "sx127x_lora.h"
dudmuck 1:d95d135a4fb4 2 #include "uart_cmds.h"
dudmuck 0:1d8d218c5cc5 3
dudmuck 0:1d8d218c5cc5 4 DigitalOut myled(LED1);
dudmuck 0:1d8d218c5cc5 5
dudmuck 0:1d8d218c5cc5 6 SPI spi(D11, D12, D13); // mosi, miso, sclk
dudmuck 0:1d8d218c5cc5 7 // dio0, dio1, nss, spi, rst
dudmuck 0:1d8d218c5cc5 8 SX127x radio( D2, D3, D10, spi, A0); // sx1276 arduino shield
dudmuck 0:1d8d218c5cc5 9
dudmuck 0:1d8d218c5cc5 10 SX127x_lora lora(radio);
dudmuck 0:1d8d218c5cc5 11 DigitalInOut rfsw(A4); // for SX1276 arduino shield
dudmuck 0:1d8d218c5cc5 12
dudmuck 0:1d8d218c5cc5 13 InterruptIn user_button(USER_BUTTON);
dudmuck 0:1d8d218c5cc5 14 Timer t;
dudmuck 0:1d8d218c5cc5 15 Ticker ticker;
dudmuck 0:1d8d218c5cc5 16 AnalogIn a1(A1);
dudmuck 0:1d8d218c5cc5 17 DigitalOut pc6_out(PC_6);
dudmuck 0:1d8d218c5cc5 18
dudmuck 0:1d8d218c5cc5 19 DigitalOut jumper_out(PC_10);
dudmuck 0:1d8d218c5cc5 20 InterruptIn jumper_in(PC_12);
dudmuck 0:1d8d218c5cc5 21
dudmuck 0:1d8d218c5cc5 22 void rfsw_callback()
dudmuck 0:1d8d218c5cc5 23 {
dudmuck 0:1d8d218c5cc5 24 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER)
dudmuck 0:1d8d218c5cc5 25 rfsw = 1;
dudmuck 0:1d8d218c5cc5 26 else
dudmuck 0:1d8d218c5cc5 27 rfsw = 0;
dudmuck 0:1d8d218c5cc5 28 }
dudmuck 0:1d8d218c5cc5 29
dudmuck 0:1d8d218c5cc5 30 /**********************************************************************/
dudmuck 0:1d8d218c5cc5 31
dudmuck 0:1d8d218c5cc5 32 uint8_t out_pin_state;
dudmuck 0:1d8d218c5cc5 33
dudmuck 0:1d8d218c5cc5 34
dudmuck 0:1d8d218c5cc5 35 static uint16_t crc16( uint8_t *buffer, uint16_t length )
dudmuck 0:1d8d218c5cc5 36 {
dudmuck 0:1d8d218c5cc5 37 uint16_t i;
dudmuck 0:1d8d218c5cc5 38 // The CRC calculation follows CCITT
dudmuck 0:1d8d218c5cc5 39 const uint16_t polynom = 0x1021;
dudmuck 0:1d8d218c5cc5 40 // CRC initial value
dudmuck 0:1d8d218c5cc5 41 uint16_t crc = 0x0000;
dudmuck 0:1d8d218c5cc5 42
dudmuck 0:1d8d218c5cc5 43 if( buffer == NULL )
dudmuck 0:1d8d218c5cc5 44 {
dudmuck 0:1d8d218c5cc5 45 return 0;
dudmuck 0:1d8d218c5cc5 46 }
dudmuck 0:1d8d218c5cc5 47
dudmuck 0:1d8d218c5cc5 48 for( i = 0; i < length; ++i )
dudmuck 0:1d8d218c5cc5 49 {
dudmuck 0:1d8d218c5cc5 50 uint16_t j;
dudmuck 0:1d8d218c5cc5 51 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:1d8d218c5cc5 52 for( j = 0; j < 8; ++j )
dudmuck 0:1d8d218c5cc5 53 {
dudmuck 0:1d8d218c5cc5 54 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:1d8d218c5cc5 55 }
dudmuck 0:1d8d218c5cc5 56 }
dudmuck 0:1d8d218c5cc5 57
dudmuck 0:1d8d218c5cc5 58 return crc;
dudmuck 0:1d8d218c5cc5 59 }
dudmuck 0:1d8d218c5cc5 60
dudmuck 0:1d8d218c5cc5 61 void tx_ack()
dudmuck 0:1d8d218c5cc5 62 {
dudmuck 0:1d8d218c5cc5 63 uint8_t n = 0;
dudmuck 0:1d8d218c5cc5 64 uint16_t crc;
dudmuck 0:1d8d218c5cc5 65
dudmuck 0:1d8d218c5cc5 66 if (radio.rx_buf[0] == CMD_OUT_PIN) {
dudmuck 0:1d8d218c5cc5 67 uint16_t ain = a1.read_u16();
dudmuck 0:1d8d218c5cc5 68 radio.tx_buf[n++] = CMD_OUT_PIN_ACK;
dudmuck 0:1d8d218c5cc5 69 /* TODO read analog pin and digital input pin */
dudmuck 0:1d8d218c5cc5 70 radio.tx_buf[n++] = ain;
dudmuck 0:1d8d218c5cc5 71 radio.tx_buf[n++] = ain >> 8;
dudmuck 0:1d8d218c5cc5 72 } else
dudmuck 0:1d8d218c5cc5 73 radio.tx_buf[n++] = 0xff;
dudmuck 0:1d8d218c5cc5 74
dudmuck 0:1d8d218c5cc5 75 crc = crc16(radio.tx_buf, n);
dudmuck 0:1d8d218c5cc5 76 radio.tx_buf[n++] = crc;
dudmuck 0:1d8d218c5cc5 77 radio.tx_buf[n++] = crc >> 8;
dudmuck 0:1d8d218c5cc5 78
dudmuck 0:1d8d218c5cc5 79 lora.RegPayloadLength = n;
dudmuck 0:1d8d218c5cc5 80 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:1d8d218c5cc5 81
dudmuck 0:1d8d218c5cc5 82 lora.start_tx(lora.RegPayloadLength); /* begin transmission */
dudmuck 0:1d8d218c5cc5 83
dudmuck 0:1d8d218c5cc5 84 while (lora.service() != SERVICE_TX_DONE) /* wait for transmission to complete */
dudmuck 0:1d8d218c5cc5 85 ;
dudmuck 0:1d8d218c5cc5 86
dudmuck 0:1d8d218c5cc5 87 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:1d8d218c5cc5 88 }
dudmuck 0:1d8d218c5cc5 89
dudmuck 1:d95d135a4fb4 90 void radio_tx(uint8_t* payload, uint8_t payload_len)
dudmuck 0:1d8d218c5cc5 91 {
dudmuck 0:1d8d218c5cc5 92 int i;
dudmuck 1:d95d135a4fb4 93 uint8_t n = 0;
dudmuck 1:d95d135a4fb4 94 uint16_t crc;
dudmuck 1:d95d135a4fb4 95
dudmuck 1:d95d135a4fb4 96 while (payload_len > 0) {
dudmuck 1:d95d135a4fb4 97 //printf("n%u, paylen%u\r\n", n, payload_len);
dudmuck 1:d95d135a4fb4 98 payload_len--;
dudmuck 1:d95d135a4fb4 99 radio.tx_buf[payload_len] = payload[payload_len];
dudmuck 1:d95d135a4fb4 100 n++;
dudmuck 1:d95d135a4fb4 101 }
dudmuck 1:d95d135a4fb4 102
dudmuck 1:d95d135a4fb4 103 crc = crc16(radio.tx_buf, n);
dudmuck 1:d95d135a4fb4 104 radio.tx_buf[n++] = crc;
dudmuck 1:d95d135a4fb4 105 radio.tx_buf[n++] = crc >> 8;
dudmuck 1:d95d135a4fb4 106
dudmuck 1:d95d135a4fb4 107 lora.RegPayloadLength = n;
dudmuck 1:d95d135a4fb4 108 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:1d8d218c5cc5 109
dudmuck 0:1d8d218c5cc5 110 for (i = 0; i < 3; i++) {
dudmuck 0:1d8d218c5cc5 111 int rx_timeout_at;
dudmuck 0:1d8d218c5cc5 112
dudmuck 0:1d8d218c5cc5 113 lora.start_tx(lora.RegPayloadLength); /* begin transmission */
dudmuck 0:1d8d218c5cc5 114
dudmuck 0:1d8d218c5cc5 115 while (lora.service() != SERVICE_TX_DONE) /* wait for transmission to complete */
dudmuck 0:1d8d218c5cc5 116 ;
dudmuck 0:1d8d218c5cc5 117 rx_timeout_at = t.read_us() + 200000;
dudmuck 0:1d8d218c5cc5 118
dudmuck 0:1d8d218c5cc5 119 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:1d8d218c5cc5 120
dudmuck 0:1d8d218c5cc5 121 while (t.read_us() < rx_timeout_at) {
dudmuck 0:1d8d218c5cc5 122 if (lora.service() == SERVICE_READ_FIFO) {
dudmuck 0:1d8d218c5cc5 123 uint16_t rx_crc;
dudmuck 2:5131512b4eb9 124 printf("rssi:%ddBm snr:%.1fdB ", lora.get_pkt_rssi(), lora.RegPktSnrValue / 4.0);
dudmuck 0:1d8d218c5cc5 125 rx_crc = radio.rx_buf[lora.RegRxNbBytes-2];
dudmuck 0:1d8d218c5cc5 126 rx_crc |= radio.rx_buf[lora.RegRxNbBytes-1] << 8;
dudmuck 0:1d8d218c5cc5 127 crc = crc16(radio.rx_buf, lora.RegRxNbBytes-2);
dudmuck 0:1d8d218c5cc5 128 if (crc == rx_crc) {
dudmuck 0:1d8d218c5cc5 129 printf("crcOk %u\r\n", i);
dudmuck 0:1d8d218c5cc5 130 if (radio.rx_buf[0] == CMD_OUT_PIN_ACK) {
dudmuck 2:5131512b4eb9 131 uint16_t ain = radio.rx_buf[1];
dudmuck 2:5131512b4eb9 132 ain |= radio.rx_buf[2] << 8;
dudmuck 0:1d8d218c5cc5 133 printf("ain %u\r\n", ain);
dudmuck 0:1d8d218c5cc5 134 }
dudmuck 0:1d8d218c5cc5 135 return;
dudmuck 0:1d8d218c5cc5 136 } else
dudmuck 0:1d8d218c5cc5 137 printf("crcFail %04x != %04x\r\n", crc, rx_crc);
dudmuck 0:1d8d218c5cc5 138 }
dudmuck 0:1d8d218c5cc5 139 }
dudmuck 0:1d8d218c5cc5 140 printf("rx-timeout %u\r\n", i);
dudmuck 0:1d8d218c5cc5 141 } // ..for()
dudmuck 0:1d8d218c5cc5 142 }
dudmuck 0:1d8d218c5cc5 143
dudmuck 0:1d8d218c5cc5 144 volatile bool start_tx;
dudmuck 0:1d8d218c5cc5 145
dudmuck 0:1d8d218c5cc5 146 void button_isr()
dudmuck 0:1d8d218c5cc5 147 {
dudmuck 0:1d8d218c5cc5 148 if (!jumper_in.read())
dudmuck 0:1d8d218c5cc5 149 start_tx = true;
dudmuck 0:1d8d218c5cc5 150 }
dudmuck 0:1d8d218c5cc5 151
dudmuck 0:1d8d218c5cc5 152 void auto_tx()
dudmuck 0:1d8d218c5cc5 153 {
dudmuck 0:1d8d218c5cc5 154 if (jumper_in.read())
dudmuck 0:1d8d218c5cc5 155 start_tx = true;
dudmuck 0:1d8d218c5cc5 156 else
dudmuck 0:1d8d218c5cc5 157 ticker.detach();
dudmuck 0:1d8d218c5cc5 158 }
dudmuck 0:1d8d218c5cc5 159
dudmuck 0:1d8d218c5cc5 160 int main()
dudmuck 0:1d8d218c5cc5 161 {
dudmuck 0:1d8d218c5cc5 162 bool jin = false;
dudmuck 1:d95d135a4fb4 163 printf("\r\n2reset\r\n");
dudmuck 0:1d8d218c5cc5 164
dudmuck 0:1d8d218c5cc5 165 jumper_out = 1;
dudmuck 0:1d8d218c5cc5 166 jumper_in.mode(PullDown);
dudmuck 0:1d8d218c5cc5 167
dudmuck 0:1d8d218c5cc5 168 while (!user_button) {
dudmuck 0:1d8d218c5cc5 169 printf("button-lo\r\n");
dudmuck 0:1d8d218c5cc5 170 wait(0.01);
dudmuck 0:1d8d218c5cc5 171 }
dudmuck 0:1d8d218c5cc5 172 user_button.fall(&button_isr);
dudmuck 0:1d8d218c5cc5 173 t.start();
dudmuck 0:1d8d218c5cc5 174
dudmuck 0:1d8d218c5cc5 175 radio.rf_switch = rfsw_callback;
dudmuck 0:1d8d218c5cc5 176
dudmuck 0:1d8d218c5cc5 177 radio.set_frf_MHz(917.3);
dudmuck 0:1d8d218c5cc5 178 lora.enable();
dudmuck 0:1d8d218c5cc5 179 lora.setBw_KHz(500);
dudmuck 0:1d8d218c5cc5 180 lora.setSf(9);
dudmuck 0:1d8d218c5cc5 181
dudmuck 0:1d8d218c5cc5 182 /* RFO or PABOOST choice:
dudmuck 0:1d8d218c5cc5 183 * SX1276 shield: RFO if using 900MHz, or PA_BOOST if using 433MHz
dudmuck 0:1d8d218c5cc5 184 */
dudmuck 0:1d8d218c5cc5 185 rfsw.input();
dudmuck 0:1d8d218c5cc5 186 if (rfsw.read()) {
dudmuck 0:1d8d218c5cc5 187 printf("LAS\r\n");
dudmuck 0:1d8d218c5cc5 188 /* LAS HF=PA_BOOST LF=RFO */
dudmuck 0:1d8d218c5cc5 189 if (radio.HF)
dudmuck 0:1d8d218c5cc5 190 radio.RegPaConfig.bits.PaSelect = 1;
dudmuck 0:1d8d218c5cc5 191 else
dudmuck 0:1d8d218c5cc5 192 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:1d8d218c5cc5 193 } else {
dudmuck 0:1d8d218c5cc5 194 /* MAS shield board, only RFO TX */
dudmuck 0:1d8d218c5cc5 195 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:1d8d218c5cc5 196 printf("MAS\r\n");
dudmuck 0:1d8d218c5cc5 197 }
dudmuck 0:1d8d218c5cc5 198 rfsw.output();
dudmuck 0:1d8d218c5cc5 199 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 0:1d8d218c5cc5 200
dudmuck 0:1d8d218c5cc5 201 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:1d8d218c5cc5 202
dudmuck 0:1d8d218c5cc5 203 for (;;) {
dudmuck 0:1d8d218c5cc5 204
dudmuck 0:1d8d218c5cc5 205 if (jumper_in.read()) {
dudmuck 0:1d8d218c5cc5 206 if (!jin) {
dudmuck 0:1d8d218c5cc5 207 ticker.attach(auto_tx, 0.5);
dudmuck 0:1d8d218c5cc5 208 jin = true;
dudmuck 0:1d8d218c5cc5 209 }
dudmuck 0:1d8d218c5cc5 210 } else {
dudmuck 0:1d8d218c5cc5 211 jin = false;
dudmuck 0:1d8d218c5cc5 212 }
dudmuck 0:1d8d218c5cc5 213
dudmuck 0:1d8d218c5cc5 214 if (start_tx) {
dudmuck 1:d95d135a4fb4 215 start_tx = false;
dudmuck 1:d95d135a4fb4 216
dudmuck 1:d95d135a4fb4 217 uint8_t buf[2];
dudmuck 0:1d8d218c5cc5 218 out_pin_state ^= 1;
dudmuck 1:d95d135a4fb4 219 buf[0] = CMD_OUT_PIN;
dudmuck 1:d95d135a4fb4 220 buf[1] = out_pin_state;
dudmuck 1:d95d135a4fb4 221 printf("start_tx...\r\n");
dudmuck 1:d95d135a4fb4 222 radio_tx(buf, 2);
dudmuck 0:1d8d218c5cc5 223 }
dudmuck 0:1d8d218c5cc5 224 if (lora.service() == SERVICE_READ_FIFO) {
dudmuck 0:1d8d218c5cc5 225 uint16_t crc, rx_crc;
dudmuck 0:1d8d218c5cc5 226 int i;
dudmuck 0:1d8d218c5cc5 227 for (i = 0; i < lora.RegRxNbBytes; i++) {
dudmuck 0:1d8d218c5cc5 228 printf("%02x ", radio.rx_buf[i]);
dudmuck 0:1d8d218c5cc5 229 }
dudmuck 2:5131512b4eb9 230 printf(" rssi:%ddBm, snr:%.1fdB\r\n", lora.get_pkt_rssi(), lora.RegPktSnrValue / 4.0);
dudmuck 0:1d8d218c5cc5 231 rx_crc = radio.rx_buf[lora.RegRxNbBytes-2];
dudmuck 0:1d8d218c5cc5 232 rx_crc |= radio.rx_buf[lora.RegRxNbBytes-1] << 8;
dudmuck 0:1d8d218c5cc5 233 crc = crc16(radio.rx_buf, lora.RegRxNbBytes-2);
dudmuck 0:1d8d218c5cc5 234 if (crc == rx_crc) {
dudmuck 0:1d8d218c5cc5 235 printf("crcOk\r\n");
dudmuck 1:d95d135a4fb4 236 if (!parse_radio_rx(radio.rx_buf) && radio.rx_buf[0] == CMD_OUT_PIN) {
dudmuck 0:1d8d218c5cc5 237 pc6_out.write(radio.rx_buf[1]);
dudmuck 0:1d8d218c5cc5 238 printf("out pin state: %u", radio.rx_buf[1]);
dudmuck 0:1d8d218c5cc5 239 }
dudmuck 0:1d8d218c5cc5 240 printf("\r\n");
dudmuck 0:1d8d218c5cc5 241 tx_ack();
dudmuck 0:1d8d218c5cc5 242 } else
dudmuck 0:1d8d218c5cc5 243 printf("crc %04x != %04x\r\n", crc, rx_crc);
dudmuck 0:1d8d218c5cc5 244 } // ..if something received
dudmuck 1:d95d135a4fb4 245
dudmuck 1:d95d135a4fb4 246 uart_service();
dudmuck 0:1d8d218c5cc5 247 } // ..for (;;)
dudmuck 0:1d8d218c5cc5 248 }
dudmuck 0:1d8d218c5cc5 249