The field version of the solarnano grid on the ionQubes

Fork of SolarNanoGridv3 by SONG Project

Battery/Battery.cpp

Committer:
defrost
Date:
2016-06-13
Revision:
17:dc19b3b39790
Parent:
13:de43f28c0365
Child:
18:be77ad141fac

File content as of revision 17:dc19b3b39790:

/**
 *@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"
#define FUNCNAME "BATTERY"
#include "defs.h"

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

Battery::Battery(FILE* fp, Serial *pc) : SolarNanoGrid(fp,pc){
    DBG("Initialize class");
    // ***** Variable initialisation *****
    // Public variable initialisation

    maxChargeRate=1.0; // Charge rate in amps

    // Protected variables initialisation
    count=0;
    sizeRead=0;
    fileLength=0;
    filePointer=0;
    fileLeft=0;

    sdBuffPnt=0;
    /**
     * Open channel address of the locker
     */
    openAddr=0;

    /**
     * Private channel address of the locker
     */
    privateAddr=0;

    countSD=0;

    // Protected flags: *
    checkedIn=0;
    flagGetTime=0;
    flagNextFile=0;
    flagSendFileName=0;
    flagSendFileSize=0;
    flagSendFile=0;
    flagSendFileDone=0;
    flagGetMaxCharge=0;
    sendingFile=0;
    startCharge = false;

    // Protected interrupts
    button=NULL;
    txWatch=NULL;
    delay=NULL;

    //Private variables initialisation
    maxRT=false;

    // ***** End of  variables initialisation *****

    // 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",(unsigned int) *ce,status);
        *ce = 0;
        DBG("PTB20= %d status=%x",(unsigned int) *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;
            DBG("Flag Set");
            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;}


        case ('M'):{
            time_t now;
            sscanf (&dataRx[2],"%f",&maxChargeRate );
            if(maxChargeRate>2.0f){
                maxChargeRate=2.0f;
            }
            if (maxChargeRate<0.0f){
                maxChargeRate=0.0f;
            }
            DBG ("Max charge %f \n\r",maxChargeRate);

            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();
    }
    if ((!sendingFile)&&(checkedIn == 1)){
        flagGetTime=1;
        flagGetMaxCharge=1;
    }
}

// ------------------------------------------------------------------------
// 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() {

    *ledGreen = !checkedIn;
    

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

    }
    if (flagGetMaxCharge) {
        flagGetMaxCharge=0;
        requestMaxCharge();

    }
    if (flagNextFile) {
        flagNextFile = 0;
        DBG("NextFile called");
        requestTime();
        nextFileToTx();
        if (fileLength>0){
            INFO("Sending file %s.",txFileName)
            sendDirName();
        } else {
            sendingFile=0;
            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);
    }

}

/**
 * sends a request for time update.
 */
void Battery::requestTime() {
    DBG("getTime");
    nrf->transmitData("T ",2);
}

/**
 * sends a request for time update.
 */
void Battery::requestMaxCharge() {
    DBG("getTime");
    nrf->transmitData("M ",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;
    }
    sendingFile=1;
    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");
        startCharge = true;
    }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;
}


/**
 * Returns the max current that can be drawn from the system, in amps
 */

float Battery::getMaxCurrent(){
    return maxChargeRate;
}

/**
 * returns a string of the log directory
 */
char* Battery::getLogDirectory(){

    return logDir;
}

/**
 * Returns true if we are authorized to start charging.
 */
bool Battery::startCharging(void){
    return startCharge;
}

bool Battery::isCheckedIn(void){
    if(checkedIn == 1){
        return true;
    }else{
        return false;
    }
}