Lora Transport Abstraction Layer for sx1272
LoraTransport.cpp
- Committer:
- trusch
- Date:
- 2016-10-13
- Revision:
- 0:518c8dac75f3
File content as of revision 0:518c8dac75f3:
#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