BraceletUS / Mbed 2 deprecated S05APP3

Dependencies:   ConfigFile EthernetInterface mbed-rtos mbed

Fork of S05APP3 by App S5

main.cpp

Committer:
benjaminroy
Date:
2017-02-14
Revision:
21:37a11c3659cc
Parent:
20:e96c9acfd2ea

File content as of revision 21:37a11c3659cc:

// Titre: S05APP3
// Auteurs: Benjamin Roy et Marc-Antoine Beaudoin
// Date: 14 février 2017
// =======================================================
// ===================== COORDINATOR =====================
// =======================================================
#include "EthernetInterface.h"
#include "ConfigFile.h"
#include "mbed.h"
#include "rtos.h"

AnalogOut errorLed(p18);
DigitalOut reset(p8);
EthernetInterface eth;
Mutex mutex;
Serial xbee(p13, p14);   // tx, rx
Serial pc(USBTX, USBRX); // tx, rx
TCPSocketConnection socket;
Ticker ticker1;
Thread *t1;

/* Boîte aux lettres */
typedef struct {
    uint8_t type;
    char strAccelerationX[15];
    char strAccelerationY[15];
    char strAccelerationZ[15]; 
    char strDryContact[15];      
} mail_t;

Mail<mail_t, 20> mail_box;

uint8_t routerAddress[8] = { 0 }; // Should be 00 13 A2 00 40 8B 41 6E
uint8_t startDelimiter = 0x7E;
uint16_t portNumber = 0;
uint16_t panId = 0;
char serverAddress[32];
char panIdChar[5];
char portNbr[5];

/*
* Imprime le buffer à l'écran pour des fins de déboguage:
*/
void printBuffer(uint8_t bufferSize, uint8_t* buffer) {
    for(uint8_t k = 0; k <= bufferSize; k++) {
        pc.printf("%X-", buffer[k]);
    }
    printf("\n");
}

/*
* Envoyer et recevoir des données via le protocole Xbee:
*/
uint8_t* readDataFromXbee(uint8_t bufferSize) {
    mutex.lock();
    uint8_t buffer[104] = { 0 };
    for (uint8_t i = 0; i <= bufferSize;) {
        if (xbee.readable()) {
            buffer[i] = xbee.getc();
            i++;
        }
    }
    mutex.unlock();
    return buffer;
}
void sendDataToXbee(uint8_t bufferSize, uint8_t* buffer) {
    for (uint8_t i = 0; i < bufferSize;) {
        if (xbee.writeable()) {
            xbee.putc(buffer[i]);
            i++; 
        }   
    }
}

/*
* Lecture du fichier de configuration:
*/
void readConfigFile() {
    LocalFileSystem local("local");
    ConfigFile cfg;
    char *serverAddressStr = "serverAddr";
    char *portNumberStr = "portNb";
    char *panIdStr = "panID";
    
    if (!cfg.read("/local/input.cfg")) { 
        error("Erreur dans la lecture du fichier de configuration...\n");
    } else {
        cfg.getValue(panIdStr, &panIdChar[0], sizeof(panIdChar));
        cfg.getValue(serverAddressStr, &serverAddress[0], sizeof(serverAddress));
        cfg.getValue(portNumberStr, &portNbr[0], sizeof(portNbr));

        portNumber = (uint16_t)strtol(portNbr, NULL, 10);
        panId = (uint16_t)strtol(panIdChar, NULL, 10);
        // printf("The server address is %s\n", serverAddress);
        // printf("The port number is %i\n", portNumber);
        // printf("The PAN ID is %i\n", panId);
    }
}

/*
* Détection et gestion des erreurs (allumer une LED pendant 1 seconde lorsqu'une erreur est détectée):
*/
void printError(char* buffer) {
    pc.printf(buffer);
    errorLed.write(3.3);
    wait(1);
    errorLed.write(0);
}

void readATCommandResponse(uint8_t* buffer) {
    if      (buffer[4] == 0x01)  printError("AT Command Response: Error.\n");
    else if (buffer[4] == 0x02)  printError("AT Command Response: Invalid Command.\n");
    else if (buffer[4] == 0x03)  printError("AT Command Response: Invalid Parameter.\n");
    else if (buffer[4] == 0x04)  printError("AT Command Response: Tx Failure.\n"); 
}

