Aloha implementation of LoRa technology

Dependencies:   SX1276Lib mbed

Fork of SX1276PingPong by Semtech

main.cpp

Committer:
rba90
Date:
2016-06-08
Revision:
16:c3c6b13c3c42
Parent:
15:f790f35839db

File content as of revision 16:c3c6b13c3c42:

#include "mbed.h"
#include "main.h"
#include "sx1276-hal.h"
#include "debug.h"
#include "Aloha.h"
#include "AlohaPacket.h"

/* Set this flag to '1' to display debug messages on the console */
#define DEBUG_MESSAGE   1

#define RF_FREQUENCY                                    868000000 // Hz
#define TX_OUTPUT_POWER                                 14        // 14 dBm
#define LORA_BANDWIDTH                              2         // [0: 125 kHz,
                                                              //  1: 250 kHz,
                                                              //  2: 500 kHz,
                                                              //  3: Reserved]
#define LORA_SPREADING_FACTOR                       7         // [SF7..SF12]
#define LORA_CODINGRATE                             1         // [1: 4/5,
                                                              //  2: 4/6,
                                                              //  3: 4/7,
                                                              //  4: 4/8]
#define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT                         5         // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON                  false
#define LORA_FHSS_ENABLED                           false  
#define LORA_NB_SYMB_HOP                            4     
#define LORA_IQ_INVERSION_ON                        false
#define LORA_CRC_ENABLED                            true


#define RX_TIMEOUT_VALUE                                3500000   // in us
#define BUFFER_SIZE                                     4 // Define the payload size here

DigitalOut led(LED2);

uint16_t BufferSize = BUFFER_SIZE;
uint8_t Buffer[BUFFER_SIZE];

int16_t RssiValue = 0.0;
int8_t SnrValue = 0.0;

/*
 *  Global variables declarations
 */
typedef enum
{
    LOWPOWER = 0,
    IDLE,
    
    RX,
    RX_TIMEOUT,
    RX_ERROR,
    
    TX,
    TX_TIMEOUT,
    
    CAD,
    CAD_DONE
}AppStates_t;

volatile AppStates_t State = LOWPOWER;


/*!
 * Radio events function pointer
 */
static RadioEvents_t RadioEvents;

/*
 *  Global variables declarations
 */
SX1276MB1xAS Radio( NULL );

// aloha protocol
Aloha aloha;

// user button
InterruptIn UserButton(USER_BUTTON);
static int seqid = 0;

void sendMessage()
{
    HeaderStruct header;
    DataStruct data;
    
    memset(&header, 0, sizeof(header));
    memset(&data, 0, sizeof(data));
    
    header.fid = 0x0;
    header.no = (uint8_t) seqid;
    data.pd0 = 0xff;
    data.pd1 = 0xff;
    
    uint8_t buffer[4];
    createAlohaPacket(buffer, &header, &data);
    
    Radio.Send(buffer, 4);
}

void sendAck(int id)
{
    HeaderStruct header;
    DataStruct data;
    
    memset(&header, 0, sizeof(header));
    memset(&data, 0, sizeof(data));
    
    header.fid = 0x1;
    header.no = (uint8_t) id;
    data.pd0 = 0x00;
    data.pd1 = 0x00;
    
    uint8_t buffer[4];
    createAlohaPacket(buffer, &header, &data);
    
    Radio.Send(buffer, 4);
}


void setExpire()
{
    if (aloha.attempts >= ALOHA_MAX_ATTEMPT)
    {
        aloha.state = Aloha::EXPIRED;
    }
    else
    {
        aloha.state = Aloha::RETRANSMIT;
    }
}

void userButtonHandler()
{
    seqid += 1;
    sendMessage();
}

void RadioInit()
{
    // Initialize Radio driver
    RadioEvents.TxDone = OnTxDone;
    RadioEvents.RxDone = OnRxDone;
    RadioEvents.RxError = OnRxError;
    RadioEvents.TxTimeout = OnTxTimeout;
    RadioEvents.RxTimeout = OnRxTimeout;
    Radio.Init( &RadioEvents );
    
    // detect radio hardware
    while( Radio.Read( REG_VERSION ) == 0x00  )
    {
        printf( "Radio could not be detected!\n\r" );
        wait( 1 );
    }
    printf("RadioRegVersion: %d\r\n", Radio.Read( REG_VERSION ));
    
    // set radio frequency channel
    Radio.SetChannel( RF_FREQUENCY ); 
    
    // set radio parameter
    Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
                         LORA_SPREADING_FACTOR, LORA_CODINGRATE,
                         LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
                         LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, 
                         LORA_IQ_INVERSION_ON, 2000000 );
    
    Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                         LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                         LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0,
                         LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, 
                         LORA_IQ_INVERSION_ON, true );
}


