The field version of the solarnano grid on the ionQubes

Fork of SolarNanoGridv3 by SONG Project

Revision:
5:57b06b4b47c6
Child:
9:541c2ae1cfec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Locker/Locker.cpp	Thu Jun 02 16:41:40 2016 +0000
@@ -0,0 +1,375 @@
+/**
+ *@section DESCRIPTION
+ * mbed SolarNanogrid  Library
+ * Locker extends SolarNanoGrid.
+ * Locker interacts with the batteries.
+ * The ID must 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 "Locker.c"
+ */
+#include "Locker.h"
+
+Locker::Locker(FILE* fp) :
+SolarNanoGrid(fp) {
+    DBG("Initialize class");
+    // No other information needed from the config file
+    fclose(fp);
+
+    battIn = (char *) calloc(256, 1);
+    battPipes = (char *) calloc(6, 1);
+    for (int i = 0; i < 4; i++) {
+        dirNames[i] = (char *) calloc(32, 1);
+        fileNames[i] = (char *) calloc(32, 1);
+    }
+
+    temp  = (char *) calloc(64, 1);
+    timeValue = (char *) calloc(32, 1);
+    sdBuffer = (char *) calloc(SDBUFFERSIZE,1);
+    doOneSecond();
+    //
+    // Setup NRF
+    //
+    openAddr = ((long long) communityID << 16) + (id & 0XFFFF);
+    addrUtil = openAddr & 0XFFFFFF0000 | 0xFE00;
+
+    DBG("  Channel:%x, Address %x Util Address %x", chan, openAddr, addrUtil);
+
+    setAsRX()
+    DBG("Nrf Details:");
+#ifdef DEBUG
+    nrf->printDetails();
+#endif
+
+    //
+    // Interrupts
+    //
+
+    nrfInt = new InterruptIn(PTC18);
+    nrfInt->fall(this, &Locker::intNrf); // attach nrf interrupt.
+
+    button = new InterruptIn(SW2);
+    button->fall(this, &Locker::intButton);
+
+    rxWatch = new Ticker();
+    rxWatch->attach(this, &Locker::intRxClean, 30.14151);
+
+    oneSecond = new Ticker();
+    oneSecond->attach(this, &Locker::intOneSecond, 1.0);
+
+    loop();
+}
+
+// Protected
+
+// ------------------------------------------------------------------------
+// Interrupt routines
+// ------------------------------------------------------------------------
+
+void Locker::intOneSecond() {
+    flagOneSecond = 1;
+}
+
+void Locker::doOneSecond() {
+    now = time(NULL);
+    sprintf(timeValue, "T %x", now);
+    *ledGreen = !*ledGreen;
+
+    //  DBG("One second: %s", timeValue);
+}
+/**
+ * called when the nrf creates an interrupt.
+ *
+ */
+void Locker::intNrf() {
+
+    int bID = 0;
+    int status = 0;
+    //
+    //Get status and pipe
+    //
+    spiNrf();
+    status = nrf->checkStatus();
+    pipe = (status >> 1);
+    pipe = (pipe & 0x0007);
+
+    //
+    // Check if data received
+    //
+    if (((status >> RX_DR) & 01) == 1) { // Received a packet
+        // Get the data
+        width = nrf->getRxData(dataRx);
+        dataRx[width] = '\0';
+        //Process the acknowledge
+        if ((pipe>=2)&&(battIn[battPipes[pipe - 2]] == SENDING)) { // A file is being transferred.
+            nrf->acknowledgeData("S ", 2, pipe);
+            flagNrf = 1;
+        } else if (dataRx[0] == 'T') {
+            // Sends the time - this is updated in doOneSecond()
+            nrf->acknowledgeData(timeValue, strlen(timeValue), pipe);
+        } else  {
+            nrf->acknowledgeData(dataRx, 2, pipe);
+            DBG("intNrf>%s %x",dataRx,bID);
+        }
+        if (pipe == 1) { // Open channel
+            if (dataRx[0] == 'C') { //Request for check in
+                int battID;
+                sscanf(&dataRx[2], "%x", &battID);
+                bID = battID & 0x00ff;
+                if (battIn[bID] == CHECKED_OUT) {
+                    battIn[bID] = CHECKED_IN;
+                    DBG("intNrf>Check in %d", bID);
+                } else {
+                    WARN("Battery %04X is already checked in.", battID);
+                }
+                flagRotate = 1;
+            }
+        }else if (pipe>1) {
+            flagNrf = 1;
+        }
+
+        lastRxTme = now;
+    }
+
+    //  DBG("intNRF");
+    nrf->clearStatus();
+    *ledBlue = !*ledBlue;
+
+}
+
+/**
+ * Responds to the received signals from Master and Batteries
+ */
+void Locker::doNrf()
+{
+    //DBG("doNrf>>");
+    // Now check which pipe
+    if (pipe>1) { //A battery
+        int bID = battPipes[pipe]; // get battery ID from pipe.
+        int p = pipe-2;
+        if (battIn[battPipes[p]] == SENDING) {
+            saveFile(p,dataRx,width);
+        } else {
+            switch (dataRx[0]) {
+            case ('D'): { // Directory name.
+                *ce = 0;
+                sscanf (&dataRx[2],"%s",&(dirNames[p][0]));
+                spiSD();
+                DBG("doNrf>>>Making dir %s:",dirNames[p]);
+                int ok = mkdir(dirNames[p],777);
+                spiNrf();
+                DBG("doNrf>>>Directory name[%d] = <%s> OK=%d",p,dirNames[p],ok);
+                *ce = 1;
+                break;
+            }
+            case ('F'): { // File name
+                *ce = 0;
+                strncpy(&fileNames[p][0],&dataRx[2],30);
+                //  sscanf (&dataRx[2],"%20s",&fileNames[p][0]);
+                sprintf(temp,"%s/%s",dirNames[p],fileNames[p]);
+                DBG("doNrf>>> Creating File name<%s>",temp);
+                spiSD();
+                // Make sure file is created and reset
+                FILE *fp = fopen(temp,"wb");
+                fclose(fp);
+                spiNrf();
+                DBG("doNrf>>>File name[%d] = <%s>",p,fileNames[p]);
+                *ce = 1;
+                break;
+
+            }
+            case ('S'): { // File name
+                battIn[battPipes[p]] = SENDING;
+                sscanf (&dataRx[2],"%x",&lengthFile[p]);
+                sdBuffPnt=0; // set buffer to start
+                DBG("doNrf>>>File Length[%d] = <%u>",p,lengthFile[p]);
+                break;
+
+            }
+
+            }
+        }
+
+    }
+}
+
+/**
+ * When the button is pressed print status
+ */
+void Locker::intButton() {
+    DBG("int Button");
+    intRxClean();
+}
+
+/**
+ * Cleans the receiver
+ */
+void Locker::intRxClean() {
+    if (now - lastRxTme>60){
+        nrfFlush();
+        wait(0.01);
+        nrfFlush();
+        DBG("intRxClean < status=%x", nrf->checkStatus());
+    }
+}
+
+
+// Loop through slow routines
+
+void Locker::loop(void) {
+    while (1) {
+        if (flagRotate == 1) {
+            flagRotate = 0;
+            DBG("R");
+
+            doRotate();
+        }
+        if (flagNrf == 1) {
+            flagNrf = 0;
+            doNrf();
+        }
+        if (flagOneSecond == 1) {
+            flagOneSecond = 0;
+            doOneSecond();
+        }
+
+        __WFI();
+    };
+
+}
+/**
+ * Rotates one battery the ON_AIR batteries.
+ */
+void Locker::doRotate() {
+    DBG("Rotate");
+
+    // Select battery
+    for (int b = 0; b < 255; b++, battQP++) {
+        battQP %= 256;
+        //INFO(" Bat %d stat %d",battQP,battIn[battQP]);
+        if (battIn[battQP] == CHECKED_IN) {
+            pipeQP = (pipeQP) % 4;
+            for (int p = 0; p < 4; p++) {
+                // Select pipe
+
+                if ((battPipes[pipeQP] == 0)
+                        && (battIn[battPipes[pipeQP]] != SENDING)) {
+                    // Remove existing battery from pipes and place back in queue
+                    if (battIn[battPipes[pipeQP]] == ON_AIR) {
+                        battIn[battPipes[pipeQP]] = CHECKED_IN;
+                    }
+                    battPipes[pipeQP] = battQP; // New battery in
+                    battIn[battQP] = ON_AIR;
+                    // int address = (addrBattery & 0XFFFFFF00)|battQP;
+                    long long address = openAddr | battQP;
+                    nrf->setRxAddress(address, pipeQP + 2);
+                    nrf->setPwrDown();
+                    nrf->setPwrUp();
+                    DBG("=====> Rotate battQ %d pipeQ %d Addr %X", battQP,
+                            pipeQP, address);
+                    DBG("Nrf Details:");
+#ifdef DEBUG
+                    nrf->printDetails();
+#endif
+                    break;
+                };
+                pipeQP = (pipeQP + 1) % 4;
+            }
+            break;
+        }
+
+    }
+
+}
+/**
+ * Take the info and saves to a file via a buffer.
+ **/
+void Locker::saveFile (int p,char *data, int width)
+{
+    *ledRed=!*ledRed;
+    memcpy (&sdBuffer[sdBuffPnt],data,width);
+    sdBuffPnt += width;
+    lengthFile[p] -= width;
+
+    //INFO("%d",lengthFile[p]);
+    if (   lengthFile[p] <=0) {
+        flushSDBuffer(p);
+        sdBuffPnt=0; // reset for next one
+        battIn[battPipes[p]] = ON_AIR;
+        INFO("saveFile> File saved: %s/%s ",dirNames[p], fileNames[p]);
+        *ledRed=1;
+        return;
+    }
+
+
+    if (sdBuffPnt >= SDBUFFERSIZE) {
+        DBG("Left %u",lengthFile[p]);
+        flushSDBuffer(p);
+        sdBuffPnt=0;
+
+    }
+
+}
+/**
+ * writes the sdbuffer to file
+ */
+void Locker::flushSDBuffer(int p)
+{
+    //INFO("z");
+    Timer t;
+    t.start();
+    strcpy(temp,dirNames[p]);
+    strcat(temp,"/");
+    strcat(temp,fileNames[p]);
+    //DBG("SD W %s",temp);
+    spiSD();
+    FILE *fp = fopen(temp,"ab");
+    if (fp!=NULL) {
+        fwrite(sdBuffer,1,sdBuffPnt,fp);
+        sdBuffPnt=0;
+        fclose(fp);
+    } else {
+        ;
+    }
+    spiNrf();
+    t.stop();
+    DBG("flush> Timer = %d ms %d us",t.read_ms(), t.read_us())
+}
+
+/**
+ * Set NRF as RX
+ */
+void Locker::setAsRX(){
+
+    spiNrf();
+    nrf->quickRxSetup(chan, addrUtil); // Pipe 0
+    nrf->setRxAddress(openAddr, 1); //Default battery pipe address 1
+    nrf->setRadio(0x01, 0x03); // 2MB/S  0dB
+    nrfFlush();
+}
+
+/**
+ * Set NRF as TX
+ */
+void Locker::setAsTX(){
+    spiNrf();
+
+}