void readRemoteATCommandResponse(uint8_t* buffer) {
    if      (buffer[14] == 0x01) printError("Remote AT Command Response: Error.\n");
    else if (buffer[14] == 0x02) printError("Remote AT Command Response: Invalid Command.\n");
    else if (buffer[14] == 0x03) printError("Remote AT Command Response: Invalid Parameter.\n");
    else if (buffer[14] == 0x04) printError("Remote AT Command Response: Tx Failure.\n");
}

void readTransmitStatus(uint8_t* buffer) {
    if      (buffer[5] == 0x01) pc.printf("Transmit Status: An expedted MAC acknowledgement never occured. \n");
    else if (buffer[5] == 0x02) pc.printf("Transmit Status: CCA failure. \n");
    else if (buffer[5] == 0x03) pc.printf("Transmit Status: Packet was purgedwithoutbeing transmitted. \n");
    else if (buffer[5] == 0x04) pc.printf("Transmit Status: Physical error on the interface with the WiFi transceiver. \n");
    else if (buffer[5] == 0x18) pc.printf("Transmit Status: No buffers. \n");
    else if (buffer[5] == 0x21) pc.printf("Transmit Status: Expected networkacknowledgement never occured. \n");
    else if (buffer[5] == 0x22) pc.printf("Transmit Status: Not joined to network. \n");
    else if (buffer[5] == 0x23) pc.printf("Transmit Status: Self-addressed. \n");
    else if (buffer[5] == 0x24) pc.printf("Transmit Status: Address not found. \n");
    else if (buffer[5] == 0x25) pc.printf("Transmit Status: Route not found. \n");
    else if (buffer[5] == 0x26) pc.printf("Transmit Status: Broadcast relay was not heard. \n");
    else if (buffer[5] == 0x2B) pc.printf("Transmit Status: Invalid binding table index. \n");
    else if (buffer[5] == 0x2C) pc.printf("Transmit Status: Invalid Endpoint. \n");
    else if (buffer[5] == 0x31) pc.printf("Transmit Status: A software error occurred. \n");
    else if (buffer[5] == 0x32) pc.printf("Transmit Status: Resource Error. \n");
    else if (buffer[5] == 0x74) pc.printf("Transmit Status: Data payload too large. \n");
    else if (buffer[5] == 0x76) pc.printf("Transmit Status: Client socket creationat attempt failed. \n");
}

void readModemStatus(uint8_t* buffer) {
    if      (buffer[1] == 0x00) pc.printf("Modem status: Hardware reset.\n");
    else if (buffer[1] == 0x01) printError("Modem status: Watchdog timer reset.\n");
    else if (buffer[1] == 0x02) printError("Modem status: Joined network.\n");
    else if (buffer[1] == 0x03) printError("Modem status: Disassociated.\n");
    else if (buffer[1] == 0x04) printError("Modem status: Configuration error/synchronization.\n");
    else if (buffer[1] == 0x05) printError("Modem status: Coordinator realignment.\n");
    else if (buffer[1] == 0x06) pc.printf("Modem status: Coordinator started.\n");
    else if (buffer[1] == 0x07) printError("Modem status: Network security key updated.\n");
    else if (buffer[1] == 0x08) printError("Modem status: Network woke up.\n");
    else if (buffer[1] == 0x0C) printError("Modem status: Network went to sleep.\n");
    else if (buffer[1] == 0x0E) printError("Modem status: Device cloud connected.\n");
    else if (buffer[1] == 0x0F) printError("Modem status: Device cloud disconnected.\n");
    else if (buffer[1] == 0x11) printError("Modem status: Modem configurationchanged while join in progress.\n");
    else if (buffer[1] == 0x80) printError("Modem status: Stack error (80+).\n");
    else if (buffer[1] == 0x82) printError("Modem status: Send/join command issuedwithout connecting from AP.\n");
    else if (buffer[1] == 0x83) printError("Modem status: Access point not found.\n");
    else if (buffer[1] == 0x84) printError("Modem status: PSK not configured.\n");
}

/*
* Calculer et vérifier le checksum des trames reçues:
*/ 
uint8_t calculateChecksum(uint8_t frameTypeIndex, uint8_t frameSize, uint8_t* buffer) {
    char checksum = 0;
    
    for (int i = frameTypeIndex; i < frameSize - 1; i++) {
        checksum += buffer[i];
    }
    return (0xFF - checksum);      
}

