Lora Transport Abstraction Layer for sx1272

Dependents:   lora-transceiver

Revision:
0:518c8dac75f3
--- /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