The field version of the solarnano grid on the ionQubes

Fork of SolarNanoGridv3 by SONG Project

Battery/Battery.cpp

Committer:
defrost
Date:
2016-06-02
Revision:
5:57b06b4b47c6
Child:
8:0acda4f2e0a8

File content as of revision 5:57b06b4b47c6:

/**
 *@section DESCRIPTION
 * mbed SolarNanogrid  Library
 * Battery extends SolarNanoGrid.
 * Battery interacts with the lockers.
 * The ID must NOT end in 00.
 *@section LICENSE
 * Copyright (c) 2016, Malcolm McCulloch
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * @file "Battery.c"
 */
#include "Battery.h"

// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------

Battery::Battery(FILE* fp) : SolarNanoGrid(fp){
    DBG("Initialize class");

    // No other information needed from the config file
    fclose(fp);
    //
    // Setup variables
    //
    txFileName = (char*) calloc(80, 1);
    fullTxFilePath = (char*) calloc(80, 1);
    logDir = (char*) calloc(20, 1);
    sdBuffer = (char*) calloc(SDBUFFERSIZE, 1);

    //
    // Setup NRF
    //
    privateAddr = ((long long)communityID <<16)+ (id &0XFFFF);
    openAddr = privateAddr & 0xFFFFFFFF00;

    DBG("Channel %x  Address %llx Address Locker %llx", chan, privateAddr, openAddr);

    spiNrf();

    nrf->quickTxSetup(chan, openAddr);
    nrf->setRadio(0x01, 0x03); // 2MB/S  0dB
    nrf->setTxRetry(0x0F, 0x0F);
    nrfFlush();
    DBG("Nrf Details:");
#ifdef DEBUG
    nrf->printDetails();
#endif
    //
    // Setup logging directories
    //
    sprintf(logDir, "/sd/data/%02X%04X", (communityID&0XFF),(id&0XFFFF));
    DBG("  Log directory %s", logDir);
    spiSD();
    mkdir("/sd/data", 777);
    mkdir(logDir, 777);
    DBG("    made");
    //
    // Setup interrupts
    //
    button = new InterruptIn(SW2);
    button->fall(this, &Battery::intButton);

    nrfInt = new InterruptIn(PTC18);
    nrfInt->fall(this, &Battery::intNrf); // attach nrf interrupt.

    txWatch = new Ticker ();
    txWatch->attach(this,&Battery::retransmit,10.01);

    delay = new Timeout();

    loop();
}

// ------------------------------------------------------------------------
// Interrupt routines
// ------------------------------------------------------------------------

/**
 * When the button is pressed transmit something
 */
void Battery::intButton(){
    if (!maxRT){
        *ce = 1;
        if(checkedIn==0){
            checkIn();
        } else{
            flagNextFile = 1;
        }

    }
}

/**
 * Called when the nrf creates an interrupt.
 *
 */
void Battery::intNrf(){
    //  DBG("NRF Interrupt Started.");
    int pipe=0;
    int status=0;
    int width=0;

    //
    //Get status and pipe
    //
    spiNrf();
    status = nrf->checkStatus();
    pipe = (status >> 1);
    pipe = (pipe & 0x0007);

    //
    // Check if max RT is reached
    //
    if (((status >>MAX_RT)& 01) ==1) {
        maxRT=true;
        DBG("MAX RT flag is set.PTB20= %d status=%x",*ce,status);
        *ce = 0;
        DBG("PTB20= %d status=%x",*ce,status);
        nrf->clearStatus();
        *ledRed=0;
    }

    //
    // Check if data received
    //
    if (((status >>RX_DR)& 01) ==1) { // Received a packet
        width= nrf->getRxData(dataRx);
        dataRx[width]='\0';
        if (dataRx[0]!='S'){
            DBG("intNrf>D[p=%1d]=<%2s> ",pipe,dataRx);
        }
        maxRT=false;
        *ce = 1;
        nrf->clearStatus();
        switch (dataRx[0]) {
        case ('C'):{
            doCheckIn();
            flagNextFile = 1;
            break;}
        case ('D'):{
            flag = &flagSendFileName;
            delay->detach();
            delay->attach(this, &Battery::setFlag, 1.5);
            break;}
        case ('F'):{
            flag = &flagSendFileSize;
            countSD = 0;
            delay->detach();
            delay->attach(this, &Battery::setFlag, 1.50);
            break;}
        case ('S'):{
            flag = &flagSendFile;
            delay->detach();
            //  printf("%d\n\r",countSD%16);
            //delay->attach(this, &Battery::setFlag, 0.05);

            if (countSD % (SDBUFFERSIZE/32) == 0) {
                delay->attach(this, &Battery::setFlag, 1.5); // wait to write to SD card
            } else {
                delay->attach_us(this, &Battery::setFlag, 800);
            }
            countSD++;
            break;}
        case ('T'):{
            time_t now;
            sscanf (&dataRx[2],"%x",&now );
            set_time(now);
            now= time(NULL);
            struct tm * timeInf = localtime(&now);
            DBG ("Time is now: %04d-%02d-%02d %02d:%02d:%02d \n\r",timeInf->tm_year+1900,timeInf->tm_mon+1,timeInf->tm_mday,timeInf->tm_hour, timeInf->tm_min,timeInf->tm_sec);

            break;}

        }
    }
    if (((status >>TX_DS)& 01) ==1) {
        //  maxRT=false;
        nrf->flushTx();
        nrf->flushRx();
        //DBG(" TX_DS");
    }

    *ledBlue = !*ledBlue;
    *ledRed = !maxRT;
}

