Class containing functions usefull to communication between PC and Xbee device

Dependents:   Coordinator_node Router_node

xbee.cpp

Committer:
EmileArseneault
Date:
2017-02-15
Revision:
20:e119856dbc5e
Parent:
19:8da8068315da

File content as of revision 20:e119856dbc5e:

#include "xbee.h"

char TransmissionNumber = 2;
Mutex mTransmissionNumber;

char GetTransmissionNumber()
{
    char nextnumber = 0;
    
    mTransmissionNumber.lock();
    nextnumber = TransmissionNumber;
    if(nextnumber == 255)
    {
        TransmissionNumber = 2;
    }
    else
    {
        TransmissionNumber++;
    }
    mTransmissionNumber.unlock();
    
    return nextnumber;
}

XBee::XBee(PinName reset, PinName transfer, PinName receive, Mail<char, 250>* m, Mail<char[256], 16>* w, Mail<char[254], 25>* r) : 
    rst(reset), comm(transfer, receive)
{
    // Constructor
    mail = m;
    webmail = w;
    frameresponsemail = r;
    rst = 0;
    wait(0.4);
    rst = 1;
    wait(3);    // waiting for initiation
    buffer[0] = '\0';
}

void XBee::appendBuffer(char* c)
{
    int i = 0;
    int j = 0;
    
    while (buffer[i] != '\0') i++;
    
    while (c[j]!= '\0' || i < 255)
    {
        buffer[i] = c[j];
        i++;j++;   
    }
    buffer[i] = '\0';
}

void XBee::sendBuffer()
{
    char* s = (char *) webmail->alloc();
    
    int i = 0;
    while (buffer[i]!= '\0' || i < 255)
    {
        s[i] = buffer[i];
        i++;
    }
    s[i] = '\0';
    
    webmail->put((char(*)[256]) s);
    
    buffer[0] = '\0';
}

char XBee::getChar()
{
    while (!comm.readable())
    {
        wait(0.02);
    }
    return comm.getc();
}

void XBee::pcPrint(char* c)
{
    int i = 0;
    while( (c)[i] != '\0')
    {
        mail->put(&(c[i]));
        i++;
    }
}

void XBee::printInt(int i)
{
    bool signe = i > 0;
    char *c = mail->alloc();
    if (signe)
    {
        *c = '-';
        mail->put(c);
        i *= -1;
    }
    
    int diviseur = 1;
    int modulo = 10;
    int j = 9;
    char chiffre[10];
    
    while (i / diviseur > 0 && j >= 0)
    {
        chiffre[j] = (char) (i % modulo)/diviseur;
        modulo *= 10;
        diviseur *= 10;
        j--;
    }
    
    j = 0;
    bool numberHasStarted = false;
    while (j < 10)
    {
        if (chiffre[j] != 0 || numberHasStarted || j == 9)
        {
            numberHasStarted = true;
            c = mail->alloc();
            *c = chiffre[j] + 0x30;
            mail->put(c);
        }
        j++;
    }
}

void XBee::printHexa(char c)
{
    char *msb = mail->alloc();
    *msb = c >> 4;
    char *lsb = mail->alloc();
    *lsb = c & 0xF;
    
    if (*msb < 10)
        *msb += 0x30;
    else
        *msb += 0x37;
        
    if (*lsb < 10)
        *lsb += 0x30;
    else
        *lsb += 0x37;
        
    char * str = "0x";
    pcPrint(str);
    mail->put(msb);
    mail->put(lsb);
    str = " ";
    pcPrint(str);
}