int main() 
{  
    RadioInit();
    UserButton.rise(userButtonHandler);
    
    Radio.Rx( RX_TIMEOUT_VALUE );
    while (1)
    {
        switch( State )
        {
        case RX:
            // if the receive frame is an ack, then cancel the timer
            // otherwise process the frame
            HeaderStruct header;
            DataStruct data;
            
            memset(&header, 0, sizeof(header));
            memset(&data, 0, sizeof(data));
            
            // decode data
            dissectAlohaPacket(Buffer, &header, &data);
            
            // process packet
            switch (header.fid)
            {
                case 0x0: // data packet
                    sendAck(header.no);
                    break;
                    
                case 0x1: // ack received
                    aloha.AlohaAckTimeout.detach();
                    aloha.state = Aloha::IDLE;
                    break;
                
                default:
                    break;
            }
                
            if (header.fid == 0x01)
            {
                aloha.AlohaAckTimeout.detach();
            }
            
            // TODO: process the frame
            
            
            printf("RECV::fid=0x%x, seqid=0x%x, pd0=0x%x, pd1=0x%x\r\n", header.fid, header.no, data.pd0, data.pd1);
            
            // enter listening mode
            Radio.Rx( RX_TIMEOUT_VALUE );
            
            State = LOWPOWER;
            break;
        case TX:
            // transmit done
            // set the state to pending and attach the timer with random delay
            
            // we dont need ack for ack
            if (aloha.state == Aloha::ACK_RESP)
            {
                aloha.state =  Aloha::IDLE;
                break;
            }
            
            // set delay time
            if (aloha.state == Aloha::IDLE)
            {
                aloha.delay = (Radio.Random() % 1000) / 1000.0f;
            }
            else if (aloha.state == Aloha::RETRANSMIT)
            {
                aloha.delay *= 2;
            }
            
            aloha.AlohaAckTimeout.detach();
            aloha.AlohaAckTimeout.attach(&setExpire, aloha.delay);
            
            // increase the attempt counter
            aloha.attempts += 1;
            
            // enter listening mode
            Radio.Rx( RX_TIMEOUT_VALUE );
            
            // state transition
            aloha.state = Aloha::PENDING;
                    
            State = LOWPOWER;
            break;
        case RX_TIMEOUT:
            // enter listening mode
            Radio.Rx( RX_TIMEOUT_VALUE );
            
            State = LOWPOWER;
            break;
        case RX_ERROR:
            // we don't handle crc failed situation
            // enter listening mode
            Radio.Rx( RX_TIMEOUT_VALUE );
            
            State = LOWPOWER;
            break;
        case TX_TIMEOUT:
            // we don't handle hardware error
            // enter listening mode
            Radio.Rx( RX_TIMEOUT_VALUE );
            
            State = LOWPOWER;
            break;
        case LOWPOWER:
            break;
        default:
            State = LOWPOWER;
            break;
        }
        
        switch (aloha.state)
        {
        case Aloha::IDLE:
            // transmit packet if any
            // printf("Aloha::IDLE\r\n");
            break;
        
        case Aloha::PENDING:
            // set rx time
            // printf("Aloha::PENDING, delay=%f, attempt=%d\r\n", aloha.delay, aloha.attempts);
            break;
            
        case Aloha::RETRANSMIT:
            // send the packet again
            sendMessage();
            
            // printf("Aloha::RETRANSMIT\r\n");
            break;
        case Aloha::EXPIRED:
            // give up the transmission
            // back to idle
            aloha.attempts = 0;
            
            aloha.state = Aloha::IDLE;
            // printf("Aloha::EXPIRED\r\n");
            break;
        case Aloha::ACK_RESP:
            break;
        default:
            break;
        }
    }
}

void OnTxDone( void )
{
    Radio.Sleep( );
    State = TX;
    printf( "> OnTxDone\n\r" );
}

void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
{
    Radio.Sleep( );
    BufferSize = size;
    memcpy( Buffer, payload, BufferSize );
    RssiValue = rssi;
    SnrValue = snr;
    State = RX;
    printf( "> OnRxDone\n\r" );
}

void OnTxTimeout( void )
{
    Radio.Sleep( );
    State = TX_TIMEOUT;
    printf( "> OnTxTimeout\n\r" );
}

void OnRxTimeout( void )
{
    Radio.Sleep( );
    Buffer[ BufferSize ] = 0;
    State = RX_TIMEOUT;
    printf( "> OnRxTimeout\n\r" );
}

void OnRxError( void )
{
    Radio.Sleep( );
    State = RX_ERROR;
    printf( "> OnRxError\n\r" );
}