Basic MAC data interface for LoRa transceiver

Dependencies:   L2Frame crc

Dependents:   LoRaBaseStation LoRaTerminal

Committer:
rba90
Date:
Wed Sep 14 07:47:18 2016 +0000
Revision:
39:0da3ee6a297d
Parent:
38:e7b679acf524
Child:
40:271fa9e98589
add CSMA/CA routine

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rba90 0:e2ccabf3f30c 1 #include "AlohaTransceiver.h"
rba90 0:e2ccabf3f30c 2 #include "mbed.h"
rba90 0:e2ccabf3f30c 3 #include "radio.h"
rba90 18:3e6483550f25 4 #include "debug.h"
rba90 0:e2ccabf3f30c 5 #include "AlohaFrame.h"
rba90 15:0dc9df48687a 6 #include "RingBuffer.h"
rba90 0:e2ccabf3f30c 7
rba90 38:e7b679acf524 8 #define ALLOW_CALLBACK_DEBUG 1
rba90 39:0da3ee6a297d 9 #define CSMA_CA_BACKOFF_TIME 1000 // in ms
rba90 39:0da3ee6a297d 10 #define CSMA_CA_CHANNEL_THRESHOLD -80 // in dbm
rba90 18:3e6483550f25 11
rba90 28:2c0e115b4f72 12 #define SET_FLAG(t, x) (t) |= 1 << (x)
rba90 28:2c0e115b4f72 13 #define CLEAR_FLAG(t, x) (t) &= ~(1 << (x))
rba90 28:2c0e115b4f72 14 #define TOGGLE_FLAG(t, x) (t) ^= 1 << (x)
rba90 28:2c0e115b4f72 15 #define CHECK_FLAG(t, x) (t) >> (x) & 1
rba90 27:463688e3bd12 16
rba90 36:09c105fe77c0 17
rba90 0:e2ccabf3f30c 18 // declear the type of radio state
rba90 0:e2ccabf3f30c 19 typedef enum
rba90 0:e2ccabf3f30c 20 {
rba90 0:e2ccabf3f30c 21 LOWPOWER = 0,
rba90 0:e2ccabf3f30c 22 IDLE,
rba90 0:e2ccabf3f30c 23
rba90 0:e2ccabf3f30c 24 RX,
rba90 0:e2ccabf3f30c 25 RX_TIMEOUT,
rba90 0:e2ccabf3f30c 26 RX_ERROR,
rba90 0:e2ccabf3f30c 27
rba90 0:e2ccabf3f30c 28 TX,
rba90 0:e2ccabf3f30c 29 TX_TIMEOUT,
rba90 0:e2ccabf3f30c 30
rba90 0:e2ccabf3f30c 31 CAD,
rba90 0:e2ccabf3f30c 32 CAD_DONE
rba90 0:e2ccabf3f30c 33 }AppStates_t;
rba90 0:e2ccabf3f30c 34
rba90 0:e2ccabf3f30c 35 // radio driver related variables
rba90 0:e2ccabf3f30c 36 static int16_t RssiValue;
rba90 0:e2ccabf3f30c 37 static int8_t SnrValue;
rba90 0:e2ccabf3f30c 38
rba90 0:e2ccabf3f30c 39 static volatile AppStates_t State;
rba90 0:e2ccabf3f30c 40 static RadioEvents_t RadioEvents;
rba90 0:e2ccabf3f30c 41
rba90 27:463688e3bd12 42 // rx queue
rba90 27:463688e3bd12 43 CircularBuffer<AlohaFrame *> AlohaRxQueue(10);
rba90 17:c6e2e2cd6e5f 44
rba90 0:e2ccabf3f30c 45 // callback functions for radio driver
rba90 0:e2ccabf3f30c 46 void OnTxDone();
rba90 0:e2ccabf3f30c 47 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
rba90 0:e2ccabf3f30c 48 void OnTxTimeout();
rba90 0:e2ccabf3f30c 49 void OnRxTimeout();
rba90 0:e2ccabf3f30c 50 void OnRxError();
rba90 0:e2ccabf3f30c 51 void OnFhssChangeChannel( uint8_t channelIndex );
rba90 0:e2ccabf3f30c 52 void OnCadDone();
rba90 0:e2ccabf3f30c 53
rba90 0:e2ccabf3f30c 54 // radio driver
rba90 20:bd26d3cbc0bd 55 #ifdef DRIVER_SX1276
rba90 0:e2ccabf3f30c 56 SX1276MB1xAS Radio( NULL );
rba90 0:e2ccabf3f30c 57 #endif
rba90 0:e2ccabf3f30c 58
rba90 20:bd26d3cbc0bd 59 #ifdef DRIVER_INAIR
rba90 0:e2ccabf3f30c 60 SX1276inAir Radio( NULL );
rba90 0:e2ccabf3f30c 61 #endif
rba90 0:e2ccabf3f30c 62
rba90 0:e2ccabf3f30c 63
rba90 36:09c105fe77c0 64
rba90 0:e2ccabf3f30c 65 /*
rba90 0:e2ccabf3f30c 66 * Abstract interface for accessing radio driver
rba90 0:e2ccabf3f30c 67 */
rba90 27:463688e3bd12 68 AlohaTransceiver::AlohaTransceiver(uint8_t id):
rba90 31:a0454fda1538 69 AlohaTxQueue(32)
rba90 0:e2ccabf3f30c 70 {
rba90 11:3e1ff29da71a 71 // store unique device id
rba90 11:3e1ff29da71a 72 deviceId = id;
rba90 11:3e1ff29da71a 73
rba90 17:c6e2e2cd6e5f 74 // initialize sequenceid
rba90 17:c6e2e2cd6e5f 75 memset(seqid, 0x0, sizeof(seqid));
rba90 17:c6e2e2cd6e5f 76
rba90 31:a0454fda1538 77 // clear tx done state
rba90 31:a0454fda1538 78 isTxDone = true;
rba90 31:a0454fda1538 79
rba90 31:a0454fda1538 80 // assume all station is clear to transmit
rba90 31:a0454fda1538 81 isAcked = 0xffff;
rba90 28:2c0e115b4f72 82
rba90 39:0da3ee6a297d 83 // reset CSMA backoff timer
rba90 39:0da3ee6a297d 84 CSMABackoffTimer.reset();
rba90 39:0da3ee6a297d 85
rba90 39:0da3ee6a297d 86 // reset CSMA backoff state
rba90 39:0da3ee6a297d 87 isBackoff = false;
rba90 39:0da3ee6a297d 88
rba90 36:09c105fe77c0 89
rba90 0:e2ccabf3f30c 90 // configure properties
rba90 0:e2ccabf3f30c 91 #if USE_MODEM_LORA == 1
rba90 0:e2ccabf3f30c 92 Settings.Power = TX_OUTPUT_POWER;
rba90 0:e2ccabf3f30c 93 Settings.Bandwidth = LORA_BANDWIDTH;
rba90 0:e2ccabf3f30c 94 Settings.Datarate = LORA_SPREADING_FACTOR;
rba90 0:e2ccabf3f30c 95 Settings.Coderate = LORA_CODINGRATE;
rba90 0:e2ccabf3f30c 96 Settings.PreambleLen = LORA_PREAMBLE_LENGTH;
rba90 0:e2ccabf3f30c 97 Settings.SymbolTimeout = LORA_SYMBOL_TIMEOUT;
rba90 0:e2ccabf3f30c 98 Settings.FixLen = LORA_FIX_LENGTH_PAYLOAD_ON;
rba90 0:e2ccabf3f30c 99 Settings.PayloadLen = 0;
rba90 0:e2ccabf3f30c 100 Settings.CrcOn = LORA_CRC_ENABLED;
rba90 0:e2ccabf3f30c 101 Settings.FreqHopOn = LORA_FHSS_ENABLED;
rba90 0:e2ccabf3f30c 102 Settings.HopPeriod = LORA_NB_SYMB_HOP;
rba90 0:e2ccabf3f30c 103 Settings.IqInverted = LORA_IQ_INVERSION_ON;
rba90 0:e2ccabf3f30c 104 Settings.RxContinuous = true;
rba90 0:e2ccabf3f30c 105 Settings.TxTimeout = TX_TIMEOUT_VALUE;
rba90 0:e2ccabf3f30c 106
rba90 0:e2ccabf3f30c 107 #elif USE_MODEM_FSK == 1
rba90 0:e2ccabf3f30c 108 // TODO: Complete settings for FSK mode
rba90 0:e2ccabf3f30c 109 #error "FSK not implemented"
rba90 0:e2ccabf3f30c 110 #else
rba90 0:e2ccabf3f30c 111 #error "Please define a modem in the compiler options."
rba90 0:e2ccabf3f30c 112 #endif
rba90 0:e2ccabf3f30c 113 }
rba90 0:e2ccabf3f30c 114
rba90 0:e2ccabf3f30c 115 AlohaTransceiver::~AlohaTransceiver()
rba90 0:e2ccabf3f30c 116 {
rba90 0:e2ccabf3f30c 117
rba90 0:e2ccabf3f30c 118 }
rba90 0:e2ccabf3f30c 119
rba90 6:f545f5aa7de3 120 void AlohaTransceiver::boardInit()
rba90 0:e2ccabf3f30c 121 {
rba90 0:e2ccabf3f30c 122 // configure callback functions
rba90 0:e2ccabf3f30c 123 RadioEvents.TxDone = OnTxDone;
rba90 0:e2ccabf3f30c 124 RadioEvents.RxDone = OnRxDone;
rba90 0:e2ccabf3f30c 125 RadioEvents.RxError = OnRxError;
rba90 0:e2ccabf3f30c 126 RadioEvents.TxTimeout = OnTxTimeout;
rba90 0:e2ccabf3f30c 127 RadioEvents.RxTimeout = OnRxTimeout;
rba90 0:e2ccabf3f30c 128 Radio.Init( &RadioEvents );
rba90 0:e2ccabf3f30c 129
rba90 0:e2ccabf3f30c 130 // verify the connection with the board
rba90 0:e2ccabf3f30c 131 while( Radio.Read( REG_VERSION ) == 0x00 )
rba90 0:e2ccabf3f30c 132 {
rba90 18:3e6483550f25 133 #ifdef DEBUG_ALOHA
rba90 18:3e6483550f25 134 debug( "Radio could not be detected!\n\r" );
rba90 18:3e6483550f25 135 #endif
rba90 0:e2ccabf3f30c 136 wait( 1 );
rba90 0:e2ccabf3f30c 137 }
rba90 18:3e6483550f25 138 #ifdef DEBUG_ALOHA
rba90 0:e2ccabf3f30c 139 printf("RadioRegVersion: %d\r\n", Radio.Read( REG_VERSION ));
rba90 18:3e6483550f25 140 #endif
rba90 0:e2ccabf3f30c 141 }
rba90 0:e2ccabf3f30c 142
rba90 0:e2ccabf3f30c 143 void AlohaTransceiver::updateSettings()
rba90 0:e2ccabf3f30c 144 {
rba90 6:f545f5aa7de3 145 Radio.SetChannel( RF_FREQUENCY );
rba90 0:e2ccabf3f30c 146 #if USE_MODEM_LORA == 1
rba90 0:e2ccabf3f30c 147
rba90 0:e2ccabf3f30c 148 Radio.SetTxConfig( MODEM_LORA, Settings.Power, 0, Settings.Bandwidth,
rba90 0:e2ccabf3f30c 149 Settings.Datarate, Settings.Coderate,
rba90 0:e2ccabf3f30c 150 Settings.PreambleLen, Settings.FixLen,
rba90 0:e2ccabf3f30c 151 Settings.CrcOn, Settings.FreqHopOn, Settings.HopPeriod,
rba90 0:e2ccabf3f30c 152 Settings.IqInverted, Settings.TxTimeout );
rba90 0:e2ccabf3f30c 153
rba90 0:e2ccabf3f30c 154 Radio.SetRxConfig( MODEM_LORA, Settings.Bandwidth, Settings.Datarate,
rba90 0:e2ccabf3f30c 155 Settings.Coderate, 0, Settings.PreambleLen,
rba90 0:e2ccabf3f30c 156 Settings.SymbolTimeout, Settings.FixLen, Settings.PayloadLen,
rba90 0:e2ccabf3f30c 157 Settings.CrcOn, Settings.FreqHopOn, Settings.HopPeriod,
rba90 0:e2ccabf3f30c 158 Settings.IqInverted, Settings.RxContinuous );
rba90 0:e2ccabf3f30c 159
rba90 0:e2ccabf3f30c 160 #elif USE_MODEM_FSK == 1
rba90 0:e2ccabf3f30c 161 #error "FSK not implemented"
rba90 0:e2ccabf3f30c 162 #else
rba90 0:e2ccabf3f30c 163 #error "Please define a modem in the compiler options."
rba90 0:e2ccabf3f30c 164 #endif
rba90 0:e2ccabf3f30c 165 }
rba90 0:e2ccabf3f30c 166
rba90 6:f545f5aa7de3 167 void AlohaTransceiver::enable()
rba90 6:f545f5aa7de3 168 {
rba90 6:f545f5aa7de3 169 // entering passive receiver mode
rba90 10:065a4b58c6ff 170 Radio.Rx( 0 );
rba90 6:f545f5aa7de3 171 }
rba90 6:f545f5aa7de3 172
rba90 0:e2ccabf3f30c 173 void AlohaTransceiver::poll()
rba90 0:e2ccabf3f30c 174 {
rba90 0:e2ccabf3f30c 175 switch( State )
rba90 0:e2ccabf3f30c 176 {
rba90 0:e2ccabf3f30c 177 case RX:
rba90 5:c3741633dc6f 178 {
rba90 27:463688e3bd12 179 // process packet if received
rba90 30:bccad60351ac 180 // it is noticed that the rx handler does not queue the received packet
rba90 30:bccad60351ac 181 // due to the hardware limitation
rba90 27:463688e3bd12 182 while (AlohaRxQueue.getCounter() > 0)
rba90 25:bcd1cee4e5a8 183 {
rba90 27:463688e3bd12 184 // pop from queue
rba90 27:463688e3bd12 185 AlohaFrame *frame = AlohaRxQueue.dequeue();
rba90 27:463688e3bd12 186
rba90 27:463688e3bd12 187 // check destination
rba90 27:463688e3bd12 188 // if the destination is the device id, then processing, otherwise drop the packet and continue
rba90 27:463688e3bd12 189 // listening
rba90 27:463688e3bd12 190 if (frame->getDestinationAddress() == (deviceId & 0x0f))
rba90 26:e87c8d345644 191 {
rba90 27:463688e3bd12 192 uint8_t type = frame->getType();
rba90 27:463688e3bd12 193
rba90 27:463688e3bd12 194 // schedule the ack frame immediatly after the data frame is received
rba90 27:463688e3bd12 195 if (type == AlohaFrame::Aloha_Data)
rba90 29:6c59b0bba861 196 {
rba90 29:6c59b0bba861 197 #ifdef DEBUG_ALOHA
rba90 29:6c59b0bba861 198 printf("\r\nRXDATA::SRC_ADDR:0x%x,SEQID:0x%x\r\n", frame->getSourceAddress(), frame->getSequenceID());
rba90 29:6c59b0bba861 199 #endif
rba90 27:463688e3bd12 200 sendAck(frame);
rba90 27:463688e3bd12 201 }
rba90 27:463688e3bd12 202 else if (type == AlohaFrame::Aloha_ACK)
rba90 27:463688e3bd12 203 {
rba90 26:e87c8d345644 204 #ifdef DEBUG_ALOHA
rba90 29:6c59b0bba861 205 printf("\r\nRXACK::SRC_ADDR:0x%x,SEQID:0x%x\r\n", frame->getSourceAddress(), frame->getSequenceID());
rba90 26:e87c8d345644 206 #endif
rba90 31:a0454fda1538 207 // clear the ack state
rba90 31:a0454fda1538 208 uint8_t src_addr = frame->getSourceAddress();
rba90 31:a0454fda1538 209 uint8_t foreign_seqid = frame->getSequenceID();
rba90 31:a0454fda1538 210
rba90 31:a0454fda1538 211 // compare the local sequence id and foreign sequence id for specific host
rba90 36:09c105fe77c0 212 if (seqid[src_addr] <= foreign_seqid)
rba90 31:a0454fda1538 213 {
rba90 31:a0454fda1538 214 setAckedFlag(src_addr);
rba90 31:a0454fda1538 215 }
rba90 37:9e895f3ffd41 216 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 217 printf("ACK::frame_seqid: %d, local_seqid: %d\r\n", frame->getSequenceID(), seqid[frame->getSourceAddress()]);
rba90 37:9e895f3ffd41 218 #endif
rba90 27:463688e3bd12 219 }
rba90 27:463688e3bd12 220
rba90 27:463688e3bd12 221 // check registered callback function
rba90 27:463688e3bd12 222 // execute callback functions if registered
rba90 27:463688e3bd12 223 if (AlohaTypeCallbackTable[type] != NULL)
rba90 27:463688e3bd12 224 {
rba90 27:463688e3bd12 225 uint8_t payload_length = frame->getPayloadLength();
rba90 27:463688e3bd12 226 uint8_t payload[payload_length];
rba90 27:463688e3bd12 227 uint8_t src_addr = frame->getSourceAddress();
rba90 27:463688e3bd12 228
rba90 27:463688e3bd12 229 // extract payload
rba90 27:463688e3bd12 230 for (uint8_t i = 0; i < payload_length; i++)
rba90 27:463688e3bd12 231 {
rba90 27:463688e3bd12 232 payload[i] = frame->getPayload(i);
rba90 27:463688e3bd12 233 }
rba90 27:463688e3bd12 234
rba90 27:463688e3bd12 235 // execute callback function
rba90 27:463688e3bd12 236 AlohaTypeCallbackTable[type](payload, payload_length, src_addr);
rba90 27:463688e3bd12 237 }
rba90 26:e87c8d345644 238 }
rba90 17:c6e2e2cd6e5f 239
rba90 27:463688e3bd12 240 // free memory
rba90 27:463688e3bd12 241 delete frame;
rba90 0:e2ccabf3f30c 242 }
rba90 0:e2ccabf3f30c 243
rba90 10:065a4b58c6ff 244 Radio.Rx( 0 );
rba90 0:e2ccabf3f30c 245 State = LOWPOWER;
rba90 0:e2ccabf3f30c 246 break;
rba90 0:e2ccabf3f30c 247 }
rba90 0:e2ccabf3f30c 248 case TX:
rba90 0:e2ccabf3f30c 249 {
rba90 28:2c0e115b4f72 250 // set tx to done, allow next transmission
rba90 28:2c0e115b4f72 251 setTxDoneFlag();
rba90 28:2c0e115b4f72 252
rba90 10:065a4b58c6ff 253 Radio.Rx( 0 );
rba90 0:e2ccabf3f30c 254 State = LOWPOWER;
rba90 0:e2ccabf3f30c 255 break;
rba90 0:e2ccabf3f30c 256 }
rba90 0:e2ccabf3f30c 257 case RX_TIMEOUT:
rba90 0:e2ccabf3f30c 258 {
rba90 10:065a4b58c6ff 259 Radio.Rx( 0 );
rba90 0:e2ccabf3f30c 260 State = LOWPOWER;
rba90 0:e2ccabf3f30c 261 break;
rba90 0:e2ccabf3f30c 262 }
rba90 0:e2ccabf3f30c 263 case RX_ERROR:
rba90 0:e2ccabf3f30c 264 {
rba90 10:065a4b58c6ff 265 Radio.Rx( 0 );
rba90 0:e2ccabf3f30c 266 State = LOWPOWER;
rba90 0:e2ccabf3f30c 267 break;
rba90 0:e2ccabf3f30c 268 }
rba90 0:e2ccabf3f30c 269 case TX_TIMEOUT:
rba90 0:e2ccabf3f30c 270 {
rba90 29:6c59b0bba861 271 // set tx to done, allow next transmission
rba90 29:6c59b0bba861 272 setTxDoneFlag();
rba90 29:6c59b0bba861 273
rba90 10:065a4b58c6ff 274 Radio.Rx( 0 );
rba90 0:e2ccabf3f30c 275 State = LOWPOWER;
rba90 0:e2ccabf3f30c 276 break;
rba90 0:e2ccabf3f30c 277 }
rba90 0:e2ccabf3f30c 278 case LOWPOWER:
rba90 0:e2ccabf3f30c 279 {
rba90 22:2e39f382f782 280 // transmit packet when the radio is free
rba90 31:a0454fda1538 281 if (getTxDoneFlag())
rba90 22:2e39f382f782 282 {
rba90 31:a0454fda1538 283 // find next available packet to transmit
rba90 39:0da3ee6a297d 284 while( AlohaTxQueue.getCounter() > 0)
rba90 31:a0454fda1538 285 {
rba90 39:0da3ee6a297d 286 // perform CSMA backoff routine
rba90 39:0da3ee6a297d 287 if (isBackoff == true) // if the transceiver is already in the backoff state, then wait until timer expires
rba90 31:a0454fda1538 288 {
rba90 39:0da3ee6a297d 289 if (CSMABackoffTimer.read_ms() > CSMA_CA_BACKOFF_TIME)
rba90 39:0da3ee6a297d 290 {
rba90 39:0da3ee6a297d 291 isBackoff = false;
rba90 39:0da3ee6a297d 292 CSMABackoffTimer.stop();
rba90 39:0da3ee6a297d 293 }
rba90 39:0da3ee6a297d 294 }
rba90 39:0da3ee6a297d 295
rba90 39:0da3ee6a297d 296
rba90 39:0da3ee6a297d 297 if (isBackoff == false) // if the transceiver is not in backoff state, then attempt to transmit
rba90 39:0da3ee6a297d 298 {
rba90 39:0da3ee6a297d 299 if (Radio.IsChannelFree(MODEM_LORA, RF_FREQUENCY, CSMA_CA_CHANNEL_THRESHOLD))
rba90 31:a0454fda1538 300 {
rba90 39:0da3ee6a297d 301 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 302 printf(" CSMA/CA::Channel is free, ready to transmit\r\n");
rba90 39:0da3ee6a297d 303 #endif
rba90 39:0da3ee6a297d 304 AlohaFrame *frame = AlohaTxQueue.dequeue();
rba90 39:0da3ee6a297d 305
rba90 39:0da3ee6a297d 306 // determined by the type of the frame, only data frame need to be cleared before transmitting
rba90 39:0da3ee6a297d 307 switch (frame->getType())
rba90 31:a0454fda1538 308 {
rba90 39:0da3ee6a297d 309 // Data frame need proper clearance
rba90 39:0da3ee6a297d 310 case AlohaFrame::Aloha_Data:
rba90 39:0da3ee6a297d 311 {
rba90 39:0da3ee6a297d 312 uint8_t dest_addr = frame->getDestinationAddress();
rba90 39:0da3ee6a297d 313
rba90 39:0da3ee6a297d 314 // depending on the availability of the destination host,
rba90 39:0da3ee6a297d 315 // the radio will on transmit the packet when acked.
rba90 39:0da3ee6a297d 316 //
rba90 39:0da3ee6a297d 317 // in the test build, we are not going to enable this feature
rba90 39:0da3ee6a297d 318 // if (getAckedFlag(dest_addr))
rba90 39:0da3ee6a297d 319 if (true)
rba90 39:0da3ee6a297d 320 {
rba90 39:0da3ee6a297d 321 sendFrame(frame);
rba90 39:0da3ee6a297d 322
rba90 39:0da3ee6a297d 323 // block the next transmission until previous transmission is done
rba90 39:0da3ee6a297d 324 clearTxDoneFlag();
rba90 39:0da3ee6a297d 325
rba90 39:0da3ee6a297d 326 // block the next transmission of the same host until an acked packet
rba90 39:0da3ee6a297d 327 // is received
rba90 39:0da3ee6a297d 328 clearAckedFlag(dest_addr);
rba90 39:0da3ee6a297d 329
rba90 39:0da3ee6a297d 330 // free memory
rba90 39:0da3ee6a297d 331 delete frame;
rba90 39:0da3ee6a297d 332 }
rba90 39:0da3ee6a297d 333
rba90 39:0da3ee6a297d 334 // otherwise put the packet back to the end of queue and wait for its being acked
rba90 39:0da3ee6a297d 335 else
rba90 39:0da3ee6a297d 336 {
rba90 39:0da3ee6a297d 337 AlohaTxQueue.enqueue(frame);
rba90 39:0da3ee6a297d 338 }
rba90 39:0da3ee6a297d 339 break;
rba90 39:0da3ee6a297d 340 }
rba90 31:a0454fda1538 341
rba90 39:0da3ee6a297d 342 default:
rba90 39:0da3ee6a297d 343 {
rba90 39:0da3ee6a297d 344 sendFrame(frame);
rba90 39:0da3ee6a297d 345
rba90 39:0da3ee6a297d 346 // block the next transmission until previous transmission is done
rba90 39:0da3ee6a297d 347 clearTxDoneFlag();
rba90 39:0da3ee6a297d 348
rba90 39:0da3ee6a297d 349 // free memory
rba90 39:0da3ee6a297d 350 delete frame;
rba90 39:0da3ee6a297d 351
rba90 39:0da3ee6a297d 352 break;
rba90 39:0da3ee6a297d 353 }
rba90 31:a0454fda1538 354 }
rba90 31:a0454fda1538 355 }
rba90 39:0da3ee6a297d 356 else // if channel if not free, then start the timer, set the backoff state to true
rba90 33:810074d10fcf 357 {
rba90 39:0da3ee6a297d 358 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 359 printf("CSMA/CA::Channel is not free, wait for 1s\r\n");
rba90 39:0da3ee6a297d 360 #endif
rba90 39:0da3ee6a297d 361 isBackoff = true;
rba90 39:0da3ee6a297d 362 CSMABackoffTimer.reset();
rba90 39:0da3ee6a297d 363 CSMABackoffTimer.start();
rba90 33:810074d10fcf 364 }
rba90 31:a0454fda1538 365 }
rba90 31:a0454fda1538 366 }
rba90 22:2e39f382f782 367 }
rba90 0:e2ccabf3f30c 368 break;
rba90 0:e2ccabf3f30c 369 }
rba90 0:e2ccabf3f30c 370 default:
rba90 0:e2ccabf3f30c 371 {
rba90 0:e2ccabf3f30c 372 State = LOWPOWER;
rba90 0:e2ccabf3f30c 373 break;
rba90 0:e2ccabf3f30c 374 }
rba90 0:e2ccabf3f30c 375 }
rba90 0:e2ccabf3f30c 376 }
rba90 0:e2ccabf3f30c 377
rba90 31:a0454fda1538 378 void AlohaTransceiver::sendFrame(AlohaFrame *frame)
rba90 31:a0454fda1538 379 {
rba90 31:a0454fda1538 380 // create a buffer for transmit
rba90 31:a0454fda1538 381 uint8_t frame_length = frame->getPayloadLength() + FIXED_BYTE;
rba90 31:a0454fda1538 382 uint8_t buffer[frame_length]; // 4 fix fields
rba90 31:a0454fda1538 383 memset(buffer, 0x0, sizeof(buffer));
rba90 31:a0454fda1538 384
rba90 31:a0454fda1538 385 // copy content to buffer
rba90 31:a0454fda1538 386 frame->serialize(buffer);
rba90 31:a0454fda1538 387
rba90 31:a0454fda1538 388 // send to radio
rba90 31:a0454fda1538 389 Radio.Send(buffer, frame_length);
rba90 31:a0454fda1538 390 }
rba90 31:a0454fda1538 391
rba90 24:8f31c33c7675 392 bool AlohaTransceiver::send(BasicPacket *packet)
rba90 24:8f31c33c7675 393 {
rba90 24:8f31c33c7675 394 // for the reason that we only transmit basic packet format, the
rba90 24:8f31c33c7675 395 // length is always 8
rba90 24:8f31c33c7675 396 uint8_t payload_length = 8;
rba90 24:8f31c33c7675 397
rba90 24:8f31c33c7675 398 // get destination address
rba90 24:8f31c33c7675 399 uint8_t destination_address = findNextHop(packet->getDestinationID());
rba90 24:8f31c33c7675 400
rba90 24:8f31c33c7675 401 // serialize the packet from upper layer
rba90 24:8f31c33c7675 402 uint8_t buffer[payload_length];
rba90 24:8f31c33c7675 403 memset(buffer, 0x0, sizeof(buffer));
rba90 24:8f31c33c7675 404
rba90 24:8f31c33c7675 405 // copy bytes into buffer
rba90 24:8f31c33c7675 406 packet->serialize(buffer);
rba90 17:c6e2e2cd6e5f 407
rba90 17:c6e2e2cd6e5f 408 // create a new frame
rba90 22:2e39f382f782 409 AlohaFrame *frame = new AlohaFrame();
rba90 17:c6e2e2cd6e5f 410
rba90 22:2e39f382f782 411 // set properfies
rba90 24:8f31c33c7675 412 // set payload as data
rba90 22:2e39f382f782 413 frame->setType(AlohaFrame::Aloha_Data);
rba90 24:8f31c33c7675 414
rba90 24:8f31c33c7675 415 // set payload length (8 bytes for BasicPacket)
rba90 22:2e39f382f782 416 frame->setPayloadLength(payload_length);
rba90 24:8f31c33c7675 417
rba90 24:8f31c33c7675 418 // set mac layer device id
rba90 22:2e39f382f782 419 frame->setSourceAddress(deviceId);
rba90 24:8f31c33c7675 420
rba90 24:8f31c33c7675 421 // set mac layer destination id
rba90 24:8f31c33c7675 422 // for multiple hop system, the destination is the next hop
rba90 24:8f31c33c7675 423 // in this case, we use destination id from upper layer
rba90 24:8f31c33c7675 424 frame->setDestinationAddress(packet->getDestinationID());
rba90 24:8f31c33c7675 425
rba90 24:8f31c33c7675 426 // set full message flag (always true in this case)
rba90 22:2e39f382f782 427 frame->setFullMessageFlag(0x1);
rba90 22:2e39f382f782 428
rba90 24:8f31c33c7675 429 // use dest_addr as key for accessing sequence id
rba90 24:8f31c33c7675 430 // the seqid should increase as it successfully transmit the packet
rba90 24:8f31c33c7675 431 frame->setSequenceID(seqid[destination_address]++);
rba90 24:8f31c33c7675 432
rba90 22:2e39f382f782 433 // set payload
rba90 17:c6e2e2cd6e5f 434 for (uint8_t i = 0; i < payload_length; i++)
rba90 17:c6e2e2cd6e5f 435 {
rba90 24:8f31c33c7675 436 frame->setPayload(i, buffer[i]);
rba90 17:c6e2e2cd6e5f 437 }
rba90 17:c6e2e2cd6e5f 438
rba90 17:c6e2e2cd6e5f 439 // calculate crc
rba90 22:2e39f382f782 440 frame->generateCrc();
rba90 17:c6e2e2cd6e5f 441
rba90 22:2e39f382f782 442 // push frame to the back of queue
rba90 22:2e39f382f782 443 AlohaTxQueue.enqueue(frame);
rba90 27:463688e3bd12 444
rba90 27:463688e3bd12 445 // debug
rba90 27:463688e3bd12 446 #ifdef DEBUG_ALOHA
rba90 29:6c59b0bba861 447 printf("\r\nTXDATA::DEST_ADDR:0x%x,SEQID:0x%x\r\n", frame->getDestinationAddress(), frame->getSequenceID());
rba90 27:463688e3bd12 448 #endif
rba90 17:c6e2e2cd6e5f 449 return true;
rba90 0:e2ccabf3f30c 450 }
rba90 0:e2ccabf3f30c 451
rba90 25:bcd1cee4e5a8 452 void AlohaTransceiver::sendAck(AlohaFrame *inFrame)
rba90 25:bcd1cee4e5a8 453 {
rba90 25:bcd1cee4e5a8 454 // create a new frame by calling it's constructor
rba90 25:bcd1cee4e5a8 455 AlohaFrame *outFrame = new AlohaFrame();
rba90 25:bcd1cee4e5a8 456
rba90 25:bcd1cee4e5a8 457 // set frame type
rba90 25:bcd1cee4e5a8 458 outFrame->setType(AlohaFrame::Aloha_ACK);
rba90 25:bcd1cee4e5a8 459
rba90 25:bcd1cee4e5a8 460 // set payload length (0 byte payload for ack frame)
rba90 25:bcd1cee4e5a8 461 outFrame->setPayloadLength(0);
rba90 25:bcd1cee4e5a8 462
rba90 25:bcd1cee4e5a8 463 // set mac layer device id
rba90 25:bcd1cee4e5a8 464 outFrame->setSourceAddress(deviceId);
rba90 25:bcd1cee4e5a8 465
rba90 25:bcd1cee4e5a8 466 // set mac layer destination id
rba90 25:bcd1cee4e5a8 467 outFrame->setDestinationAddress(inFrame->getSourceAddress());
rba90 25:bcd1cee4e5a8 468
rba90 25:bcd1cee4e5a8 469 // set full message flag
rba90 25:bcd1cee4e5a8 470 outFrame->setFullMessageFlag(0x1);
rba90 25:bcd1cee4e5a8 471
rba90 25:bcd1cee4e5a8 472 // set seqid
rba90 25:bcd1cee4e5a8 473 // the sequence id is always the source id + 1
rba90 25:bcd1cee4e5a8 474 outFrame->setSequenceID(inFrame->getSequenceID() + 1);
rba90 25:bcd1cee4e5a8 475
rba90 25:bcd1cee4e5a8 476 // no payload
rba90 25:bcd1cee4e5a8 477
rba90 25:bcd1cee4e5a8 478 // generate cec
rba90 25:bcd1cee4e5a8 479 outFrame->generateCrc();
rba90 25:bcd1cee4e5a8 480
rba90 25:bcd1cee4e5a8 481 // push frame to the back of queue
rba90 25:bcd1cee4e5a8 482 AlohaTxQueue.enqueue(outFrame);
rba90 25:bcd1cee4e5a8 483
rba90 25:bcd1cee4e5a8 484 // debug
rba90 25:bcd1cee4e5a8 485 #ifdef DEBUG_ALOHA
rba90 29:6c59b0bba861 486 printf("\r\nTXACK::DEST_ADDR:0x%x,SEQID:0x%x\r\n", outFrame->getDestinationAddress(), outFrame->getSequenceID());
rba90 25:bcd1cee4e5a8 487 #endif
rba90 25:bcd1cee4e5a8 488 }
rba90 25:bcd1cee4e5a8 489
rba90 28:2c0e115b4f72 490 bool AlohaTransceiver::getTxDoneFlag()
rba90 28:2c0e115b4f72 491 {
rba90 31:a0454fda1538 492 return isTxDone;
rba90 28:2c0e115b4f72 493 }
rba90 28:2c0e115b4f72 494
rba90 28:2c0e115b4f72 495 void AlohaTransceiver::setTxDoneFlag()
rba90 28:2c0e115b4f72 496 {
rba90 31:a0454fda1538 497 isTxDone = true;
rba90 28:2c0e115b4f72 498 }
rba90 28:2c0e115b4f72 499
rba90 28:2c0e115b4f72 500 void AlohaTransceiver::clearTxDoneFlag()
rba90 28:2c0e115b4f72 501 {
rba90 31:a0454fda1538 502 isTxDone = false;
rba90 31:a0454fda1538 503 }
rba90 31:a0454fda1538 504
rba90 31:a0454fda1538 505 bool AlohaTransceiver::getAckedFlag(uint8_t addr)
rba90 31:a0454fda1538 506 {
rba90 31:a0454fda1538 507 return CHECK_FLAG(isAcked, addr);
rba90 31:a0454fda1538 508 }
rba90 31:a0454fda1538 509
rba90 31:a0454fda1538 510 void AlohaTransceiver::setAckedFlag(uint8_t addr)
rba90 31:a0454fda1538 511 {
rba90 31:a0454fda1538 512 SET_FLAG(isAcked, addr);
rba90 31:a0454fda1538 513 }
rba90 31:a0454fda1538 514
rba90 31:a0454fda1538 515 void AlohaTransceiver::clearAckedFlag(uint8_t addr)
rba90 31:a0454fda1538 516 {
rba90 31:a0454fda1538 517 CLEAR_FLAG(isAcked, addr);
rba90 28:2c0e115b4f72 518 }
rba90 28:2c0e115b4f72 519
rba90 0:e2ccabf3f30c 520 void AlohaTransceiver::registerType(AlohaFrame::AlohaType_t type, aloha_callback_func f)
rba90 0:e2ccabf3f30c 521 {
rba90 0:e2ccabf3f30c 522 AlohaTypeCallbackTable[type] = f;
rba90 0:e2ccabf3f30c 523 }
rba90 0:e2ccabf3f30c 524
rba90 0:e2ccabf3f30c 525 void AlohaTransceiver::deRegisterType(AlohaFrame::AlohaType_t type, aloha_callback_func f)
rba90 0:e2ccabf3f30c 526 {
rba90 0:e2ccabf3f30c 527 AlohaTypeCallbackTable[type] = NULL;
rba90 0:e2ccabf3f30c 528 }
rba90 0:e2ccabf3f30c 529
rba90 2:fa264e48d5f7 530 int16_t AlohaTransceiver::getRssi()
rba90 2:fa264e48d5f7 531 {
rba90 2:fa264e48d5f7 532 return RssiValue;
rba90 2:fa264e48d5f7 533 }
rba90 2:fa264e48d5f7 534
rba90 2:fa264e48d5f7 535 int8_t AlohaTransceiver::getSnr()
rba90 2:fa264e48d5f7 536 {
rba90 2:fa264e48d5f7 537 return SnrValue;
rba90 2:fa264e48d5f7 538 }
rba90 2:fa264e48d5f7 539
rba90 17:c6e2e2cd6e5f 540 uint8_t AlohaTransceiver::getDeviceID()
rba90 11:3e1ff29da71a 541 {
rba90 11:3e1ff29da71a 542 return deviceId;
rba90 11:3e1ff29da71a 543 }
rba90 11:3e1ff29da71a 544
rba90 17:c6e2e2cd6e5f 545 void AlohaTransceiver::setDeviceID(uint8_t id)
rba90 11:3e1ff29da71a 546 {
rba90 11:3e1ff29da71a 547 deviceId = id;
rba90 11:3e1ff29da71a 548 }
rba90 11:3e1ff29da71a 549
rba90 24:8f31c33c7675 550 uint8_t AlohaTransceiver::findNextHop(uint8_t addr)
rba90 24:8f31c33c7675 551 {
rba90 24:8f31c33c7675 552 // TODO: maintain a routing lookup table for choosing shortest path
rba90 24:8f31c33c7675 553 return addr;
rba90 24:8f31c33c7675 554 }
rba90 24:8f31c33c7675 555
rba90 8:4bda842f73d4 556 #if USE_MODEM_LORA == 1
rba90 8:4bda842f73d4 557 AlohaTransceiver::LoRaSettings_t *AlohaTransceiver::getSettings()
rba90 8:4bda842f73d4 558 {
rba90 8:4bda842f73d4 559 return &Settings;
rba90 8:4bda842f73d4 560 }
rba90 8:4bda842f73d4 561
rba90 8:4bda842f73d4 562 #elif USE_MODEM_FSK == 1
rba90 8:4bda842f73d4 563 AlohaTransceiver::FskSettings_t *AlohaTransceiver::getSettings()
rba90 8:4bda842f73d4 564 {
rba90 8:4bda842f73d4 565 return &Settings;
rba90 8:4bda842f73d4 566 }
rba90 8:4bda842f73d4 567 #else
rba90 8:4bda842f73d4 568 #error "Please define a modem in the compiler options."
rba90 8:4bda842f73d4 569 #endif
rba90 8:4bda842f73d4 570
rba90 0:e2ccabf3f30c 571 void OnTxDone( void )
rba90 0:e2ccabf3f30c 572 {
rba90 0:e2ccabf3f30c 573 Radio.Sleep( );
rba90 0:e2ccabf3f30c 574 State = TX;
rba90 18:3e6483550f25 575
rba90 18:3e6483550f25 576 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 577 debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnTxDone\n\r" );
rba90 18:3e6483550f25 578 #endif
rba90 0:e2ccabf3f30c 579 }
rba90 0:e2ccabf3f30c 580
rba90 0:e2ccabf3f30c 581 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
rba90 0:e2ccabf3f30c 582 {
rba90 27:463688e3bd12 583 uint8_t payload_length;
rba90 27:463688e3bd12 584
rba90 0:e2ccabf3f30c 585 Radio.Sleep( );
rba90 0:e2ccabf3f30c 586
rba90 0:e2ccabf3f30c 587 // safeguard: if size exceeded maximum buffer size, it will cause memory overflow
rba90 27:463688e3bd12 588 payload_length = size ? BUFFER_SIZE : size <= BUFFER_SIZE;
rba90 27:463688e3bd12 589
rba90 27:463688e3bd12 590 // create a new frame instance
rba90 27:463688e3bd12 591 AlohaFrame *frame = new AlohaFrame(payload, payload_length);
rba90 27:463688e3bd12 592
rba90 27:463688e3bd12 593 // push onto the end of queue
rba90 27:463688e3bd12 594 AlohaRxQueue.enqueue(frame);
rba90 0:e2ccabf3f30c 595
rba90 0:e2ccabf3f30c 596 RssiValue = rssi;
rba90 0:e2ccabf3f30c 597 SnrValue = snr;
rba90 0:e2ccabf3f30c 598 State = RX;
rba90 18:3e6483550f25 599
rba90 18:3e6483550f25 600 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 601 debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxDone, RSSI=%d, SNR=%d\n\r", rssi, snr );
rba90 18:3e6483550f25 602 #endif
rba90 0:e2ccabf3f30c 603 }
rba90 0:e2ccabf3f30c 604
rba90 0:e2ccabf3f30c 605 void OnTxTimeout( void )
rba90 0:e2ccabf3f30c 606 {
rba90 0:e2ccabf3f30c 607 Radio.Sleep( );
rba90 0:e2ccabf3f30c 608 State = TX_TIMEOUT;
rba90 18:3e6483550f25 609
rba90 18:3e6483550f25 610 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 611 debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnTxTimeout\r\n" );
rba90 18:3e6483550f25 612 #endif
rba90 0:e2ccabf3f30c 613 }
rba90 0:e2ccabf3f30c 614
rba90 0:e2ccabf3f30c 615 void OnRxTimeout( void )
rba90 0:e2ccabf3f30c 616 {
rba90 0:e2ccabf3f30c 617 Radio.Sleep( );
rba90 0:e2ccabf3f30c 618 State = RX_TIMEOUT;
rba90 18:3e6483550f25 619
rba90 18:3e6483550f25 620 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 621 debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxTimeout\r\n" );
rba90 18:3e6483550f25 622 #endif
rba90 0:e2ccabf3f30c 623 }
rba90 0:e2ccabf3f30c 624
rba90 0:e2ccabf3f30c 625 void OnRxError( void )
rba90 0:e2ccabf3f30c 626 {
rba90 0:e2ccabf3f30c 627 Radio.Sleep( );
rba90 0:e2ccabf3f30c 628 State = RX_ERROR;
rba90 18:3e6483550f25 629
rba90 18:3e6483550f25 630 #ifdef DEBUG_ALOHA
rba90 39:0da3ee6a297d 631 debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxError\r\n" );
rba90 18:3e6483550f25 632 #endif
rba90 0:e2ccabf3f30c 633 }
rba90 24:8f31c33c7675 634
rba90 36:09c105fe77c0 635