Aloha implementation of LoRa technology

Dependencies:   SX1276Lib mbed

Fork of SX1276PingPong by Semtech

Committer:
rba90
Date:
Wed Jun 08 22:15:29 2016 +0000
Revision:
16:c3c6b13c3c42
Parent:
15:f790f35839db
random stuff

Who changed what in which revision?

UserRevisionLine numberNew contents of line
GregCr 0:1ed39951ab7b 1 #include "mbed.h"
GregCr 4:5ece30264cd9 2 #include "main.h"
GregCr 14:c7251480feb9 3 #include "sx1276-hal.h"
GregCr 8:f956dee63a56 4 #include "debug.h"
rba90 15:f790f35839db 5 #include "Aloha.h"
rba90 15:f790f35839db 6 #include "AlohaPacket.h"
GregCr 0:1ed39951ab7b 7
GregCr 0:1ed39951ab7b 8 /* Set this flag to '1' to display debug messages on the console */
rba90 15:f790f35839db 9 #define DEBUG_MESSAGE 1
GregCr 0:1ed39951ab7b 10
GregCr 5:f2431c4fe3bb 11 #define RF_FREQUENCY 868000000 // Hz
GregCr 0:1ed39951ab7b 12 #define TX_OUTPUT_POWER 14 // 14 dBm
rba90 15:f790f35839db 13 #define LORA_BANDWIDTH 2 // [0: 125 kHz,
rba90 15:f790f35839db 14 // 1: 250 kHz,
rba90 15:f790f35839db 15 // 2: 500 kHz,
rba90 15:f790f35839db 16 // 3: Reserved]
rba90 15:f790f35839db 17 #define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
rba90 15:f790f35839db 18 #define LORA_CODINGRATE 1 // [1: 4/5,
rba90 15:f790f35839db 19 // 2: 4/6,
rba90 15:f790f35839db 20 // 3: 4/7,
rba90 15:f790f35839db 21 // 4: 4/8]
rba90 15:f790f35839db 22 #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
rba90 15:f790f35839db 23 #define LORA_SYMBOL_TIMEOUT 5 // Symbols
rba90 15:f790f35839db 24 #define LORA_FIX_LENGTH_PAYLOAD_ON false
rba90 15:f790f35839db 25 #define LORA_FHSS_ENABLED false
rba90 15:f790f35839db 26 #define LORA_NB_SYMB_HOP 4
rba90 15:f790f35839db 27 #define LORA_IQ_INVERSION_ON false
rba90 15:f790f35839db 28 #define LORA_CRC_ENABLED true
GregCr 0:1ed39951ab7b 29
GregCr 0:1ed39951ab7b 30
GregCr 7:c1bbd6c56979 31 #define RX_TIMEOUT_VALUE 3500000 // in us
rba90 15:f790f35839db 32 #define BUFFER_SIZE 4 // Define the payload size here
GregCr 0:1ed39951ab7b 33
GregCr 3:8b9e2a4df4b5 34 DigitalOut led(LED2);
rba90 15:f790f35839db 35
rba90 15:f790f35839db 36 uint16_t BufferSize = BUFFER_SIZE;
rba90 15:f790f35839db 37 uint8_t Buffer[BUFFER_SIZE];
rba90 15:f790f35839db 38
rba90 15:f790f35839db 39 int16_t RssiValue = 0.0;
rba90 15:f790f35839db 40 int8_t SnrValue = 0.0;
GregCr 3:8b9e2a4df4b5 41
GregCr 0:1ed39951ab7b 42 /*
GregCr 0:1ed39951ab7b 43 * Global variables declarations
GregCr 0:1ed39951ab7b 44 */
mluis 10:7af820d1e1df 45 typedef enum
mluis 10:7af820d1e1df 46 {
mluis 10:7af820d1e1df 47 LOWPOWER = 0,
mluis 10:7af820d1e1df 48 IDLE,
mluis 10:7af820d1e1df 49
mluis 10:7af820d1e1df 50 RX,
mluis 10:7af820d1e1df 51 RX_TIMEOUT,
mluis 10:7af820d1e1df 52 RX_ERROR,
mluis 10:7af820d1e1df 53
mluis 10:7af820d1e1df 54 TX,
mluis 10:7af820d1e1df 55 TX_TIMEOUT,
mluis 10:7af820d1e1df 56
mluis 10:7af820d1e1df 57 CAD,
mluis 10:7af820d1e1df 58 CAD_DONE
mluis 10:7af820d1e1df 59 }AppStates_t;
GregCr 0:1ed39951ab7b 60
mluis 10:7af820d1e1df 61 volatile AppStates_t State = LOWPOWER;
mluis 10:7af820d1e1df 62
rba90 15:f790f35839db 63
mluis 10:7af820d1e1df 64 /*!
mluis 10:7af820d1e1df 65 * Radio events function pointer
mluis 10:7af820d1e1df 66 */
mluis 10:7af820d1e1df 67 static RadioEvents_t RadioEvents;
mluis 10:7af820d1e1df 68
mluis 10:7af820d1e1df 69 /*
mluis 10:7af820d1e1df 70 * Global variables declarations
mluis 10:7af820d1e1df 71 */
GregCr 14:c7251480feb9 72 SX1276MB1xAS Radio( NULL );
GregCr 0:1ed39951ab7b 73
rba90 15:f790f35839db 74 // aloha protocol
rba90 15:f790f35839db 75 Aloha aloha;
GregCr 0:1ed39951ab7b 76
rba90 16:c3c6b13c3c42 77 // user button
rba90 16:c3c6b13c3c42 78 InterruptIn UserButton(USER_BUTTON);
rba90 16:c3c6b13c3c42 79 static int seqid = 0;
rba90 16:c3c6b13c3c42 80
rba90 16:c3c6b13c3c42 81 void sendMessage()
rba90 16:c3c6b13c3c42 82 {
rba90 16:c3c6b13c3c42 83 HeaderStruct header;
rba90 16:c3c6b13c3c42 84 DataStruct data;
rba90 16:c3c6b13c3c42 85
rba90 16:c3c6b13c3c42 86 memset(&header, 0, sizeof(header));
rba90 16:c3c6b13c3c42 87 memset(&data, 0, sizeof(data));
rba90 16:c3c6b13c3c42 88
rba90 16:c3c6b13c3c42 89 header.fid = 0x0;
rba90 16:c3c6b13c3c42 90 header.no = (uint8_t) seqid;
rba90 16:c3c6b13c3c42 91 data.pd0 = 0xff;
rba90 16:c3c6b13c3c42 92 data.pd1 = 0xff;
rba90 16:c3c6b13c3c42 93
rba90 16:c3c6b13c3c42 94 uint8_t buffer[4];
rba90 16:c3c6b13c3c42 95 createAlohaPacket(buffer, &header, &data);
rba90 16:c3c6b13c3c42 96
rba90 16:c3c6b13c3c42 97 Radio.Send(buffer, 4);
rba90 16:c3c6b13c3c42 98 }
rba90 16:c3c6b13c3c42 99
rba90 16:c3c6b13c3c42 100 void sendAck(int id)
rba90 16:c3c6b13c3c42 101 {
rba90 16:c3c6b13c3c42 102 HeaderStruct header;
rba90 16:c3c6b13c3c42 103 DataStruct data;
rba90 16:c3c6b13c3c42 104
rba90 16:c3c6b13c3c42 105 memset(&header, 0, sizeof(header));
rba90 16:c3c6b13c3c42 106 memset(&data, 0, sizeof(data));
rba90 16:c3c6b13c3c42 107
rba90 16:c3c6b13c3c42 108 header.fid = 0x1;
rba90 16:c3c6b13c3c42 109 header.no = (uint8_t) id;
rba90 16:c3c6b13c3c42 110 data.pd0 = 0x00;
rba90 16:c3c6b13c3c42 111 data.pd1 = 0x00;
rba90 16:c3c6b13c3c42 112
rba90 16:c3c6b13c3c42 113 uint8_t buffer[4];
rba90 16:c3c6b13c3c42 114 createAlohaPacket(buffer, &header, &data);
rba90 16:c3c6b13c3c42 115
rba90 16:c3c6b13c3c42 116 Radio.Send(buffer, 4);
rba90 16:c3c6b13c3c42 117 }
rba90 16:c3c6b13c3c42 118
rba90 16:c3c6b13c3c42 119
rba90 15:f790f35839db 120 void setExpire()
GregCr 0:1ed39951ab7b 121 {
rba90 15:f790f35839db 122 if (aloha.attempts >= ALOHA_MAX_ATTEMPT)
rba90 15:f790f35839db 123 {
rba90 15:f790f35839db 124 aloha.state = Aloha::EXPIRED;
rba90 15:f790f35839db 125 }
rba90 15:f790f35839db 126 else
rba90 15:f790f35839db 127 {
rba90 15:f790f35839db 128 aloha.state = Aloha::RETRANSMIT;
rba90 15:f790f35839db 129 }
rba90 15:f790f35839db 130 }
mluis 10:7af820d1e1df 131
rba90 16:c3c6b13c3c42 132 void userButtonHandler()
rba90 16:c3c6b13c3c42 133 {
rba90 16:c3c6b13c3c42 134 seqid += 1;
rba90 16:c3c6b13c3c42 135 sendMessage();
rba90 16:c3c6b13c3c42 136 }
rba90 16:c3c6b13c3c42 137
rba90 15:f790f35839db 138 void RadioInit()
rba90 15:f790f35839db 139 {
mluis 10:7af820d1e1df 140 // Initialize Radio driver
mluis 10:7af820d1e1df 141 RadioEvents.TxDone = OnTxDone;
mluis 10:7af820d1e1df 142 RadioEvents.RxDone = OnRxDone;
mluis 10:7af820d1e1df 143 RadioEvents.RxError = OnRxError;
mluis 10:7af820d1e1df 144 RadioEvents.TxTimeout = OnTxTimeout;
mluis 10:7af820d1e1df 145 RadioEvents.RxTimeout = OnRxTimeout;
mluis 10:7af820d1e1df 146 Radio.Init( &RadioEvents );
GregCr 0:1ed39951ab7b 147
rba90 15:f790f35839db 148 // detect radio hardware
GregCr 7:c1bbd6c56979 149 while( Radio.Read( REG_VERSION ) == 0x00 )
GregCr 2:59e108728d71 150 {
rba90 15:f790f35839db 151 printf( "Radio could not be detected!\n\r" );
GregCr 7:c1bbd6c56979 152 wait( 1 );
GregCr 2:59e108728d71 153 }
rba90 15:f790f35839db 154 printf("RadioRegVersion: %d\r\n", Radio.Read( REG_VERSION ));
GregCr 14:c7251480feb9 155
rba90 15:f790f35839db 156 // set radio frequency channel
GregCr 0:1ed39951ab7b 157 Radio.SetChannel( RF_FREQUENCY );
GregCr 3:8b9e2a4df4b5 158
rba90 15:f790f35839db 159 // set radio parameter
GregCr 0:1ed39951ab7b 160 Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
GregCr 0:1ed39951ab7b 161 LORA_SPREADING_FACTOR, LORA_CODINGRATE,
GregCr 0:1ed39951ab7b 162 LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
GregCr 3:8b9e2a4df4b5 163 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
GregCr 7:c1bbd6c56979 164 LORA_IQ_INVERSION_ON, 2000000 );
GregCr 0:1ed39951ab7b 165
GregCr 0:1ed39951ab7b 166 Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
GregCr 0:1ed39951ab7b 167 LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
mluis 9:e764990e45df 168 LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0,
GregCr 3:8b9e2a4df4b5 169 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
GregCr 3:8b9e2a4df4b5 170 LORA_IQ_INVERSION_ON, true );
rba90 15:f790f35839db 171 }
rba90 15:f790f35839db 172
GregCr 0:1ed39951ab7b 173
rba90 15:f790f35839db 174 int main()
rba90 15:f790f35839db 175 {
rba90 15:f790f35839db 176 RadioInit();
rba90 16:c3c6b13c3c42 177 UserButton.rise(userButtonHandler);
GregCr 0:1ed39951ab7b 178
rba90 16:c3c6b13c3c42 179 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 15:f790f35839db 180 while (1)
GregCr 0:1ed39951ab7b 181 {
GregCr 0:1ed39951ab7b 182 switch( State )
GregCr 0:1ed39951ab7b 183 {
GregCr 0:1ed39951ab7b 184 case RX:
rba90 15:f790f35839db 185 // if the receive frame is an ack, then cancel the timer
rba90 15:f790f35839db 186 // otherwise process the frame
rba90 15:f790f35839db 187 HeaderStruct header;
rba90 16:c3c6b13c3c42 188 DataStruct data;
rba90 16:c3c6b13c3c42 189
rba90 15:f790f35839db 190 memset(&header, 0, sizeof(header));
rba90 16:c3c6b13c3c42 191 memset(&data, 0, sizeof(data));
rba90 15:f790f35839db 192
rba90 16:c3c6b13c3c42 193 // decode data
rba90 16:c3c6b13c3c42 194 dissectAlohaPacket(Buffer, &header, &data);
rba90 16:c3c6b13c3c42 195
rba90 16:c3c6b13c3c42 196 // process packet
rba90 16:c3c6b13c3c42 197 switch (header.fid)
rba90 16:c3c6b13c3c42 198 {
rba90 16:c3c6b13c3c42 199 case 0x0: // data packet
rba90 16:c3c6b13c3c42 200 sendAck(header.no);
rba90 16:c3c6b13c3c42 201 break;
rba90 16:c3c6b13c3c42 202
rba90 16:c3c6b13c3c42 203 case 0x1: // ack received
rba90 16:c3c6b13c3c42 204 aloha.AlohaAckTimeout.detach();
rba90 16:c3c6b13c3c42 205 aloha.state = Aloha::IDLE;
rba90 16:c3c6b13c3c42 206 break;
rba90 16:c3c6b13c3c42 207
rba90 16:c3c6b13c3c42 208 default:
rba90 16:c3c6b13c3c42 209 break;
rba90 16:c3c6b13c3c42 210 }
rba90 16:c3c6b13c3c42 211
rba90 15:f790f35839db 212 if (header.fid == 0x01)
GregCr 0:1ed39951ab7b 213 {
rba90 15:f790f35839db 214 aloha.AlohaAckTimeout.detach();
GregCr 0:1ed39951ab7b 215 }
rba90 15:f790f35839db 216
rba90 15:f790f35839db 217 // TODO: process the frame
rba90 16:c3c6b13c3c42 218
rba90 16:c3c6b13c3c42 219
rba90 16:c3c6b13c3c42 220 printf("RECV::fid=0x%x, seqid=0x%x, pd0=0x%x, pd1=0x%x\r\n", header.fid, header.no, data.pd0, data.pd1);
rba90 16:c3c6b13c3c42 221
rba90 16:c3c6b13c3c42 222 // enter listening mode
rba90 16:c3c6b13c3c42 223 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 16:c3c6b13c3c42 224
rba90 16:c3c6b13c3c42 225 State = LOWPOWER;
GregCr 0:1ed39951ab7b 226 break;
rba90 15:f790f35839db 227 case TX:
rba90 15:f790f35839db 228 // transmit done
rba90 16:c3c6b13c3c42 229 // set the state to pending and attach the timer with random delay
rba90 16:c3c6b13c3c42 230
rba90 16:c3c6b13c3c42 231 // we dont need ack for ack
rba90 16:c3c6b13c3c42 232 if (aloha.state == Aloha::ACK_RESP)
rba90 16:c3c6b13c3c42 233 {
rba90 16:c3c6b13c3c42 234 aloha.state = Aloha::IDLE;
rba90 16:c3c6b13c3c42 235 break;
rba90 16:c3c6b13c3c42 236 }
rba90 16:c3c6b13c3c42 237
rba90 16:c3c6b13c3c42 238 // set delay time
rba90 16:c3c6b13c3c42 239 if (aloha.state == Aloha::IDLE)
rba90 16:c3c6b13c3c42 240 {
rba90 16:c3c6b13c3c42 241 aloha.delay = (Radio.Random() % 1000) / 1000.0f;
rba90 16:c3c6b13c3c42 242 }
rba90 16:c3c6b13c3c42 243 else if (aloha.state == Aloha::RETRANSMIT)
rba90 16:c3c6b13c3c42 244 {
rba90 16:c3c6b13c3c42 245 aloha.delay *= 2;
rba90 16:c3c6b13c3c42 246 }
rba90 16:c3c6b13c3c42 247
rba90 16:c3c6b13c3c42 248 aloha.AlohaAckTimeout.detach();
rba90 16:c3c6b13c3c42 249 aloha.AlohaAckTimeout.attach(&setExpire, aloha.delay);
rba90 16:c3c6b13c3c42 250
rba90 16:c3c6b13c3c42 251 // increase the attempt counter
rba90 16:c3c6b13c3c42 252 aloha.attempts += 1;
rba90 16:c3c6b13c3c42 253
rba90 16:c3c6b13c3c42 254 // enter listening mode
rba90 16:c3c6b13c3c42 255 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 16:c3c6b13c3c42 256
rba90 16:c3c6b13c3c42 257 // state transition
rba90 15:f790f35839db 258 aloha.state = Aloha::PENDING;
rba90 16:c3c6b13c3c42 259
rba90 16:c3c6b13c3c42 260 State = LOWPOWER;
GregCr 0:1ed39951ab7b 261 break;
GregCr 0:1ed39951ab7b 262 case RX_TIMEOUT:
rba90 15:f790f35839db 263 // enter listening mode
rba90 16:c3c6b13c3c42 264 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 16:c3c6b13c3c42 265
rba90 16:c3c6b13c3c42 266 State = LOWPOWER;
GregCr 0:1ed39951ab7b 267 break;
GregCr 0:1ed39951ab7b 268 case RX_ERROR:
rba90 15:f790f35839db 269 // we don't handle crc failed situation
rba90 16:c3c6b13c3c42 270 // enter listening mode
rba90 16:c3c6b13c3c42 271 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 16:c3c6b13c3c42 272
rba90 16:c3c6b13c3c42 273 State = LOWPOWER;
GregCr 0:1ed39951ab7b 274 break;
GregCr 0:1ed39951ab7b 275 case TX_TIMEOUT:
rba90 15:f790f35839db 276 // we don't handle hardware error
rba90 16:c3c6b13c3c42 277 // enter listening mode
rba90 16:c3c6b13c3c42 278 Radio.Rx( RX_TIMEOUT_VALUE );
rba90 16:c3c6b13c3c42 279
rba90 16:c3c6b13c3c42 280 State = LOWPOWER;
GregCr 0:1ed39951ab7b 281 break;
GregCr 0:1ed39951ab7b 282 case LOWPOWER:
GregCr 0:1ed39951ab7b 283 break;
GregCr 0:1ed39951ab7b 284 default:
rba90 16:c3c6b13c3c42 285 State = LOWPOWER;
rba90 15:f790f35839db 286 break;
rba90 15:f790f35839db 287 }
rba90 15:f790f35839db 288
rba90 15:f790f35839db 289 switch (aloha.state)
rba90 15:f790f35839db 290 {
rba90 15:f790f35839db 291 case Aloha::IDLE:
rba90 15:f790f35839db 292 // transmit packet if any
rba90 16:c3c6b13c3c42 293 // printf("Aloha::IDLE\r\n");
rba90 15:f790f35839db 294 break;
rba90 15:f790f35839db 295
rba90 15:f790f35839db 296 case Aloha::PENDING:
rba90 15:f790f35839db 297 // set rx time
rba90 16:c3c6b13c3c42 298 // printf("Aloha::PENDING, delay=%f, attempt=%d\r\n", aloha.delay, aloha.attempts);
GregCr 0:1ed39951ab7b 299 break;
rba90 15:f790f35839db 300
rba90 15:f790f35839db 301 case Aloha::RETRANSMIT:
rba90 15:f790f35839db 302 // send the packet again
rba90 16:c3c6b13c3c42 303 sendMessage();
rba90 16:c3c6b13c3c42 304
rba90 16:c3c6b13c3c42 305 // printf("Aloha::RETRANSMIT\r\n");
rba90 15:f790f35839db 306 break;
rba90 15:f790f35839db 307 case Aloha::EXPIRED:
rba90 15:f790f35839db 308 // give up the transmission
rba90 15:f790f35839db 309 // back to idle
rba90 16:c3c6b13c3c42 310 aloha.attempts = 0;
rba90 16:c3c6b13c3c42 311
rba90 15:f790f35839db 312 aloha.state = Aloha::IDLE;
rba90 16:c3c6b13c3c42 313 // printf("Aloha::EXPIRED\r\n");
rba90 16:c3c6b13c3c42 314 break;
rba90 16:c3c6b13c3c42 315 case Aloha::ACK_RESP:
rba90 16:c3c6b13c3c42 316 break;
rba90 16:c3c6b13c3c42 317 default:
rba90 15:f790f35839db 318 break;
rba90 15:f790f35839db 319 }
GregCr 0:1ed39951ab7b 320 }
GregCr 0:1ed39951ab7b 321 }
GregCr 0:1ed39951ab7b 322
GregCr 0:1ed39951ab7b 323 void OnTxDone( void )
GregCr 0:1ed39951ab7b 324 {
GregCr 5:f2431c4fe3bb 325 Radio.Sleep( );
GregCr 0:1ed39951ab7b 326 State = TX;
rba90 15:f790f35839db 327 printf( "> OnTxDone\n\r" );
GregCr 0:1ed39951ab7b 328 }
GregCr 0:1ed39951ab7b 329
GregCr 4:5ece30264cd9 330 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
GregCr 0:1ed39951ab7b 331 {
GregCr 0:1ed39951ab7b 332 Radio.Sleep( );
GregCr 0:1ed39951ab7b 333 BufferSize = size;
GregCr 0:1ed39951ab7b 334 memcpy( Buffer, payload, BufferSize );
GregCr 0:1ed39951ab7b 335 RssiValue = rssi;
GregCr 0:1ed39951ab7b 336 SnrValue = snr;
GregCr 0:1ed39951ab7b 337 State = RX;
rba90 15:f790f35839db 338 printf( "> OnRxDone\n\r" );
GregCr 0:1ed39951ab7b 339 }
GregCr 0:1ed39951ab7b 340
GregCr 0:1ed39951ab7b 341 void OnTxTimeout( void )
GregCr 0:1ed39951ab7b 342 {
GregCr 0:1ed39951ab7b 343 Radio.Sleep( );
GregCr 0:1ed39951ab7b 344 State = TX_TIMEOUT;
rba90 15:f790f35839db 345 printf( "> OnTxTimeout\n\r" );
GregCr 0:1ed39951ab7b 346 }
GregCr 0:1ed39951ab7b 347
GregCr 0:1ed39951ab7b 348 void OnRxTimeout( void )
GregCr 0:1ed39951ab7b 349 {
GregCr 0:1ed39951ab7b 350 Radio.Sleep( );
GregCr 1:126d70d374f6 351 Buffer[ BufferSize ] = 0;
GregCr 0:1ed39951ab7b 352 State = RX_TIMEOUT;
rba90 15:f790f35839db 353 printf( "> OnRxTimeout\n\r" );
GregCr 0:1ed39951ab7b 354 }
GregCr 0:1ed39951ab7b 355
GregCr 0:1ed39951ab7b 356 void OnRxError( void )
GregCr 0:1ed39951ab7b 357 {
GregCr 0:1ed39951ab7b 358 Radio.Sleep( );
GregCr 0:1ed39951ab7b 359 State = RX_ERROR;
rba90 15:f790f35839db 360 printf( "> OnRxError\n\r" );
GregCr 0:1ed39951ab7b 361 }