Basic MAC data interface for LoRa transceiver

Dependencies:   L2Frame crc

Dependents:   LoRaBaseStation LoRaTerminal

Revision:
39:0da3ee6a297d
Parent:
38:e7b679acf524
Child:
40:271fa9e98589
--- a/AlohaTransceiver.cpp	Wed Sep 14 06:36:24 2016 +0000
+++ b/AlohaTransceiver.cpp	Wed Sep 14 07:47:18 2016 +0000
@@ -6,6 +6,8 @@
 #include "RingBuffer.h"
 
 #define ALLOW_CALLBACK_DEBUG  1
+#define CSMA_CA_BACKOFF_TIME 1000 // in ms
+#define CSMA_CA_CHANNEL_THRESHOLD -80 // in dbm
 
 #define SET_FLAG(t, x) (t) |= 1 << (x)
 #define CLEAR_FLAG(t, x) (t) &= ~(1 << (x))
@@ -78,6 +80,12 @@
     // assume all station is clear to transmit
     isAcked = 0xffff;
     
+    // reset CSMA backoff timer
+    CSMABackoffTimer.reset();
+    
+    // reset CSMA backoff state
+    isBackoff = false;
+    
     
     // configure properties
 #if USE_MODEM_LORA == 1
@@ -206,7 +214,7 @@
                             setAckedFlag(src_addr);
                         }
 #ifdef DEBUG_ALOHA
-                        printf("frame_seqid: %d, local_seqid: %d\r\n", frame->getSequenceID(), seqid[frame->getSourceAddress()]);
+                        printf("ACK::frame_seqid: %d, local_seqid: %d\r\n", frame->getSequenceID(), seqid[frame->getSourceAddress()]);
 #endif
                     }
                 
@@ -273,57 +281,86 @@
             if (getTxDoneFlag())
             {
                 // find next available packet to transmit
-                for (size_t i = 0; i < AlohaTxQueue.getCounter(); i++)
+                while( AlohaTxQueue.getCounter() > 0)
                 {
-                    AlohaFrame *frame = AlohaTxQueue.dequeue();
-
-                    // determined by the type of the frame, only data frame need to be cleared before transmitting
-                    switch (frame->getType())
+                    // perform CSMA backoff routine
+                    if (isBackoff == true) // if the transceiver is already in the backoff state, then wait until timer expires
                     {
-                        // Data frame need proper clearance
-                        case AlohaFrame::Aloha_Data:
+                        if (CSMABackoffTimer.read_ms() > CSMA_CA_BACKOFF_TIME)
+                        {
+                            isBackoff = false;
+                            CSMABackoffTimer.stop();
+                        }
+                    }
+                    
+                    
+                    if (isBackoff == false) // if the transceiver is not in backoff state, then attempt to transmit
+                    {
+                        if (Radio.IsChannelFree(MODEM_LORA, RF_FREQUENCY, CSMA_CA_CHANNEL_THRESHOLD))
                         {
-                            uint8_t dest_addr = frame->getDestinationAddress();
-                            
-                            // depending on the availability of the destination host,
-                            // the radio will on transmit the packet when acked.
-                            // 
-                            // in the test build, we are not going to enable this feature
-                            // if (getAckedFlag(dest_addr))
-                            if (true)
+#ifdef DEBUG_ALOHA
+                            printf(" CSMA/CA::Channel is free, ready to transmit\r\n");
+#endif 
+                            AlohaFrame *frame = AlohaTxQueue.dequeue();
+
+                            // determined by the type of the frame, only data frame need to be cleared before transmitting
+                            switch (frame->getType())
                             {
-                                sendFrame(frame);
-                                
-                                // block the next transmission until previous transmission is done
-                                clearTxDoneFlag();
+                                // Data frame need proper clearance
+                                case AlohaFrame::Aloha_Data:
+                                {
+                                    uint8_t dest_addr = frame->getDestinationAddress();
+                                    
+                                    // depending on the availability of the destination host,
+                                    // the radio will on transmit the packet when acked.
+                                    // 
+                                    // in the test build, we are not going to enable this feature
+                                    // if (getAckedFlag(dest_addr))
+                                    if (true)
+                                    {
+                                        sendFrame(frame);
+                                        
+                                        // block the next transmission until previous transmission is done
+                                        clearTxDoneFlag();
+                                        
+                                        // block the next transmission of the same host until an acked packet
+                                        // is received
+                                        clearAckedFlag(dest_addr);
+                                        
+                                        // free memory
+                                        delete frame;
+                                    }
+                                    
+                                    // otherwise put the packet back to the end of queue and wait for its being acked
+                                    else
+                                    {
+                                        AlohaTxQueue.enqueue(frame);
+                                    }
+                                    break;
+                                }
                                 
-                                // block the next transmission of the same host until an acked packet
-                                // is received
-                                clearAckedFlag(dest_addr);
-                                
-                                // free memory
-                                delete frame;
-                            }
-                            
-                            // otherwise put the packet back to the end of queue and wait for its being acked
-                            else
-                            {
-                                AlohaTxQueue.enqueue(frame);
+                                default:
+                                {
+                                    sendFrame(frame);
+                                    
+                                    // block the next transmission until previous transmission is done
+                                    clearTxDoneFlag();
+                                        
+                                    // free memory
+                                    delete frame;
+                                    
+                                    break;
+                                }
                             }
-                            break;
                         }
-                        
-                        default:
+                        else // if channel if not free, then start the timer, set the backoff state to true
                         {
-                            sendFrame(frame);
-                            
-                            // block the next transmission until previous transmission is done
-                            clearTxDoneFlag();
-                                
-                            // free memory
-                            delete frame;
-                            
-                            break;
+#ifdef DEBUG_ALOHA
+                            printf("CSMA/CA::Channel is not free, wait for 1s\r\n");
+#endif
+                            isBackoff = true;
+                            CSMABackoffTimer.reset();
+                            CSMABackoffTimer.start();
                         }
                     }
                 }
@@ -537,7 +574,7 @@
     State = TX;
     
 #ifdef DEBUG_ALOHA
-    debug_if(ALLOW_CALLBACK_DEBUG, "> OnTxDone\n\r" );
+    debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnTxDone\n\r" );
 #endif
 }
 
@@ -561,7 +598,7 @@
     State = RX;
     
 #ifdef DEBUG_ALOHA
-    debug_if(ALLOW_CALLBACK_DEBUG, "> OnRxDone, RSSI=%d, SNR=%d\n\r", rssi, snr );
+    debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxDone, RSSI=%d, SNR=%d\n\r", rssi, snr );
 #endif
 }
 
@@ -571,7 +608,7 @@
     State = TX_TIMEOUT;
     
 #ifdef DEBUG_ALOHA
-    debug_if(ALLOW_CALLBACK_DEBUG, "> OnTxTimeout\n\r" );
+    debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnTxTimeout\r\n" );
 #endif
 }
 
@@ -581,7 +618,7 @@
     State = RX_TIMEOUT;
     
 #ifdef DEBUG_ALOHA
-    debug_if(ALLOW_CALLBACK_DEBUG, "> OnRxTimeout\n\r" );
+    debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxTimeout\r\n" );
 #endif
 }
 
@@ -591,7 +628,7 @@
     State = RX_ERROR;
     
 #ifdef DEBUG_ALOHA
-    debug_if(ALLOW_CALLBACK_DEBUG, "> OnRxError\n\r" );
+    debug_if(ALLOW_CALLBACK_DEBUG, "RADIO::OnRxError\r\n" );
 #endif
 }