The field version of the solarnano grid on the ionQubes
Fork of SolarNanoGridv3 by
Diff: Locker/Locker.cpp
- 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(); + +}