char XBee::SendATCommand(char firstChar, char secondChar, char *optionalParam, int paramLen)
{
    // Frame Type 0x08
    // Two char as parameters
    
    char cmdtosend[10];
    char sum = 0;
    int cmdlength = 8;
    int i = 0;
    
    cmdtosend[0] = FRAMEDELIMITER;
    cmdtosend[1] = 0x00;
    cmdtosend[2] = 0x04 + paramLen;
    cmdtosend[3] = 0x08;
    cmdtosend[4] = GetTransmissionNumber();
    cmdtosend[5] = firstChar;
    cmdtosend[6] = secondChar;
    
    // Ajouter les parametres au message
    if(optionalParam != NULL)
    {   
        i = 0;
        cmdlength += paramLen;
        
        while (i < paramLen)
        {
            cmdtosend[7 + i] = (optionalParam)[i];
            i++;
        }
        pcPrint("\r\n\0");
    }
    
    // Calculate checksum
    i = 3;
    while (i < (cmdlength - 1))
    {
        sum += cmdtosend[i];
        i++;
    }
    cmdtosend[cmdlength - 1] = 0xFF - sum;
    
    // Envoyer la commande sur UART
    i = 0;
    while (i < cmdlength)
    {
        comm.putc(cmdtosend[i]);
        i++;
    }
    
    wait(0.2);
    return cmdtosend[4];
}

void XBee::InterpretMessage()
{
    if (comm.readable())
    {
        char start = getChar(); // = FRAMEDELIMITER
        //assert
        if (start == FRAMEDELIMITER)
        {
            char len_msb = getChar();
            char len_lsb = getChar();
    
            int len = ((int) len_msb << 4) + (int) len_lsb;
            
            // Resolving frame type
            char type = getChar();
            len--;
            
            switch (type){
                case 0x88: ATCommandResponse(len);
                    break;
                case 0x8A: ModemStatus(len);
                    break;
                case 0x8B: ZigBeeTransmitStatus(len);
                    break;
                case 0x90: ZigBeeReceivePacket(len);
                    break;
                default: pcPrint("Please implement response of type ");
                    printHexa(type);
                    pcPrint("\r\n\0");
                    for (int i = 0; i <len; i++) 
                    {      
                        getChar();
                    }
            }
        }
        else
        {
            pcPrint("Not valid Frame\r\n");
        }
    }
}

void XBee::ATCommandResponse(int len)
{
    //char *receivedResponse = (char *)frameresponsemail->alloc();
    //receivedResponse[0] = FRAMEDELIMITER;
    //receivedResponse[1] = len >> 4;
    //receivedResponse[2] = len;
    //receivedResponse[3] = 0x88;
    
    char total = 0x88;
    char id;
    char command[2];
    char status;
    int i = 0;
    char data[255];
    char checksum = 0;
    
    id = getChar();
    
    command[0] = getChar();
    command[1] = getChar();
    total += command[0];
    total += command[1];
    
    status = getChar();
    
    len -= 4;
    
    pcPrint("ID:");
    printHexa(id);
    pcPrint(" response to command \0");
    printHexa(command[0]);
    printHexa(command[1]);
    pcPrint(" is \0");
    
    if (len == 0)
    {
        switch (status)
        {
            case 0 : pcPrint("OK"); break;
            case 1 : pcPrint("ERROR"); break;
            case 2 : pcPrint("Invalid Command"); break;
            case 3 : pcPrint("Invalid Parameter"); break;
            case 4 : pcPrint("Tx Failure"); break;
            default : pcPrint("Unknow error ..."); break;
        }
    }
    
    //receivedResponse[4] = id;
    //receivedResponse[5] = command[0];
    //receivedResponse[6] = command[1];
    //receivedResponse[7] = status;
    
    while (i < len)
    {
        if (comm.readable())
        {
            data[i] = getChar();
            //receivedResponse[8 + i] = data[i];
            total += data[i];
            printHexa(data[i]);
            i++;
        }
    }
    
    checksum = getChar();
    //receivedResponse[8 + i] = checksum;
    //frameresponsemail->put((char(*)[254])&receivedResponse[0]);
    
    // Verify checksum
    total += id;
    total += status;
    total += checksum;
    
    if (total != 0xFF)
    {
        pcPrint("Checksum is wrong\0");
    }
    pcPrint("\r\n\0");
}