/**
 * Transmits the data and sets up a call back to check data sent 30s later.
 */

/**
 * Checks to see if transmit failed and then retransmit
 *
 */
void Battery::retransmit(){

    if (maxRT) {
        DBG("Retransmit");
        *ledRed=1;
        *ce = 1;
        maxRT=false;
        nrf->clearStatus();
        nrf->flushRx();
        nrf->retransmitData();
    }
}

// ------------------------------------------------------------------------
// Main routines
// ------------------------------------------------------------------------

/**
 * Checks in the Battery to the locker
 * Transmits "C ID"
 *
 */
void Battery::checkIn() {
    sprintf(dataTx, "C %04X", (int) (id&0XFFFF));
    DBG("Check into locker [%s]", dataTx);
    spiNrf();
    nrf->transmitData(dataTx, strlen(dataTx));
}

/**
 * Checks in the Battery to the locker
 * Acknowledge received.
 * Changes the TX pipe address.
 *
 */
void Battery::doCheckIn() {
    nrf->setTxAddress(privateAddr);
    checkedIn = 1;
    DBG("Checked into locker");
    DBG("Nrf Details:");
#ifdef DEBUG
    nrf->printDetails();
#endif
}
/**
 * Checks in the Battery to the locker
 * Acknowledge received.
 * Changes the TX pipe address.
 *
 */
void Battery::doCheckOut() {
    nrf->setTxAddress(openAddr);
    checkedIn = 0;
    DBG("Checked out of locker");
    DBG("Nrf Details:");
#ifdef DEBUG
    nrf->printDetails();
#endif
}

/**
 * Slow routines for Battery
 */
void Battery::loop() {
    while (1) {
        *ledGreen = !checkedIn;

        if (flagGetTime) {
            flagGetTime=0;
            getTime();

        }
        if (flagNextFile) {
            flagNextFile = 0;
            getTime();
            nextFileToTx();
            if (fileLength>0){
                INFO("Sending file %s.",txFileName)
                sendDirName();
            } else {
                INFO("No more files to send.")
            }
        }
        if (flagSendFileName) {
            flagSendFileName = 0;
            sendFileName();

        }
        if (flagSendFileSize) {
            flagSendFileSize = 0;
            sendFileSize();
        }
        if (flagSendFile) {
            flagSendFile = 0;
            sendFile();
        }
        if (flagSendFileDone) {
            flagSendFileDone = 0;
            sendFileDone();
            INFO("File sent <%s>",txFileName);
            flag = &flagNextFile;
            delay->detach();
            delay->attach(this, &Battery::setFlag, 2.5);
        }
        __WFI();
    }
}

/**
 * sends a request for time update.
 */
void Battery::getTime() {
    DBG("getTime");
    nrf->transmitData("T ",2);
}
/**
 * Selects the next file to transmit
 * Uses /sd/lastFileTx.txt to store the lst file transmitted
 */
