The field version of the solarnano grid on the ionQubes

Fork of SolarNanoGridv3 by SONG Project

Revision:
5:57b06b4b47c6
Child:
8:0acda4f2e0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Battery/Battery.cpp	Thu Jun 02 16:41:40 2016 +0000
@@ -0,0 +1,534 @@
+/**
+ *@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;
+}