Basic MAC data interface for LoRa transceiver

Dependencies:   L2Frame crc

Dependents:   LoRaBaseStation LoRaTerminal

Committer:
rba90
Date:
Wed Sep 14 08:50:37 2016 +0000
Revision:
41:37c1d616a848
Parent:
40:271fa9e98589
transmit one packet at a time

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