void Battery::nextFileToTx() {

    DBG("> nextTxFile");

    char lastFileName[64];
    char fileName[64];
    char fn[40];
    unsigned int txLength;

    sdBuffPnt=0;// Tells sendFile to read from SD the first time.
    fileLength = 0;
    strcpy(txFileName, "");
    spiSD();
    // Read in last file name
    FILE *fp = fopen("/sd/lastFileTx.txt", "r");
    if (fp != NULL) {
        if (fscanf(fp, "%s %u", lastFileName, &txLength) != 2) {
            sprintf(lastFileName, "a");
        }
        fclose(fp);
    } else {
        sprintf(lastFileName, "a");
    }
    DBG("nextFileToTx>Last Filename=%s len=%u",lastFileName,txLength);
    // Open directory and read files
    DIR *dp;
    struct dirent *dirp;
    spiSD();
    dp = opendir(logDir);
    if (dp == NULL) {
        DBG("nextTxFile logdir %s is NULL", logDir);
    } else
        //read all directory and file names in current directory into filename vector
        while ((dirp = readdir(dp)) != NULL) {
            DBG("nextFileToTx> WHILE lst [%s]  dir [%s] %d",lastFileName, dirp->d_name,strcmp(lastFileName, dirp->d_name));

            if (strcmp(lastFileName, dirp->d_name) < 0) {
                strcpy(fileName, dirp->d_name);
                sprintf(txFileName, "%s/%s", logDir, dirp->d_name);
                fp = fopen(txFileName, "r");
                fseek(fp, 0L, SEEK_END);
                fileLength = ftell(fp);
                fclose(fp);
                DBG("CHOSEN %s old %s ", fileName, lastFileName );
                break;
            }
            if (strcmp(lastFileName, dirp->d_name) == 0) {

                strcpy(fileName, dirp->d_name);
                sprintf(fn, "%s/%s", logDir, dirp->d_name);
                fp = fopen(fn, "r");
                fseek(fp, 0L, SEEK_END);
                fileLength = ftell(fp);
                fclose(fp);
                if (txLength < fileLength) {
                    sprintf(txFileName, "%s/%s", logDir, dirp->d_name);
                    DBG("More to send is %s old %u new %u ", fileName, txLength,fileLength );
                    break;
                }
            }
            // test filename and if greater than last read then choose.
        }
    closedir(dp);
    if (strlen(txFileName) > 0) {
        strcpy(txFileName, fileName);
        sprintf(fullTxFilePath, "%s/%s", logDir, txFileName);
        fileLeft = fileLength;

    } else {
        fileLength =0;
    }
    DBG("nextTxFile> Next is [%s] length %d", txFileName, fileLength);

}
/**
 * Sends the directory name, allows the otherside to create.
 */

void Battery::sendDirName() {
    sprintf(dataTx, "D %s", logDir);

    DBG("send Dir Name [%s].\n\r", dataTx);

    spiNrf();
    nrf->transmitData(dataTx, strlen(dataTx));

}
/**
 * Sends the file name, if fileLength >0
 */

void Battery::sendFileName() {
    // delay->detach();
    if (fileLength < 1) {
        return;
    }
    sprintf(dataTx, "F %20s", txFileName);

    DBG("send File Name [%s] \n\r", dataTx);

    spiNrf();
    nrf->transmitData(dataTx, strlen(dataTx));
}

/**
 * Sends the file length to the locker - this is also the cue that the following bytes are the file.
 */
void Battery::sendFileSize() {
    if (fileLength < 1) {
        return;
    }
    filePointer = 0;
    sprintf(dataTx, "S %X", fileLength);


    DBG("send File size [%s]", dataTx);

    spiNrf();
    nrf->transmitData(dataTx, strlen(dataTx));
}

/**
 * Sends the file length to the locker - this is also the cue that the following bytes are the file.
 */
void Battery::sendFile() {

    //  printf("send File [%s] at %d  %d\n\r",fullTxFilePath,fileLength, fileLeft );

//  if (fileLength < 1) {
//      INFO("File Sent");
//      sdBuffPnt=0;
//      return;
//  }
    if (sdBuffPnt>=SDBUFFERSIZE){
        sdBuffPnt=0;
    }
    if (sdBuffPnt == 0) {
        spiSD();
        FILE *fp = fopen(fullTxFilePath, "rb");
        if (fp == NULL) {
            spiNrf();
            INFO("sendFile> File %s not found for reading",fullTxFilePath);
            return;
        }
        spiSD();
        fseek(fp, fileLength - fileLeft, SEEK_SET);
        sizeRead = fread(sdBuffer, 1,SDBUFFERSIZE, fp);
        fileLeft -= sizeRead;
        fclose(fp);
        //      printf("File %s %d \n\r",fullTxFilePath,sizeRead);
        spiNrf();

    }

    if ((count++) % 256 ==0) {
        DBG("W %d %d", fileLeft, sizeRead);
    }
    int size=32;
    if (sizeRead<32){
        size=sizeRead;
    }
    if ((fileLeft==0)&&(sizeRead==0)){
        sdBuffPnt=0;
        flagSendFileDone=1;
        DBG("Done sending");
    }else{
        sizeRead -= size;
        nrf->transmitData(&(sdBuffer[sdBuffPnt]), size);
        sdBuffPnt+=size;
    }


}

/**
 * Update the last file sent file
 */
void Battery::sendFileDone() {
    if (strlen(txFileName)>0){
        spiSD();
        FILE *fp = fopen("/sd/lastFileTx.txt", "w");
        if (fp != NULL) {
            fprintf(fp, "%s %u \n", txFileName, fileLength);
            fclose(fp);
            DBG("sendFileDone> updated lastFileTx.txt %s %u ", txFileName, fileLength);
        }else{
            INFO("sendFileDone> Cannot update file lastFiletx.txt");
        }
        spiNrf();

    }

}

/**
 * Sets the value pointed to by flag to 1.
 */
void Battery::setFlag() {
    if (flag != NULL) {
        *flag = 1;
    }
    flag = NULL;
}