bool checksumIsValid(uint8_t bufferSize, uint8_t* buffer) {
    uint32_t checkSum = 0;
    
    for (int i = 0; i < bufferSize; i++) {
        checkSum += buffer[i];
    }    
    if ((0xFF - (checkSum & 0xFF)) != buffer[bufferSize]) {
        pc.printf("Erreur dans la transmission de la trame -->  ");
        printBuffer(bufferSize, buffer);
        return false;
    }
    return true;
}

/*
* Faire allumer une DEL, reliée à un des ports du XBEE (DIO) du Routeur, en utilisant une commande de configuration à distance provenant du Coordinateur
* HIGH: {0x7E, 0x00, 0x10, 0x17, 0x01, 0x00, 0x13, 0xA2, 0x00, 0x40, 0x8B, 0x41, 0x6E, 0xFF, 0xFE, 0x02, 0x44, 0x34, 0x05, 0x3C};
* LOW:  {0x7E, 0x00, 0x10, 0x17, 0x02, 0x00, 0x13, 0xA2, 0x00, 0x40, 0x8B, 0x41, 0x6E, 0xFF, 0xFE, 0x02, 0x44, 0x34, 0x04, 0x3C}; 
*/ 
void toggleRouterLed() {
    bool led = false; 
    uint8_t command[20] = { 0 };

    Thread::signal_wait(0x2); // Attendre que l'adresse du noeud rooteur soit connue
    command[0] = startDelimiter;
    command[1] = 0x00;
    command[2] = 0x10;
    command[3] = 0x17;
    for (uint8_t i = 0; i < sizeof(routerAddress); i++) {
        command[i + 5] = routerAddress[i];
    }
    command[13] = 0xFF;
    command[14] = 0xFE;
    command[15] = 0x02;
    command[16] = 0x44;
    command[17] = 0x34;
    
    while(1) {
        Thread::signal_wait(0x1);   // Période: 1 Hz
        
        if (led) {
            command[4] = 0x01;
            command[18] = 0x05;
        } else {
            command[4] = 0x02;
            command[18] = 0x04;
        }
        command[19] = calculateChecksum(3, sizeof(command), command);

        sendDataToXbee(sizeof(command), command);
        led = !led;
    }
}

void sendDataToServer() {
    while(1) {
        osEvent evt = mail_box.get();
        
        if (evt.status == osEventMail) {
            mail_t *mail = (mail_t*)evt.value.p;
            
            int responseSize = 0;
            char buffer[50] = { 0 };
            
            if (mail->type == 0) {
                sprintf(buffer, "%s, %s, %s\0", mail->strAccelerationX, mail->strAccelerationY, mail->strAccelerationZ);
            } else {
                sprintf(buffer, "%s\0", mail->strDryContact);
            }
            
            printf("Envoye des serveurs: ");
            printBuffer(buffer, sizeof(buffer)-1);
            socket.send_all(buffer, sizeof(buffer)-1);
            responseSize = socket.receive(buffer, sizeof(buffer)-1);
            buffer[responseSize] = '\0';
            pc.printf("Server: %s\n", buffer);
            
            mail_box.free(mail);      
        }
    }
}

/*
* Lire et décomposer les trames reçues (adresse, données, status):
*/
void readRouterAddress(uint8_t* buffer) {
    for (uint8_t i = 0; i < 8; i++) {
        routerAddress[i] = buffer[i + 1];
    }
    t1->signal_set(0x02);
}

void readRouterData(uint8_t bufferSize, uint8_t* buffer) {
    uint16_t acc[3] = {0};

    if (buffer[0] == 0x90 && bufferSize == 18) { // Ajouter les données reçues par l'accéléromètre à la boîte aux lettres:
        for (uint8_t i = 12; i < bufferSize; i += 2) {
            acc[(i/2)-6] = (buffer[i+1] << 8 ) | (buffer[i] & 0xff);
        }
        mail_t *mail = mail_box.alloc();
        mail->type = 0;
        sprintf(mail->strAccelerationX, "X:%i\0", acc[0]);
        sprintf(mail->strAccelerationY, "Y:%i\0", acc[1]);
        sprintf(mail->strAccelerationZ, "Z:%i\0", acc[2]);
        mail_box.put(mail);
                        
    } else if (buffer[0] == 0x90 && bufferSize == 13) { // Ajouter les données reçues par le contact sec à la boîte aux lettres:
        mail_t *mail = mail_box.alloc();
        mail->type = 1;
        sprintf(mail->strDryContact, "Contact: %i\0", buffer[12]);
        mail_box.put(mail);
    }
}

