Basic MAC data interface for LoRa transceiver

Dependencies:   L2Frame crc

Dependents:   LoRaBaseStation LoRaTerminal

Committer:
rba90
Date:
Wed Sep 14 06:36:24 2016 +0000
Revision:
38:e7b679acf524
Parent:
37:9e895f3ffd41
Child:
39:0da3ee6a297d
print SNR and RSSI if ALLOW_CALLBACK_DEBUG is set to 1

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