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