* Routeur

Dependencies:   ConfigFile mbed MMA8452 mbed-rtos

Fork of S05APP3_routeur by Benjamin Roy

main.cpp

Committer:
benjaminroy
Date:
2017-02-14
Revision:
15:42879340d625
Parent:
14:ef95f6bce079

File content as of revision 15:42879340d625:

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

#define MMA8452_CTRL_REG_1 0x2A
#define MMA8452_ADDRESS1 0x3A
#define MMA8452_OUT_X_MSB 0x01
#define MMA8452_OUT_Y_MSB 0x03
#define MMA8452_OUT_Z_MSB 0x05
#define MMA8452_WHO_AM_I 0x0D

Accelerometer_MMA8452 mma8452(p28, p27, 100);
AnalogOut errorLed(p18);
DigitalOut reset(p8);
DigitalIn btn(p15);
I2C i2c(p28, p27);          // SDA, SCL
Mutex mutex;
Mutex mutex2; 
Mutex mutex3;  
Serial xbee(p13, p14);      // tx, rx
Serial pc(USBTX, USBRX);    // tx, rx
Ticker ticker1;
Ticker ticker2;
Thread *t1;
Thread *t2;

/* Boîte aux lettres */
typedef struct {
    uint8_t data[40];
} mail_t;

Mail<mail_t, 50> mail_box;

int16_t (*functionPointers[4])();
uint16_t panId = 0;
uint16_t dryContactPeriod = 0;
uint16_t accelerometerPeriod = 0;
uint8_t coordinatorAddress[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t startDelimiter = 0x7E;
uint8_t accFrameId = 0x01;
uint8_t dryContactFrameId = 0x02;
char panIdChar[5];
char dryContactPeriodChar[5];
char accelerometerPeriodChar[5];

/*
* Imprimer 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]);
    }
    pc.printf("\n");
}

/*
* Envoyer et recevoir des données via le protocole Xbee:
*/
uint8_t* readDataFromXbee(uint8_t bufferSize) {
    uint8_t buffer[104] = { 0 };
    for (uint8_t i = 0; i <= bufferSize;) {
        if (xbee.readable()) {
            buffer[i] = xbee.getc();
            i++;
        }
    }
    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 *panIdStr = "panID";
    char *accPeriodStr = "accelerometerPeriod";
    char *dryContactStr = "dryContactPeriod";
    
    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(dryContactStr, &dryContactPeriodChar[0], sizeof(dryContactPeriodChar));
        cfg.getValue(accPeriodStr, &accelerometerPeriodChar[0], sizeof(accelerometerPeriodChar));

        panId = (uint16_t)strtol(panIdChar, NULL, 10);
        dryContactPeriod = (uint16_t)strtol(dryContactPeriodChar, NULL, 10);
        accelerometerPeriod = (uint16_t)strtol(accelerometerPeriodChar, NULL, 10);
        // printf("The PAN ID is %i\n", panId);
        // printf("Period of accelerometer: %i\n", accelerometerPeriod);
        // printf("Period of the dry contact: %i\n", dryContactPeriod);
    }
}

/*
* 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");
}

uint8_t* split16bitsData(uint16_t acc) {
    union {
        uint16_t u16_value;
        uint8_t  u8_value[2];
    } data;

    data.u16_value = acc;
    return data.u8_value;
}

/*
* Lecture des données transmises par l'accéléromètre et le contact sec:
*/
int16_t readXAcceleration() {
    int16_t temp; 
    char addr[1] = { MMA8452_OUT_X_MSB };
    char XAcceleration[2] = { 0 };
        
    i2c.write(MMA8452_ADDRESS1, addr, 1, true);
    i2c.read(MMA8452_ADDRESS1, &XAcceleration[0], 2);

    ((char*)&temp)[0] = XAcceleration[1];
    ((char*)&temp)[1] = XAcceleration[0];
    return (temp >> 4);
}

