The field version of the solarnano grid on the ionQubes

Fork of SolarNanoGridv3 by SONG Project

Locker/Locker.cpp

Committer:
defrost
Date:
2016-09-06
Revision:
36:a5620262f296
Parent:
28:e85a86fc8b59

File content as of revision 36:a5620262f296:

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

Locker::Locker(FILE* fp,Serial *pc) :
    SolarNanoGrid(fp,pc)
{
    DBG("Initialize class locker");


    // ***** variables initialization *****

    // Protected variables: *
    /**
     * Open channel address of the locker
     */
    openAddr=0;

    /**
     * Channel address for Utility
     */
    addrUtil=0;
    /**
     * Array of battery states
     */
    sdBuffPnt=0;
    battQP=0; // Battery queue pointer
    pipeQP=0; // pipe q pointer (Add 2)
    pipe = 0;
    width = 0;
    now=0;
    lastRxTme=0;
    maxCharge=1.0;

    // flags
    flagRotate=false;
    flagNrf=0;
    flagOneSecond=0;

    // ***** end of varibale initialization *****

    // No other information needed from the config file
    fclose(fp);
    DBG("Close file");

    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);
    maxChargeValue= (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 %llx Util Address %llx", chan, openAddr, addrUtil);

    setAsRX(addrUtil);
    nrf->setRxAddress(openAddr, 1); //Default battery pipe address 1

    DBG("Nrf Details:");
#ifdef DEBUG
    nrf->printDetails();
#endif
    //
    //Pods
    //
    pods[0]=new DigitalOut(PTE24,0);
    pods[1]=new DigitalOut(PTE25,0);
    pods[2]=new DigitalOut(PTD1,0);
    pods[3]=new DigitalOut(PTD3,0);
    pods[4]=new DigitalOut(PTD2,0);
    pods[5]=new DigitalOut(PTD0,0);
    pods[6]=new DigitalOut(PTC4,0);
    pods[7]=new DigitalOut(PTE26,0);
    pods[8]=new DigitalOut(PTC5,0);
    pods[9]=new DigitalOut(PTC7,0);
    pods[10]=new DigitalOut(PTC0,0);
    pods[11]=new DigitalOut(PTC9,0);
    pods[12]=new DigitalOut(PTC8,0);
    pods[13]=new DigitalOut(PTC1,0);
    pods[14]=new DigitalOut(PTB19,0);
    pods[15]=new DigitalOut(PTB18,0);



    //
    // 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);
    sprintf(maxChargeValue,"M %4.2f",maxCharge);

    *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;
            DBG("A file is being transferred");
        } else if (dataRx[0] == 'T') {
            // Sends the time - this is updated in doOneSecond()
            nrf->acknowledgeData(timeValue, strlen(timeValue), pipe);
            DBG("Send Time in acknowledge");
        } else if (dataRx[0] == 'M') {
            // Sends the maxCharge value - this is updated in doOneSecond()
            nrf->acknowledgeData(maxChargeValue, strlen(maxChargeValue), pipe);
            DBG("Sent maxCharge: %s in acknowledge", maxChargeValue);
        } else  {
            nrf->acknowledgeData(dataRx, 2, pipe);
            DBG("intNrf>%s %x",dataRx,bID);
        }
        if (pipe == 1) { // Open channel
            DBG("intNrf>Pipe 1  %s",dataRx);
            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 (dataRx[0] == 'b') { //Battery drop off
              //  DBG("intNrf>User check in %s",dataRx);
                sscanf (&dataRx[2], "%x %x", &userIDDrop, &numBatDrop);
                int pod = (userIDDrop&0XF0)>>4;
                if (dataRx[1] == 'd') {
                    turnPodOn(pod,1);
                    *ledRed=0;
                }
                if (dataRx[1] == 'p') {
                    turnPodOn(pod,0);
                    *ledRed=1;
                }


            }
        } else if (pipe>1) {
            if (dataRx[0] == 'O') { //Request for check out
                int battID;
                sscanf(&dataRx[2], "%x", &battID);
                bID = battID & 0x00ff;

                battIn[bID] = CHECKED_OUT;
                DBG("intNrf>Check out %d", bID);

                flagRotate = 1;
            }
            flagNrf = 1;
        }

        lastRxTme = now;

    }

    DBG("intNRF> int rx");
    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 %llX", 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->setRadio(0x01, 0x03); // 2MB/S  0dB
//  nrfFlush();
//}
//
///**
// * Set NRF as TX
// */
//void Locker::setAsTX(){
//  spiNRF();
//
//}

/**
 * Turns a pod power on
 */
void Locker::turnPodOn(int pod,int on)
{
    DBG("Pod %d on %d",pod,on);
    pods[pod]->write(on);
}