void XBee::ModemStatus(int len)
{
    char status = getChar();
    
    switch (status){
        case 0 : pcPrint("Hardware reset\r\n\0"); break;
        case 1 : pcPrint("Watchdog timer reset\r\n\0"); break;
        case 2 : pcPrint("Joined network (routers and end devices)\r\n\0"); break;
        case 3 : pcPrint("Disassociated\r\n\0"); break;
        case 6 : pcPrint("Coordinator started\r\n\0"); break;
        case 7 : pcPrint("Network security key was updated\r\n\0"); break;
        case 0x0D : pcPrint("Voltage supply limit exceeded\r\n\0"); break;
        case 0x11 : pcPrint("Modem configuration changed while join in progress\r\n\0"); break;
        default : pcPrint("stack error\r\n\0"); break;
    }
    
    char checksum = getChar();
    
    checksum += 0x8A + status;
    
    if (checksum != 0xFF)
    {
        pcPrint("Checksum is wrong\r\n\0");
    }
}

void XBee::ZigBeeTransmitStatus(int len)
{
    char id = getChar();
    char msb = getChar();
    char lsb = getChar();
    char retry =  getChar();
    char status = getChar();
    char discovery = getChar();
    char checksum;
    
    pcPrint("Response to transmit #");
    printHexa(id);
    pcPrint(" is : ");
    
    if (status == 0)
    {
        pcPrint("Success\r\n");
    }
    else
    {
        switch (status){
            case 0x01 : pcPrint("MAC ACK Failure\r\n"); break;
            case 0x02 : pcPrint("CCA Failure\r\n"); break;
            case 0x15 : pcPrint("Invalid destination endpoint\r\n"); break;
            case 0x21 : pcPrint("Network ACK Failure\r\n"); break;
            case 0x22 : pcPrint("Not Joined to Network\r\n"); break;
            case 0x23 : pcPrint("Self-addressed\r\n"); break;
            case 0x24 : pcPrint("Address Not Found\r\n"); break;
            case 0x25 : pcPrint("Route Not Found\r\n"); break;
            case 0x26 : pcPrint("Broadcast source failed to hear a neighbor relay the message\r\n"); break;
            case 0x2B : pcPrint("Invalid binding table index\r\n"); break;
            case 0x2C : pcPrint("Resource error lack of free buffers, timers, etc.\r\n"); break;
            case 0x2D : pcPrint("Attempted broadcast with APS transmission\r\n"); break;
            case 0x2E : pcPrint("Attempted unicast with APS transmission, but EE=0\r\n"); break;
            case 0x32 : pcPrint("Resource error lack of free buffers, timers, etc.\r\n"); break;
            case 0x74 : pcPrint("Data payload too large\r\n"); break;
            default : pcPrint("Unknow error ...\r\n"); break;
        }
    }
    
    checksum = getChar();
    // Validate checksum TODO
}

void XBee::ZigBeeReceivePacket(int len)
{
    int i = 0;
    char adresse64bit[8];
    char adresse16bit[2];
    char receiveOptions;
    char checksum;
    char data = 0;
    char total = 0x90;
    
    printHexa(len+1); // DEBUG PRINT
    pcPrint(" On recoit :"); // DEBUG PRINT
    
    while(i < 8)
    {
        adresse64bit[i] = getChar();
        pcPrint(" "); // DEBUG PRINT
        printHexa(adresse64bit[i]); // DEBUG PRINT
        total += adresse64bit[i];
        i++;
    }
    
    adresse16bit[0] = getChar();
    adresse16bit[1] = getChar();
    
    total += adresse16bit[0];
    total += adresse16bit[1];
    
    pcPrint(" "); // DEBUG PRINT
    printHexa(adresse16bit[0]); // DEBUG PRINT
    pcPrint(" "); // DEBUG PRINT
    printHexa(adresse16bit[1]); // DEBUG PRINT
    
    receiveOptions = getChar();
    pcPrint(" "); // DEBUG PRINT
    printHexa(receiveOptions); // DEBUG PRINT
    
    total += receiveOptions;
    
    //printHexa(len - 11);
    //pcPrint(" Data received : ");
    
    i = 11;
    while (i < len)
    {
        data = getChar();
        total += data;
        pcPrint(" "); // DEBUG PRINT
        printHexa(data); // DEBUG PRINT
        i++;   
    }
    
    checksum = getChar();
    total += checksum;
    
    pcPrint(" "); // DEBUG PRINT
    printHexa(checksum); // DEBUG PRINT
    
    pcPrint("\r\n");
    
    if (total != 0xFF)
    {
        pcPrint("Checksum is wrong\0");
    }
    pcPrint("\r\n\0");
    // Validate checksum TODO
}