int16_t readYAcceleration() {
    int16_t temp; 
    char addr[1] = { MMA8452_OUT_Y_MSB };
    char YAcceleration[2] = { 0 };
        
    i2c.write(MMA8452_ADDRESS1, addr, 1, true);
    i2c.read(MMA8452_ADDRESS1, &YAcceleration[0], 2);

    ((char*)&temp)[0] = YAcceleration[1];
    ((char*)&temp)[1] = YAcceleration[0];
    return (temp >> 4);
}

int16_t readZAcceleration() {
    int16_t temp; 
    char addr[1] = { MMA8452_OUT_Z_MSB };
    char ZAcceleration[2] = { 0 };
        
    i2c.write(MMA8452_ADDRESS1, addr, 1, true);
    i2c.read(MMA8452_ADDRESS1, &ZAcceleration[0], 2);

    ((char*)&temp)[0] = ZAcceleration[1];
    ((char*)&temp)[1] = ZAcceleration[0];
    return (temp >> 4);
}

int16_t readDryContact() {
    return btn;
}

/*
* Calculer et vérifier le checksum des trames reçues:
*/ 
uint8_t calculateChecksum(uint8_t frameTypeIndex, uint8_t bufferSize, uint8_t* buffer) {
    uint32_t checksum = 0;

    for (uint8_t i = frameTypeIndex; i < bufferSize - 1; i++) {
        checksum += buffer[i];
    }

    return (uint8_t)(0xFF - (checksum & 0xFF));      
}

