Lora Transport Abstraction Layer for sx1272

Dependents:   lora-transceiver

Committer:
trusch
Date:
Thu Oct 13 09:40:21 2016 +0000
Revision:
0:518c8dac75f3
initial commit;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
trusch 0:518c8dac75f3 1 #include "LoraTransport.h"
trusch 0:518c8dac75f3 2 #include "mbed.h"
trusch 0:518c8dac75f3 3
trusch 0:518c8dac75f3 4 namespace LoraTransport {
trusch 0:518c8dac75f3 5
trusch 0:518c8dac75f3 6 namespace {
trusch 0:518c8dac75f3 7
trusch 0:518c8dac75f3 8 void onTxDone();
trusch 0:518c8dac75f3 9 void onTxTimeout();
trusch 0:518c8dac75f3 10 void onRxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr);
trusch 0:518c8dac75f3 11 void onRxTimeout();
trusch 0:518c8dac75f3 12 void onCadDone(bool);
trusch 0:518c8dac75f3 13 void onRxError();
trusch 0:518c8dac75f3 14
trusch 0:518c8dac75f3 15 XRange _radio(onTxDone, onTxTimeout, onRxDone, onRxTimeout, onRxError, NULL, onCadDone );
trusch 0:518c8dac75f3 16 mbed::Timer _timer;
trusch 0:518c8dac75f3 17 int _deadline;
trusch 0:518c8dac75f3 18 uint16_t _addr;
trusch 0:518c8dac75f3 19 int16_t _rssi_value;
trusch 0:518c8dac75f3 20 int8_t _snr_value;
trusch 0:518c8dac75f3 21 State _state;
trusch 0:518c8dac75f3 22 State _last_error_state;
trusch 0:518c8dac75f3 23 uint8_t _next_packet_number;
trusch 0:518c8dac75f3 24 Packet _packet;
trusch 0:518c8dac75f3 25 Ack _ack;
trusch 0:518c8dac75f3 26
trusch 0:518c8dac75f3 27 /*bool overNineThousand(int n){
trusch 0:518c8dac75f3 28 return n > 9000; // https://www.youtube.com/watch?v=LqSg9yVfzV0
trusch 0:518c8dac75f3 29 }*/
trusch 0:518c8dac75f3 30
trusch 0:518c8dac75f3 31 void onCadDone(bool activityDetected){
trusch 0:518c8dac75f3 32 _radio.Sleep();
trusch 0:518c8dac75f3 33 if(activityDetected){
trusch 0:518c8dac75f3 34 _radio.StartCad();
trusch 0:518c8dac75f3 35 }else{
trusch 0:518c8dac75f3 36 wait_ms((_radio.Random()%100)*10);
trusch 0:518c8dac75f3 37 if(_state == TX_MSG){
trusch 0:518c8dac75f3 38 _radio.Send((uint8_t*)&_packet, _packet.payload_size+5);
trusch 0:518c8dac75f3 39 }else if(_state == TX_SUCCESS_ACK || _state == TX_ERROR_ACK){
trusch 0:518c8dac75f3 40 _radio.Send((uint8_t*)&_ack, sizeof(_ack));
trusch 0:518c8dac75f3 41 }
trusch 0:518c8dac75f3 42 }
trusch 0:518c8dac75f3 43 }
trusch 0:518c8dac75f3 44
trusch 0:518c8dac75f3 45 void onTxTimeout(){
trusch 0:518c8dac75f3 46 _radio.Sleep();
trusch 0:518c8dac75f3 47 //printf("tx timeout\r\n");
trusch 0:518c8dac75f3 48 //printf("time on air for packet: %f\r\n",_radio.TimeOnAir(MODEM_LORA,_packet.payload_size+5));
trusch 0:518c8dac75f3 49 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 50 //printf("deadline reached, give up\r\n");
trusch 0:518c8dac75f3 51 _timer.stop();
trusch 0:518c8dac75f3 52 if(_state == TX_MSG){
trusch 0:518c8dac75f3 53 //printf("tx timeout while sending message\r\n");
trusch 0:518c8dac75f3 54 // timeout sending message
trusch 0:518c8dac75f3 55 _last_error_state = TX_MSG_TIMEOUT;
trusch 0:518c8dac75f3 56 _state = TX_ERROR;
trusch 0:518c8dac75f3 57 }else if(_state == TX_SUCCESS_ACK){
trusch 0:518c8dac75f3 58 //printf("tx timeout while sending success ack\r\n");
trusch 0:518c8dac75f3 59 // timeout sending success ack
trusch 0:518c8dac75f3 60 _last_error_state = TX_SUCCESS_ACK_TIMEOUT;
trusch 0:518c8dac75f3 61 _state = RX_ERROR;
trusch 0:518c8dac75f3 62 }else if(_state == TX_ERROR_ACK){
trusch 0:518c8dac75f3 63 //printf("tx timeout while sending error ack\r\n");
trusch 0:518c8dac75f3 64 // timeout sending error ack
trusch 0:518c8dac75f3 65 _last_error_state = TX_ERROR_ACK_TIMEOUT;
trusch 0:518c8dac75f3 66 _state = RX_ERROR;
trusch 0:518c8dac75f3 67 }
trusch 0:518c8dac75f3 68 }else{
trusch 0:518c8dac75f3 69 _radio.StartCad();
trusch 0:518c8dac75f3 70 }
trusch 0:518c8dac75f3 71 }
trusch 0:518c8dac75f3 72
trusch 0:518c8dac75f3 73 void onTxDone(){
trusch 0:518c8dac75f3 74 _radio.Sleep();
trusch 0:518c8dac75f3 75 if(_state == TX_MSG){
trusch 0:518c8dac75f3 76 // sending message ready, now wait for ack
trusch 0:518c8dac75f3 77 _state = RX_ACK;
trusch 0:518c8dac75f3 78 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 79 }else if(_state == TX_SUCCESS_ACK){
trusch 0:518c8dac75f3 80 // sending success ack ready -> success!
trusch 0:518c8dac75f3 81 _timer.stop();
trusch 0:518c8dac75f3 82 _state = RX_SUCCESS;
trusch 0:518c8dac75f3 83 }else if(_state == TX_ERROR_ACK){
trusch 0:518c8dac75f3 84 // sending error ack ready
trusch 0:518c8dac75f3 85 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 86 // no time for retry
trusch 0:518c8dac75f3 87 //printf("error ack transmitted, give up\r\n");
trusch 0:518c8dac75f3 88 _last_error_state = RX_MSG_ERROR;
trusch 0:518c8dac75f3 89 _timer.stop();
trusch 0:518c8dac75f3 90 _state = RX_ERROR;
trusch 0:518c8dac75f3 91 }else{
trusch 0:518c8dac75f3 92 // we have time for retry!
trusch 0:518c8dac75f3 93 //printf("error ack transmitted, retry\r\n");
trusch 0:518c8dac75f3 94 _state = RX_MSG;
trusch 0:518c8dac75f3 95 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 96 }
trusch 0:518c8dac75f3 97 }
trusch 0:518c8dac75f3 98 }
trusch 0:518c8dac75f3 99
trusch 0:518c8dac75f3 100 void onRxTimeout(){
trusch 0:518c8dac75f3 101 _radio.Sleep();
trusch 0:518c8dac75f3 102 if(_state == RX_MSG){
trusch 0:518c8dac75f3 103 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 104 // no time for retry
trusch 0:518c8dac75f3 105 //printf("rx msg timeout, give up\r\n");
trusch 0:518c8dac75f3 106 _timer.stop();
trusch 0:518c8dac75f3 107 _last_error_state = RX_MSG_TIMEOUT;
trusch 0:518c8dac75f3 108 _state = RX_ERROR;
trusch 0:518c8dac75f3 109 }else{
trusch 0:518c8dac75f3 110 // we have time for retry!
trusch 0:518c8dac75f3 111 //printf("rx msg timeout, retry\r\n");
trusch 0:518c8dac75f3 112 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 113 }
trusch 0:518c8dac75f3 114 }else if(_state == RX_ACK){
trusch 0:518c8dac75f3 115 // no ack received
trusch 0:518c8dac75f3 116 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 117 // no time for retry
trusch 0:518c8dac75f3 118 //printf("rx ack timeout, give up\r\n");
trusch 0:518c8dac75f3 119 _timer.stop();
trusch 0:518c8dac75f3 120 _last_error_state = RX_ACK_TIMEOUT;
trusch 0:518c8dac75f3 121 _state = TX_ERROR;
trusch 0:518c8dac75f3 122 }else{
trusch 0:518c8dac75f3 123 // we have time for retry!
trusch 0:518c8dac75f3 124 //printf("rx ack timeout, retry\r\n");
trusch 0:518c8dac75f3 125 _state = TX_MSG;
trusch 0:518c8dac75f3 126 _radio.StartCad();
trusch 0:518c8dac75f3 127 }
trusch 0:518c8dac75f3 128 }
trusch 0:518c8dac75f3 129 }
trusch 0:518c8dac75f3 130
trusch 0:518c8dac75f3 131 void onRxError(){
trusch 0:518c8dac75f3 132 _radio.Sleep();
trusch 0:518c8dac75f3 133 if(_state == RX_MSG){
trusch 0:518c8dac75f3 134 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 135 //printf("rx message error, give up\r\n");
trusch 0:518c8dac75f3 136 // no time for retry
trusch 0:518c8dac75f3 137 _timer.stop();
trusch 0:518c8dac75f3 138 _last_error_state = RX_MSG_ERROR;
trusch 0:518c8dac75f3 139 _state = RX_ERROR;
trusch 0:518c8dac75f3 140 }else{
trusch 0:518c8dac75f3 141 // we have time for retry -> send fail ack;
trusch 0:518c8dac75f3 142 //printf("rx message error, send fail ack\r\n");
trusch 0:518c8dac75f3 143 _ack.from_addr = _addr;
trusch 0:518c8dac75f3 144 _ack.to_addr = 0;
trusch 0:518c8dac75f3 145 _ack.success = false;
trusch 0:518c8dac75f3 146 _state = TX_ERROR_ACK;
trusch 0:518c8dac75f3 147 _radio.StartCad();
trusch 0:518c8dac75f3 148 }
trusch 0:518c8dac75f3 149 }else if(_state == RX_ACK){
trusch 0:518c8dac75f3 150 // no ack received
trusch 0:518c8dac75f3 151 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 152 // no time for retry
trusch 0:518c8dac75f3 153 //printf("rx ack error, give up\r\n");
trusch 0:518c8dac75f3 154 _timer.stop();
trusch 0:518c8dac75f3 155 _last_error_state = RX_ACK_TIMEOUT;
trusch 0:518c8dac75f3 156 _state = TX_ERROR;
trusch 0:518c8dac75f3 157 }else{
trusch 0:518c8dac75f3 158 // we have time for retry!
trusch 0:518c8dac75f3 159 //printf("rx ack error, retry\r\n");
trusch 0:518c8dac75f3 160 _state = TX_MSG;
trusch 0:518c8dac75f3 161 _radio.StartCad();
trusch 0:518c8dac75f3 162 }
trusch 0:518c8dac75f3 163 }
trusch 0:518c8dac75f3 164 }
trusch 0:518c8dac75f3 165
trusch 0:518c8dac75f3 166 void onRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ){
trusch 0:518c8dac75f3 167 _radio.Sleep();
trusch 0:518c8dac75f3 168 _rssi_value = rssi;
trusch 0:518c8dac75f3 169 _snr_value = snr;
trusch 0:518c8dac75f3 170 if(_state == RX_MSG){
trusch 0:518c8dac75f3 171 _packet.to_addr = *((uint16_t*)(payload+2));
trusch 0:518c8dac75f3 172 if(_packet.to_addr != _addr && _packet.to_addr != 0){
trusch 0:518c8dac75f3 173 //packet is not for us
trusch 0:518c8dac75f3 174 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 175 // no time for retry
trusch 0:518c8dac75f3 176 _timer.stop();
trusch 0:518c8dac75f3 177 _last_error_state = RX_MSG_TIMEOUT;
trusch 0:518c8dac75f3 178 _state = RX_ERROR;
trusch 0:518c8dac75f3 179 }else{
trusch 0:518c8dac75f3 180 //printf("packet is not for us, retry\r\n");
trusch 0:518c8dac75f3 181 _state = RX_MSG;
trusch 0:518c8dac75f3 182 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 183 }
trusch 0:518c8dac75f3 184 }else{
trusch 0:518c8dac75f3 185 //packet is for us
trusch 0:518c8dac75f3 186 _packet.from_addr = *((uint16_t*)(payload));
trusch 0:518c8dac75f3 187 _packet.packet_number = *(payload+4);
trusch 0:518c8dac75f3 188 _packet.payload_size = size-5;
trusch 0:518c8dac75f3 189 memcpy(_packet.payload, payload+5, _packet.payload_size);
trusch 0:518c8dac75f3 190 _ack.packet_number = _packet.packet_number;
trusch 0:518c8dac75f3 191 _ack.from_addr = _packet.to_addr;
trusch 0:518c8dac75f3 192 _ack.to_addr = _packet.from_addr;
trusch 0:518c8dac75f3 193 _ack.success = true;
trusch 0:518c8dac75f3 194 _state = TX_SUCCESS_ACK;
trusch 0:518c8dac75f3 195 _radio.StartCad();
trusch 0:518c8dac75f3 196 }
trusch 0:518c8dac75f3 197 }else if(_state == RX_ACK){
trusch 0:518c8dac75f3 198 _ack.to_addr = *((uint16_t*)(payload+2));
trusch 0:518c8dac75f3 199 if(_ack.to_addr != _addr && _ack.to_addr != 0){
trusch 0:518c8dac75f3 200 //ack is not for us
trusch 0:518c8dac75f3 201 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 202 //printf("ack is not for us, give up\r\n");
trusch 0:518c8dac75f3 203 // no time for retry
trusch 0:518c8dac75f3 204 _timer.stop();
trusch 0:518c8dac75f3 205 _last_error_state = RX_ACK_TIMEOUT;
trusch 0:518c8dac75f3 206 _state = TX_ERROR;
trusch 0:518c8dac75f3 207 }else{
trusch 0:518c8dac75f3 208 //printf("ack is not for us, retry\r\n");
trusch 0:518c8dac75f3 209 _state = RX_ACK;
trusch 0:518c8dac75f3 210 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 211 }
trusch 0:518c8dac75f3 212 }else{
trusch 0:518c8dac75f3 213 //ack is for us
trusch 0:518c8dac75f3 214 _ack.from_addr = *((uint16_t*)payload);
trusch 0:518c8dac75f3 215 _ack.packet_number = *(payload+4);
trusch 0:518c8dac75f3 216 _ack.success = *(payload+5);
trusch 0:518c8dac75f3 217 if(_ack.success == true && _ack.packet_number == _packet.packet_number){
trusch 0:518c8dac75f3 218 // got success ack -> transmission completed!
trusch 0:518c8dac75f3 219 _timer.stop();
trusch 0:518c8dac75f3 220 _state = TX_SUCCESS;
trusch 0:518c8dac75f3 221 }else{
trusch 0:518c8dac75f3 222 if(_timer.read_us() > _deadline){
trusch 0:518c8dac75f3 223 // no time for retry
trusch 0:518c8dac75f3 224 //printf("got fail ack, give up\r\n");
trusch 0:518c8dac75f3 225 _timer.stop();
trusch 0:518c8dac75f3 226 _last_error_state = TX_MSG_TIMEOUT;
trusch 0:518c8dac75f3 227 _state = TX_ERROR;
trusch 0:518c8dac75f3 228 }else{
trusch 0:518c8dac75f3 229 //retry
trusch 0:518c8dac75f3 230 //printf("got fail ack, retry\r\n");
trusch 0:518c8dac75f3 231 _state = TX_MSG;
trusch 0:518c8dac75f3 232 _radio.StartCad();
trusch 0:518c8dac75f3 233 }
trusch 0:518c8dac75f3 234 }
trusch 0:518c8dac75f3 235 }
trusch 0:518c8dac75f3 236 }
trusch 0:518c8dac75f3 237 }
trusch 0:518c8dac75f3 238
trusch 0:518c8dac75f3 239 }//end anonym namespace
trusch 0:518c8dac75f3 240
trusch 0:518c8dac75f3 241
trusch 0:518c8dac75f3 242 void init(){
trusch 0:518c8dac75f3 243 _addr = 0;
trusch 0:518c8dac75f3 244 _rssi_value = 0;
trusch 0:518c8dac75f3 245 _snr_value = 0;
trusch 0:518c8dac75f3 246 _state = IDLE;
trusch 0:518c8dac75f3 247 _last_error_state = IDLE;
trusch 0:518c8dac75f3 248 _next_packet_number = 0;
trusch 0:518c8dac75f3 249 _radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
trusch 0:518c8dac75f3 250 LORA_SPREADING_FACTOR, LORA_CODINGRATE,
trusch 0:518c8dac75f3 251 LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
trusch 0:518c8dac75f3 252 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
trusch 0:518c8dac75f3 253 LORA_IQ_INVERSION_ON, TX_TIMEOUT_VALUE );
trusch 0:518c8dac75f3 254 _radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
trusch 0:518c8dac75f3 255 LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
trusch 0:518c8dac75f3 256 LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0,
trusch 0:518c8dac75f3 257 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
trusch 0:518c8dac75f3 258 LORA_IQ_INVERSION_ON, true );
trusch 0:518c8dac75f3 259 }
trusch 0:518c8dac75f3 260
trusch 0:518c8dac75f3 261 void setAddress(uint16_t addr){
trusch 0:518c8dac75f3 262 _addr = addr;
trusch 0:518c8dac75f3 263 }
trusch 0:518c8dac75f3 264
trusch 0:518c8dac75f3 265 void send(uint16_t addr, uint8_t *ptr, uint8_t len, uint32_t timeout){
trusch 0:518c8dac75f3 266 _packet.from_addr = _addr;
trusch 0:518c8dac75f3 267 _packet.to_addr = addr;
trusch 0:518c8dac75f3 268 _packet.packet_number = _next_packet_number++;
trusch 0:518c8dac75f3 269 memcpy(_packet.payload, ptr, len);
trusch 0:518c8dac75f3 270 _packet.payload_size = len;
trusch 0:518c8dac75f3 271 _state = CAD_RUNNING;
trusch 0:518c8dac75f3 272 _deadline = timeout;
trusch 0:518c8dac75f3 273 _timer.stop();
trusch 0:518c8dac75f3 274 _timer.reset();
trusch 0:518c8dac75f3 275 _timer.start();
trusch 0:518c8dac75f3 276 _state = TX_MSG;
trusch 0:518c8dac75f3 277 //printf("send message with %i bytes\r\n",len);
trusch 0:518c8dac75f3 278 _radio.StartCad();
trusch 0:518c8dac75f3 279 }
trusch 0:518c8dac75f3 280
trusch 0:518c8dac75f3 281 void recv(uint32_t timeout){
trusch 0:518c8dac75f3 282 _state = RX_MSG;
trusch 0:518c8dac75f3 283 _deadline = timeout;
trusch 0:518c8dac75f3 284 _timer.stop();
trusch 0:518c8dac75f3 285 _timer.reset();
trusch 0:518c8dac75f3 286 _timer.start();
trusch 0:518c8dac75f3 287 _state = RX_MSG;
trusch 0:518c8dac75f3 288 _radio.Rx(RX_TIMEOUT_VALUE);
trusch 0:518c8dac75f3 289 }
trusch 0:518c8dac75f3 290
trusch 0:518c8dac75f3 291 State getState(){
trusch 0:518c8dac75f3 292 return _state;
trusch 0:518c8dac75f3 293 }
trusch 0:518c8dac75f3 294 State getLastErrorState(){
trusch 0:518c8dac75f3 295 return _last_error_state;
trusch 0:518c8dac75f3 296 }
trusch 0:518c8dac75f3 297 Packet& getPacket(){
trusch 0:518c8dac75f3 298 return _packet;
trusch 0:518c8dac75f3 299 }
trusch 0:518c8dac75f3 300 int16_t getRSSI(){
trusch 0:518c8dac75f3 301 return _rssi_value;
trusch 0:518c8dac75f3 302 }
trusch 0:518c8dac75f3 303 int8_t getSNR(){
trusch 0:518c8dac75f3 304 return _snr_value;
trusch 0:518c8dac75f3 305 }
trusch 0:518c8dac75f3 306
trusch 0:518c8dac75f3 307 bool done(){
trusch 0:518c8dac75f3 308 if( _state == TX_ERROR ||
trusch 0:518c8dac75f3 309 _state == TX_SUCCESS ||
trusch 0:518c8dac75f3 310 _state == RX_ERROR ||
trusch 0:518c8dac75f3 311 _state == RX_SUCCESS ||
trusch 0:518c8dac75f3 312 _state == IDLE) {
trusch 0:518c8dac75f3 313 return true;
trusch 0:518c8dac75f3 314 }
trusch 0:518c8dac75f3 315 return false;
trusch 0:518c8dac75f3 316 }
trusch 0:518c8dac75f3 317
trusch 0:518c8dac75f3 318 bool success(){
trusch 0:518c8dac75f3 319 if(_state == TX_SUCCESS || _state == RX_SUCCESS) {
trusch 0:518c8dac75f3 320 return true;
trusch 0:518c8dac75f3 321 }
trusch 0:518c8dac75f3 322 return false;
trusch 0:518c8dac75f3 323 }
trusch 0:518c8dac75f3 324
trusch 0:518c8dac75f3 325
trusch 0:518c8dac75f3 326 } // end LoraTranport namespace