void readDataFromRouter(){
    while(1) {
        if (xbee.readable() && xbee.getc() == startDelimiter) {
            uint8_t buffer[104] = { 0 };
            uint8_t bufferSize = (xbee.getc() << 8 ) | (xbee.getc() & 0xff);          
            memcpy(buffer, readDataFromXbee(bufferSize), bufferSize + 1);
            
            if (checksumIsValid(bufferSize, buffer)) {
                if (buffer[0] == 0x90) {                // Frame Type: 
                    printBuffer(bufferSize, buffer);
                    readRouterAddress(buffer);
                    readRouterData(bufferSize, buffer);
                } else if (buffer[0] == 0x8A) {         // Frame Type: Modem Status
                    readModemStatus(buffer);
                }  else if (buffer[0] == 0x8B) {        // Frame Type: Transmit Status   
                }  else if (buffer[0] == 0x97) {        // Frame Type: Remote AT Command Response
                    readRemoteATCommandResponse(buffer);
                }  else if (buffer[0] == 0x09) {        // Frame Type: AT Command Response
                    readATCommandResponse(buffer);
                }      
            }
        }
    }
}

/*
* Poser le ID du réseau PAN à rejoindre:
*/
void setCoordinatorPanId(uint16_t panId) {
    char _8bitsPanId[2] = { (panId >> 8) & 0xFF, panId & 0xFF };

    uint8_t setPanIdBuffer[] = { startDelimiter, 0x00, 0x06, 0x09, 0x01, 0x49, 0x44, _8bitsPanId[0], _8bitsPanId[1], 0x00 };
    uint8_t saveChangesBuffer[] = { startDelimiter, 0x00, 0x04, 0x09, 0x02, 0x57, 0x52, 0x4B };
    uint8_t applyChangesBuffer[] = { startDelimiter, 0x00, 0x04, 0x09, 0x03, 0x41, 0x43, 0x6F };
    setPanIdBuffer[sizeof(setPanIdBuffer) - 1] = calculateChecksum(0, sizeof(setPanIdBuffer), setPanIdBuffer); // Calculate the checksum
  
    sendDataToXbee(sizeof(setPanIdBuffer), setPanIdBuffer);         // Set the 64-bit PAN ID
    sendDataToXbee(sizeof(saveChangesBuffer), saveChangesBuffer);   // Save the changes 
    sendDataToXbee(sizeof(applyChangesBuffer), applyChangesBuffer); // Apply changes by sending the CN command
}

/*
* Envoyer un signal au thread qui fait clignoter la DEL du noeud routeur:
*/
void isr() { t1->signal_set(0x1); }

// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
int main() {
    pc.printf("Starting a coordinator... \n");
    
    reset = 0;
    wait_ms(1);
    reset = 1;
    wait_ms(1); 
    
    readConfigFile();          
    setCoordinatorPanId(panId);

    if (eth.init() != 0) { // Use DHCP
        pc.printf("Erreur d'initialisation du RJ45.\n");
    }
    if (eth.connect() != 0) {
        pc.printf("Erreur de connection du RJ45\n"); 
    } else {
        pc.printf("IP Address is %s\n", eth.getIPAddress());
    }
    
    int numberOfRetries = 0;
    while (socket.connect(serverAddress, portNumber) != 0) {
        if (numberOfRetries == 5) {
            error("Erreur dans la connection au socket.\n");
        }
        numberOfRetries++;
    } 
    
    // Démarrage des tâches:
    Thread _readDataFromRouter(readDataFromRouter);
    Thread _toggleRouterLed(toggleRouterLed);
    Thread _sendDataToServer(sendDataToServer);
    t1 = &_toggleRouterLed;
    
    ticker1.attach(&isr, 1);
    while(1) {}
}