bool checksumIsValid(uint8_t bufferSize, uint8_t* buffer) {
    uint32_t checkSum = 0;
    
    for (uint8_t 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;
}

void sendDataToCoordinator() {        
    while (true) {
        osEvent evt = mail_box.get();
        
        if (evt.status == osEventMail) {
            mail_t *mail = (mail_t*)evt.value.p;
            sendDataToXbee(sizeof(mail->data), mail->data);
            mail_box.free(mail);
        } 
    }
}

void addDataToMemPool(uint8_t bufferSize, uint8_t* buffer, uint8_t frameId) {
    printBuffer(bufferSize, buffer);
    
    mail_t *mail = mail_box.alloc();
    for (uint8_t i = 0; i < bufferSize; i++) {
        mail->data[i] = buffer[i];
    }
    mail_box.put(mail);
}

void sendDryContactToMemPool() {
    while(true) {
        Thread::signal_wait(0x1);
        
        mutex2.lock();
        int16_t dryContact = functionPointers[0] ();        
        uint8_t buffer[19] = { 0 };    
        
        buffer[0] = startDelimiter;             // Start Delimiter
        buffer[1] = 0x00;                       // Length
        buffer[2] = 0x0F;                       // Length
        buffer[3] = 0x10;                       // Frame Type
        buffer[4] = dryContactFrameId;          // Frame ID
        buffer[5] = coordinatorAddress[0];      // 64 bit adress
        buffer[6] = coordinatorAddress[1];      // 64 bit adress
        buffer[7] = coordinatorAddress[2];      // 64 bit adress
        buffer[8] = coordinatorAddress[3];      // 64 bit adress
        buffer[9] = coordinatorAddress[4];      // 64 bit adress
        buffer[10] = coordinatorAddress[5];     // 64 bit adress
        buffer[11] = coordinatorAddress[6];     // 64 bit adress
        buffer[12] = coordinatorAddress[7];     // 64 bit adress
        buffer[13] = 0xFF;                      // 16 bit adress
        buffer[14] = 0xFE;                      // 16 bit adress
        buffer[15] = 0x00;                      // Broadcast radius
        buffer[16] = 0x00;                      // Options
        buffer[17] = dryContact;                // RF Data...
        buffer[18] = calculateChecksum(3, sizeof(buffer), buffer); // Checksum
    
        mutex.lock();
        addDataToMemPool(sizeof(buffer), buffer, buffer[4]);
        mutex.unlock();
        mutex2.unlock();
    }
}

void sendXYZAccelerationsToMemPool() {
    while (true) {
        Thread::signal_wait(0x1);
        
        mutex3.lock();
        int16_t accX = std::abs(functionPointers[1]());
        int16_t accY = std::abs(functionPointers[2]());
        int16_t accZ = std::abs(functionPointers[3]());
        //printf("Acceleration X: %i\n", accX); 
        //printf("Acceleration Y: %i\n", accY);
        //printf("Acceleration Z: %i\n", accZ);
        
        uint8_t buffer[24] = { 0 };   
        uint8_t* XAcceleration = split16bitsData(accX);
        uint8_t* YAcceleration = split16bitsData(accY);
        uint8_t* ZAcceleration = split16bitsData(accZ);
        
        buffer[0] = startDelimiter;             // Start Delimiter
        buffer[1] = 0x00;                       // Length
        buffer[2] = 0x14;                       // Length
        buffer[3] = 0x10;                       // Frame Type
        buffer[4] = accFrameId;                 // Frame ID
        buffer[5] = coordinatorAddress[0];      // 64 bit adress
        buffer[6] = coordinatorAddress[1];      // 64 bit adress
        buffer[7] = coordinatorAddress[2];      // 64 bit adress
        buffer[8] = coordinatorAddress[3];      // 64 bit adress
        buffer[9] = coordinatorAddress[4];      // 64 bit adress
        buffer[10] = coordinatorAddress[5];     // 64 bit adress
        buffer[11] = coordinatorAddress[6];     // 64 bit adress
        buffer[12] = coordinatorAddress[7];     // 64 bit adress
        buffer[13] = 0xFF;                      // 16 bit adress
        buffer[14] = 0xFE;                      // 16 bit adress
        buffer[15] = 0x00;                      // Broadcast radius
        buffer[16] = 0x00;                      // Options
        buffer[17] = XAcceleration[0];          // RF Data...
        buffer[18] = XAcceleration[1];          // RF Data...
        buffer[19] = YAcceleration[0];          // RF Data...
        buffer[20] = YAcceleration[1];          // RF Data...
        buffer[21] = ZAcceleration[0];          // RF Data...
        buffer[22] = ZAcceleration[1];          // RF Data...
        buffer[23] = calculateChecksum(3, sizeof(buffer), buffer); // Checksum

        mutex.lock();
        addDataToMemPool(sizeof(buffer), buffer, buffer[4]);
        mutex.unlock();
        mutex3.unlock();
    }
}

/*
* Lire et décomposer les trames reçues:
*/
void readDataFromCoordinator(){
    while(1) {
        uint8_t buffer[104] = { 0 };
    
        if (xbee.readable() && xbee.getc() == startDelimiter) {
            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: 
     
                } else if (buffer[0] == 0x8A) {         // Frame Type: Modem Status
                    readModemStatus(buffer);
                } else if (buffer[0] == 0x8B) {         // Frame Type: Transmit Status
                    readTransmitStatus(buffer);
                } else if (buffer[0] == 0x97) {         // Frame Type: Remote AT Command Response
                    
                } else if (buffer[0] == 0x09) {         // Frame Type: AT Command Response
                    readATCommandResponse(buffer);
                }      
            } 
        }
    }
}

/*
* Poser le ID du réseau PAN à rejoindre:
*/
void setRouterPanId(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
}

/*
* 
*/
void wakeupThread1() { t1->signal_set(0x1); }
void wakeupThread2() { t2->signal_set(0x1); }

// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------
int main() {
    printf("Starting a router...\n");    
    
    reset = 0;
    wait_ms(1);
    reset = 1;
    wait_ms(1);
    
    mma8452.init();
    mma8452.activate();
    
    readConfigFile();
    setRouterPanId(panId);
    
    functionPointers[0] = readDryContact;
    functionPointers[1] = readXAcceleration;    
    functionPointers[2] = readYAcceleration;
    functionPointers[3] = readZAcceleration;
    
    // Démarrage des tâches...
    Thread _readDryContact(sendDryContactToMemPool);
    Thread _readAccelerations(sendXYZAccelerationsToMemPool);
    Thread _sendDataToCoordinator(sendDataToCoordinator);
    Thread _readDataFromCoordinator(readDataFromCoordinator);
    t1 = &_readDryContact;
    t2 = &_readAccelerations;
    
    ticker1.attach(&wakeupThread1, dryContactPeriod);
    ticker2.attach(&wakeupThread2, accelerometerPeriod);
    while (1) {}
}