void XBee::ZigBeeTransmit(int adresse16, int adresse64msb, int adresse64lsb, char *data, int dataLength)
{
    // Frame Type 0x10
    // 0x0000000000000000 - Reserved 64-bit address for the coordinator
    // 0x000000000000FFFF - Broadcast address
    
    // The Transmit Status frame (0x8B) est la reponse
    char cmdtosend[25];
    char checksum = 0x00;
    int cmdlength = 18;
    int i = 3;
    
    //ID command to set/read operating 64 bit PAN ID
    //WR command to set operating 64 bit PAN ID across reboot
    //OI command to read operating 16 bit PAN ID
    //II command to set operating 16 bit PAN ID
    
    cmdtosend[0] = FRAMEDELIMITER;
    cmdtosend[1] = 0x00;
    cmdtosend[2] = 0x0E + dataLength;
    cmdtosend[3] = 0x10;        // Frame type
    cmdtosend[4] = 0x01;        // Frame number
    
    cmdtosend[5]  = (adresse64msb & 0xFF000000) >> 24;  // MSB adresse 64-bit 
    cmdtosend[6]  = (adresse64msb & 0x00FF0000) >> 16;
    cmdtosend[7]  = (adresse64msb & 0x0000FF00) >> 8;
    cmdtosend[8]  = adresse64msb & 0x000000FF;
    
    cmdtosend[9]  = (adresse64lsb & 0xFF000000) >> 24;
    cmdtosend[10] = (adresse64lsb & 0x00FF0000) >> 16;
    cmdtosend[11] = (adresse64lsb & 0x0000FF00) >> 8;
    cmdtosend[12] = adresse64lsb & 0x000000FF;          // LSB adresse 64-bit
    
    cmdtosend[13] = adresse16 >> 8;                     // MSB adresse 16-bit
    cmdtosend[14] = adresse16 & 0x00FF;                 // LSB adresse 16-bit
    cmdtosend[15] = 0x00;       // Broadcast Radius
    cmdtosend[16] = 0x00;       // Options
    
    // Set RF DATA
    if(data != NULL)
    {   
        i = 0;
        cmdlength += dataLength;
        
        while (i < dataLength)
        {
            cmdtosend[17 + i] = (data)[i];
            i++;
        }
    }
    
    // Calculate checksum
    i = 3;
    while (i < (cmdlength - 1))
    {
        checksum += cmdtosend[i];
        i++;
    }
    cmdtosend[cmdlength - 1] = 0xFF - checksum;
    
    // Envoyer la commande sur UART
    i = 0;
    pcPrint("On envoie :"); // DEBUG PRINT
    while (i < cmdlength)
    {
        comm.putc(cmdtosend[i]); // DEBUG PRINT
        pcPrint(" ");
        printHexa(cmdtosend[i]); // DEBUG PRINT
        i++;
    }
    pcPrint("\r\n"); // DEBUG PRINT
    wait(0.1);
}

void XBee::BroadcastHelloWorld()
{
    char hello[5] = {'H', 'e', 'l', 'l', 'o'};
    char world[5] = {'w', 'o', 'r', 'l', 'd'};
    
    while (1)
    {
        ZigBeeTransmit(0x0000, 0x00000000, 0x00000000, &hello[0], 5);
        ZigBeeTransmit(0x0000, 0x00000000, 0x00000000, &world[0], 5);
        wait(2);
    }
}