Lora Transport Abstraction Layer for sx1272

Dependents:   lora-transceiver

Files at this revision

API Documentation at this revision

Comitter:
trusch
Date:
Thu Oct 13 09:40:21 2016 +0000
Commit message:
initial commit;

Changed in this revision

LoraTransport.cpp Show annotated file Show diff for this revision Revisions of this file
LoraTransport.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 518c8dac75f3 LoraTransport.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoraTransport.cpp	Thu Oct 13 09:40:21 2016 +0000
@@ -0,0 +1,326 @@
+#include "LoraTransport.h"
+#include "mbed.h"
+
+namespace LoraTransport {
+
+    namespace {
+
+        void onTxDone();
+        void onTxTimeout();
+        void onRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr);
+        void onRxTimeout();
+        void onCadDone(bool);
+        void onRxError();
+
+        XRange _radio(onTxDone, onTxTimeout, onRxDone, onRxTimeout, onRxError, NULL, onCadDone );
+        mbed::Timer _timer;
+        int _deadline;
+        uint16_t _addr;
+        int16_t _rssi_value;
+        int8_t _snr_value;
+        State _state;
+        State _last_error_state;
+        uint8_t _next_packet_number;
+        Packet _packet;
+        Ack _ack;
+
+        /*bool overNineThousand(int n){
+            return n > 9000; // https://www.youtube.com/watch?v=LqSg9yVfzV0
+        }*/
+
+        void onCadDone(bool activityDetected){
+            _radio.Sleep();
+            if(activityDetected){
+                _radio.StartCad();
+            }else{
+                wait_ms((_radio.Random()%100)*10);
+                if(_state == TX_MSG){
+                    _radio.Send((uint8_t*)&_packet, _packet.payload_size+5);
+                }else if(_state == TX_SUCCESS_ACK || _state == TX_ERROR_ACK){
+                    _radio.Send((uint8_t*)&_ack, sizeof(_ack));
+                }
+            }
+        }
+
+        void onTxTimeout(){
+            _radio.Sleep();
+            //printf("tx timeout\r\n");
+            //printf("time on air for packet: %f\r\n",_radio.TimeOnAir(MODEM_LORA,_packet.payload_size+5));
+            if(_timer.read_us() > _deadline){
+                //printf("deadline reached, give up\r\n");
+                _timer.stop();
+                if(_state == TX_MSG){
+                    //printf("tx timeout while sending message\r\n");
+                    // timeout sending message
+                    _last_error_state = TX_MSG_TIMEOUT;
+                    _state = TX_ERROR;
+                }else if(_state == TX_SUCCESS_ACK){
+                    //printf("tx timeout while sending success ack\r\n");
+                    // timeout sending success ack
+                    _last_error_state = TX_SUCCESS_ACK_TIMEOUT;
+                    _state = RX_ERROR;
+                }else if(_state == TX_ERROR_ACK){
+                    //printf("tx timeout while sending error ack\r\n");
+                    // timeout sending error ack
+                    _last_error_state = TX_ERROR_ACK_TIMEOUT;
+                    _state = RX_ERROR;
+                }
+            }else{
+                _radio.StartCad();
+            }
+        }
+
+        void onTxDone(){
+            _radio.Sleep();
+            if(_state == TX_MSG){
+                // sending message ready, now wait for ack
+                _state = RX_ACK;
+                _radio.Rx(RX_TIMEOUT_VALUE);
+            }else if(_state == TX_SUCCESS_ACK){
+                // sending success ack ready -> success!
+                _timer.stop();
+                _state = RX_SUCCESS;
+            }else if(_state == TX_ERROR_ACK){
+                // sending error ack ready
+                if(_timer.read_us() > _deadline){
+                    // no time for retry
+                    //printf("error ack transmitted, give up\r\n");
+                    _last_error_state = RX_MSG_ERROR;
+                    _timer.stop();
+                    _state = RX_ERROR;
+                }else{
+                    // we have time for retry!
+                    //printf("error ack transmitted, retry\r\n");
+                    _state = RX_MSG;
+                    _radio.Rx(RX_TIMEOUT_VALUE);
+                }
+            }
+        }
+
+        void onRxTimeout(){
+            _radio.Sleep();
+            if(_state == RX_MSG){
+                if(_timer.read_us() > _deadline){
+                    // no time for retry
+                    //printf("rx msg timeout, give up\r\n");
+                    _timer.stop();
+                    _last_error_state = RX_MSG_TIMEOUT;
+                    _state = RX_ERROR;
+                }else{
+                    // we have time for retry!
+                    //printf("rx msg timeout, retry\r\n");
+                    _radio.Rx(RX_TIMEOUT_VALUE);
+                }
+            }else if(_state == RX_ACK){
+                // no ack received
+                if(_timer.read_us() > _deadline){
+                    // no time for retry
+                    //printf("rx ack timeout, give up\r\n");
+                    _timer.stop();
+                    _last_error_state = RX_ACK_TIMEOUT;
+                    _state = TX_ERROR;
+                }else{
+                    // we have time for retry!
+                    //printf("rx ack timeout, retry\r\n");
+                    _state = TX_MSG;
+                    _radio.StartCad();
+                }
+            }
+        }
+
+        void onRxError(){
+            _radio.Sleep();
+            if(_state == RX_MSG){
+                if(_timer.read_us() > _deadline){
+                    //printf("rx message error, give up\r\n");
+                    // no time for retry
+                    _timer.stop();
+                    _last_error_state = RX_MSG_ERROR;
+                    _state = RX_ERROR;
+                }else{
+                    // we have time for retry -> send fail ack;
+                    //printf("rx message error, send fail ack\r\n");
+                    _ack.from_addr = _addr;
+                    _ack.to_addr = 0;
+                    _ack.success = false;
+                    _state = TX_ERROR_ACK;
+                    _radio.StartCad();
+                }
+            }else if(_state == RX_ACK){
+                // no ack received
+                if(_timer.read_us() > _deadline){
+                    // no time for retry
+                    //printf("rx ack error, give up\r\n");
+                    _timer.stop();
+                    _last_error_state = RX_ACK_TIMEOUT;
+                    _state = TX_ERROR;
+                }else{
+                    // we have time for retry!
+                    //printf("rx ack error, retry\r\n");
+                    _state = TX_MSG;
+                    _radio.StartCad();
+                }
+            }
+        }
+
+        void onRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ){
+            _radio.Sleep();
+            _rssi_value = rssi;
+            _snr_value = snr;
+            if(_state == RX_MSG){
+                _packet.to_addr = *((uint16_t*)(payload+2));
+                if(_packet.to_addr != _addr && _packet.to_addr != 0){
+                    //packet is not for us
+                    if(_timer.read_us() > _deadline){
+                        // no time for retry
+                        _timer.stop();
+                        _last_error_state = RX_MSG_TIMEOUT;
+                        _state = RX_ERROR;
+                    }else{
+                        //printf("packet is not for us, retry\r\n");
+                        _state = RX_MSG;
+                        _radio.Rx(RX_TIMEOUT_VALUE);
+                    }
+                }else{
+                    //packet is for us
+                    _packet.from_addr = *((uint16_t*)(payload));
+                    _packet.packet_number = *(payload+4);
+                    _packet.payload_size = size-5;
+                    memcpy(_packet.payload, payload+5, _packet.payload_size);
+                    _ack.packet_number = _packet.packet_number;
+                    _ack.from_addr = _packet.to_addr;
+                    _ack.to_addr = _packet.from_addr;
+                    _ack.success = true;
+                    _state = TX_SUCCESS_ACK;
+                    _radio.StartCad();
+                }
+            }else if(_state == RX_ACK){
+                _ack.to_addr = *((uint16_t*)(payload+2));
+                if(_ack.to_addr != _addr && _ack.to_addr != 0){
+                    //ack is not for us
+                    if(_timer.read_us() > _deadline){
+                        //printf("ack is not for us, give up\r\n");
+                        // no time for retry
+                        _timer.stop();
+                        _last_error_state = RX_ACK_TIMEOUT;
+                        _state = TX_ERROR;
+                    }else{
+                        //printf("ack is not for us, retry\r\n");
+                        _state = RX_ACK;
+                        _radio.Rx(RX_TIMEOUT_VALUE);
+                    }
+                }else{
+                    //ack is for us
+                    _ack.from_addr = *((uint16_t*)payload);
+                    _ack.packet_number = *(payload+4);
+                    _ack.success = *(payload+5);
+                    if(_ack.success == true && _ack.packet_number == _packet.packet_number){
+                        // got success ack -> transmission completed!
+                        _timer.stop();
+                        _state = TX_SUCCESS;
+                    }else{
+                        if(_timer.read_us() > _deadline){
+                            // no time for retry
+                            //printf("got fail ack, give up\r\n");
+                            _timer.stop();
+                            _last_error_state = TX_MSG_TIMEOUT;
+                            _state = TX_ERROR;
+                        }else{
+                            //retry
+                            //printf("got fail ack, retry\r\n");
+                            _state = TX_MSG;
+                            _radio.StartCad();
+                        }
+                    }
+                }
+            }
+        }
+
+    }//end anonym namespace
+
+
+    void init(){
+        _addr = 0;
+        _rssi_value = 0;
+        _snr_value = 0;
+        _state = IDLE;
+        _last_error_state = IDLE;
+        _next_packet_number = 0;
+        _radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
+                           LORA_SPREADING_FACTOR, LORA_CODINGRATE,
+                           LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
+                           LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
+                           LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE );
+        _radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
+                           LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
+                           LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0,
+                           LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
+                           LORA_IQ_INVERSION_ON, true );
+    }
+
+    void setAddress(uint16_t addr){
+        _addr = addr;
+    }
+
+    void send(uint16_t addr, uint8_t *ptr, uint8_t len, uint32_t timeout){
+        _packet.from_addr = _addr;
+        _packet.to_addr = addr;
+        _packet.packet_number = _next_packet_number++;
+        memcpy(_packet.payload, ptr, len);
+        _packet.payload_size = len;
+        _state = CAD_RUNNING;
+        _deadline = timeout;
+        _timer.stop();
+        _timer.reset();
+        _timer.start();
+        _state = TX_MSG;
+        //printf("send message with %i bytes\r\n",len);
+        _radio.StartCad();
+    }
+
+    void recv(uint32_t timeout){
+        _state = RX_MSG;
+        _deadline = timeout;
+        _timer.stop();
+        _timer.reset();
+        _timer.start();
+        _state = RX_MSG;
+        _radio.Rx(RX_TIMEOUT_VALUE);
+    }
+
+    State getState(){
+        return _state;
+    }
+    State getLastErrorState(){
+        return _last_error_state;
+    }
+    Packet& getPacket(){
+        return _packet;
+    }
+    int16_t getRSSI(){
+        return _rssi_value;
+    }
+    int8_t getSNR(){
+        return _snr_value;
+    }
+
+    bool done(){
+        if( _state == TX_ERROR ||
+            _state == TX_SUCCESS ||
+            _state == RX_ERROR ||
+            _state == RX_SUCCESS ||
+            _state == IDLE) {
+            return true;
+        }
+        return false;
+    }
+
+    bool success(){
+        if(_state == TX_SUCCESS || _state == RX_SUCCESS) {
+            return true;
+        }
+        return false;
+    }
+
+
+} // end LoraTranport namespace
diff -r 000000000000 -r 518c8dac75f3 LoraTransport.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoraTransport.h	Thu Oct 13 09:40:21 2016 +0000
@@ -0,0 +1,86 @@
+#ifndef __LORA_TRANSPORT__
+#define __LORA_TRANSPORT__
+
+#include "sx1272-hal.h"
+
+#define RF_FREQUENCY                                868300000 // Hz
+#define TX_OUTPUT_POWER                             20        // 14 dBm
+#define RX_TIMEOUT_VALUE                            5000000   // in us
+#define TX_TIMEOUT_VALUE                            5000000   // in us
+#define LORA_BANDWIDTH                              0         // [0: 125 kHz, 1: 250 kHz, 2: 500 kHz, 3: Reserved]
+#define LORA_SPREADING_FACTOR                       9         // [SF7..SF12]
+#define LORA_CODINGRATE                             1         // [1: 4/5, 2: 4/6, 3: 4/7,  4: 4/8]
+#define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
+#define LORA_SYMBOL_TIMEOUT                         5         // Symbols
+#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
+#define LORA_FHSS_ENABLED                           false
+#define LORA_NB_SYMB_HOP                            4
+#define LORA_IQ_INVERSION_ON                        false
+#define LORA_CRC_ENABLED                            true
+
+#define MAX_PAYLOAD_SIZE 251
+
+namespace LoraTransport {
+
+    struct Packet {
+        uint16_t from_addr;
+        uint16_t to_addr;
+        uint8_t  packet_number;
+        uint8_t  payload[MAX_PAYLOAD_SIZE];
+        uint8_t  payload_size;
+    };
+
+    struct Ack {
+        uint16_t from_addr;
+        uint16_t to_addr;
+        uint8_t  packet_number;
+        uint8_t  success;
+    };
+
+    enum State {
+        IDLE,                   //0
+        // TX cycle
+        CAD_RUNNING,            //1
+        CAD_POSITIVE,           //2
+        CAD_NEGATIVE,           //3
+        TX_MSG,                 //4
+        TX_MSG_TIMEOUT,         //5
+        TX_MSG_DONE,            //6
+        RX_ACK,                 //7
+        RX_ACK_TIMEOUT,         //8
+        RX_ACK_ERROR,           //9
+        RX_ACK_DONE,            //10
+        TX_ERROR,               //11
+        TX_SUCCESS,             //12
+        // RX cycle
+        RX_MSG,                 //13
+        RX_MSG_TIMEOUT,         //14
+        RX_MSG_ERROR,           //15
+        RX_MSG_DONE,            //16
+        TX_ERROR_ACK,           //17
+        TX_ERROR_ACK_TIMEOUT,   //18
+        TX_ERROR_ACK_DONE,      //19
+        TX_SUCCESS_ACK,         //20
+        TX_SUCCESS_ACK_TIMEOUT, //21
+        TX_SUCCESS_ACK_DONE,    //22
+        RX_ERROR,               //23
+        RX_SUCCESS              //24
+
+    };
+
+    void init();
+    void send(uint16_t addr, uint8_t *ptr, uint8_t len, uint32_t timeout = 20000000 /*µs -> 20s*/);
+    void recv(uint32_t timeout = 20000000 /*µs -> 20s*/);
+    bool done();
+    bool success();
+
+    void setAddress(uint16_t addr);
+    State getState();
+    State getLastErrorState();
+    Packet& getPacket();
+    int16_t getRSSI();
+    int8_t getSNR();
+
+};
+
+#endif // __LORA_TRANSPORT__