CROTUS / CROTUS_XBee

Dependents:   ProjetCasque

Fork of CROTUS_XBee by Valentin Libioulle

xbee.cpp

Committer:
libv2001
Date:
2017-04-03
Revision:
3:cc699ba7a827
Parent:
2:406da750f115
Child:
4:6ba5b06193d1

File content as of revision 3:cc699ba7a827:

#include "mbed.h"
#include "rtos.h"
#include "xbee.h"

/*******************************************************/
/*****************PRIVATE FUNCTIONS*********************/
/*******************************************************/
namespace {
    DigitalOut _xbeeConnection(LED4);

    Serial _xbee(p9, p10);
    DigitalOut _xbeeRst(p8);

    char _destination64bit[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    char _destination16bit[2] = {0xff, 0xfe};
    
    const int HARDWARE_RESET_SIGNAL = 0x10;
    const int CONNECTED_SIGNAL = 0x20;
    const int TICKER_SIGNAL = 0x40;
    const int RESPONSE_SIGNAL = 0x80;
    
    int _responseStatus;
    
    int _panID = 0xB00B;
    char _frameID = 0;
    
    Thread _xbeeReceiver;
    Thread * _xbeeTransmitter;
    
    void(*_packetReceivedCallback)(char*, int) = 0;
    
    /*******************************************************/
    /*******************XBEE UTILITIES**********************/
    /*******************************************************/
    inline char _GetFrameID(){
        ++_frameID;
        if (_frameID == 0){
            _frameID = 1;
        }
        return _frameID;
    }
    
    inline uint16_t _GetFrameLength(char * buffer){
        return (((uint16_t)buffer[LENGTH_MSB_IDX]) << 8) + buffer[LENGTH_LSB_IDX];
    }
    
    bool _ValidateCheckSum(char * buffer){
        uint16_t length = _GetFrameLength(buffer);
        
        char sum = 0;
        for (int i = 0; i <= length; ++i){
            sum += buffer[i + API_ID_IDX];
        }
        
        return sum == 0xff;
    }
    
    inline uint16_t _GetAtParamLength(char * buffer){
        return _GetFrameLength(buffer) - AT_MIN_SIZE;
    }
    
    inline uint16_t _GetAtQueueParamLength(char * buffer){
        return _GetFrameLength(buffer) - AT_QUEUE_MIN_SIZE;
    }
    
    inline uint16_t _GetTransmitDataLength(char * buffer){
        return _GetFrameLength(buffer) - TRANSMIT_MIN_SIZE;
    }
    
    inline uint16_t _GetAtResponseParamLength(char * buffer){
        return _GetFrameLength(buffer) - AT_CMD_RSP_MIN_SIZE;
    }
    
    inline uint16_t _GetReceivedPacketDataLength(char * buffer){
        return _GetFrameLength(buffer) - RECEIVED_PACKET_MIN_SIZE;
    }
    
    void _SetCheckSum(char * buffer){
        uint16_t length = _GetFrameLength(buffer);
        
        char sum = 0;
        
        int max = length + 3;
        
        for(int i = 3; i < max; ++i){
            sum += buffer[i];
        }
        
        buffer[max] = 0xff - sum;
    }
    
    /*******************************************************/
    /**********************XBEE SEND************************/
    /*******************************************************/
    void _XbeeSend(char * buffer, int count){
        for ( int i = 0; i < count; ++i ){
            _xbee.putc(buffer[i]);
            wait_us(25);
        }
    }
    
    void _XbeeSendATCommand(bool queue, char * type, char * data, int dataLength){
        char buffer[64];
        buffer[START_IDX] = START_BYTE;
        buffer[LENGTH_MSB_IDX] = (dataLength + AT_MIN_SIZE) >> 8;
        buffer[LENGTH_LSB_IDX] = (dataLength + AT_MIN_SIZE) & 0xff;
        buffer[API_ID_IDX] = queue ? API_ID_AT_CMD_QUEUE : API_ID_AT_CMD;
        buffer[FRAME_ID_IDX] = _GetFrameID();
        memcpy(&buffer[AT_CMD_ID_IDX], type, AT_CMD_ID_SIZE);
        memcpy(&buffer[AT_PARAM_IDX], data, dataLength);
        
        _SetCheckSum(buffer);
        
        while(true){
            _XbeeSend(buffer, dataLength + AT_MIN_SIZE + FRAME_MIN_SIZE);
        
            Thread::signal_wait(RESPONSE_SIGNAL);
            
            switch (_responseStatus){
            case AT_CMD_RSP_STATUS_OK:
                return;
            case AT_CMD_RSP_STATUS_ERROR:
            case AT_CMD_RSP_STATUS_INVALID_CMD:
            case AT_CMD_RSP_STATUS_INVALID_PARAM:
            case AT_CMD_RSP_STATUS_TX_FAILURE:
            default:
                _xbeeConnection = 0;
                break;
            }
        }
    }
    
    inline void _XbeeSendATID(){
        char idBuf[8];
        for (int i = 0; i < 8; ++i){
            idBuf[i] = (_panID >> (56 - 8 * i)) & 0xff;
        }
        _XbeeSendATCommand(true, "ID", idBuf, 8);
    }
    
    inline void _XbeeSendATWR(){
        _XbeeSendATCommand(true, "WR", 0, 0);
    }
    
    inline void _XbeeSendATAC(){
        _XbeeSendATCommand(true, "AC", 0, 0);
    }

    /*******************************************************/
    /********************XBEE RECEIVE***********************/
    /*******************************************************/
    inline char _XbeeReadChar(){
        while(!_xbee.readable()){
        }
        return _xbee.getc();
    }
    
    void _HandleXbeeReceivedPacket(char * cmd){
        _packetReceivedCallback(&cmd[RECEIVED_PACKET_DATA_IDX], _GetReceivedPacketDataLength(cmd));
    }
    
    void _HandleXbeeModemStatus(char * cmd){
        switch(cmd[MODEM_STATUS_STATUS_IDX]){
        case MODEM_STATUS_HARDWARE_RST:
            _xbeeTransmitter->signal_set(HARDWARE_RESET_SIGNAL);
            break;
        case MODEM_STATUS_COORDINATOR_STARTED: // For the coordinator
        case MODEM_STATUS_JOINED_NETWORK:      // For the router
            _xbeeTransmitter->signal_set(CONNECTED_SIGNAL);
            break;
        default:
            _xbeeConnection = 0;
            break;
        }
    }
    
    void _HandleXbeeATCommandResponse(char * cmd){
        _responseStatus = cmd[AT_CMD_RSP_STATUS_IDX];
        _xbeeTransmitter->signal_set(RESPONSE_SIGNAL);
    }
    
    void _HandleXbeeTransmitStatus(char * cmd){
        switch(cmd[TRANSMIT_STATUS_DELIVERY_STATUS_IDX]){
        case TRANSMIT_STATUS_OK:
            _responseStatus = cmd[TRANSMIT_STATUS_DELIVERY_STATUS_IDX];
            _xbeeTransmitter->signal_set(RESPONSE_SIGNAL);
            break;
        default:
            _xbeeConnection = 0;
        }
    }
    
    void _HandleXbeeReceivedCommand(char * cmd){
        switch(cmd[API_ID_IDX]){
        case API_ID_AT_CMD_RSP:
            _HandleXbeeATCommandResponse(cmd);
            break;
        case API_ID_MODEM_STATUS:
            _HandleXbeeModemStatus(cmd);
            break;
        case API_ID_RECEIVED_PACKET:
            _HandleXbeeReceivedPacket(cmd);
            break;
        case API_ID_TRANSMIT_STATUS:
            _HandleXbeeTransmitStatus(cmd);
            break;
        default:
            _xbeeConnection = 0;
            break;
        }
    }
    
    /*******************************************************/
    /*********************THREAD MAIN***********************/
    /*******************************************************/
    void _XbeeReceiver(){
        char buffer[64];
        while(true){
            buffer[START_IDX] = _XbeeReadChar();
            if (buffer[START_IDX] != START_BYTE){
                _xbeeConnection = 0;
                continue;
            }
            buffer[LENGTH_MSB_IDX] = _XbeeReadChar();
            buffer[LENGTH_LSB_IDX] = _XbeeReadChar();
            int length = _GetFrameLength(buffer);
            
            for (int i = 0; i <= length; ++i){
                buffer[i + API_ID_IDX] = _XbeeReadChar();
            }
            if (!_ValidateCheckSum(buffer)){
                _xbeeConnection = 0;
                continue;
            }
            
            _HandleXbeeReceivedCommand(buffer);
        }
    }

};

/*******************************************************/
/******************PUBLIC FUNCTIONS*********************/
/*******************************************************/
void XbeeSendData(char * data, int dataLength){
    char buffer[64];
    buffer[START_IDX] = START_BYTE;
    buffer[LENGTH_MSB_IDX] = (dataLength + TRANSMIT_MIN_SIZE) >> 8;
    buffer[LENGTH_LSB_IDX] = (dataLength + TRANSMIT_MIN_SIZE) & 0xff;
    buffer[API_ID_IDX] = API_ID_TRANSMIT;
    buffer[FRAME_ID_IDX] = _GetFrameID();
    memcpy(&buffer[TRANSMIT_64BIT_MSB_IDX], _destination64bit, ADDR_64BIT_SIZE);
    memcpy(&buffer[TRANSMIT_16BIT_MSB_IDX], _destination16bit, ADDR_16BIT_SIZE);
    buffer[TRANSMIT_BROADCAST_IDX] = TRANSMIT_DEFAULT_BROADCAST;
    buffer[TRANSMIT_OPT_IDX] = TRANSMIT_DEFAULT_OPT;
    memcpy(&buffer[TRANSMIT_DATA_IDX], data, dataLength);
    
    _SetCheckSum(buffer);
    
    _XbeeSend(buffer, dataLength + TRANSMIT_MIN_SIZE + FRAME_MIN_SIZE);

    Thread::signal_wait(RESPONSE_SIGNAL);
    
    switch (_responseStatus){
    case TRANSMIT_STATUS_OK:
        _xbeeConnection = 1;
        break;
    default:
        _xbeeConnection = 0;
        break;
    }
}

bool InitXbee(bool coordinator, void(*packetReceivedCallback)(char*, int), Thread * xbeeTransmitter){
    _packetReceivedCallback = packetReceivedCallback;
    _xbeeTransmitter = xbeeTransmitter;
    
    if (coordinator)
    {
        uint8_t temp[8] = {0x00, 0x13, 0xA2, 0x00, 0x40, 0x33, 0x19, 0x8D};
        memcpy(_destination64bit, temp, 8);
    }
    
    _xbeeReceiver.start(callback(_XbeeReceiver));
    
    _xbeeRst.write(0);
    wait(0.4);
    _xbeeRst.write(1);
    
    Thread::signal_wait(HARDWARE_RESET_SIGNAL);
    
    _XbeeSendATID();
    _XbeeSendATWR();
    _XbeeSendATAC();
    
    Thread::signal_wait(CONNECTED_SIGNAL);
    
    _xbeeConnection = 1;
    
    return true;
}