Lora Transport Abstraction Layer for sx1272
Revision 0:518c8dac75f3, committed 2016-10-13
- 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__