The field version of the solarnano grid on the ionQubes
Fork of SolarNanoGridv3 by
Battery/Battery.cpp
- Committer:
- defrost
- Date:
- 2016-09-06
- Revision:
- 36:a5620262f296
- Parent:
- 35:ede6d8bad011
File content as of revision 36:a5620262f296:
/** *@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" #define FUNCNAME "BATTERY" #include "defs.h" // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ Battery::Battery(FILE* fp, Serial *pc) : SolarNanoGrid(fp,pc) { DBG("Initialize class"); // ***** Variable initialisation ***** // Public variable initialisation maxChargeRate=1.5; // Charge rate in amps // Protected variables initialisation count=0; sizeRead=0; fileLength=0; filePointer=0; fileLeft=0; sdBuffPnt=0; /** * Open channel address of the locker */ openAddr=0; /** * Private channel address of the locker */ privateAddr=0; countSD=0; // Protected flags: * checkedIn=0; flagDirFileName=0; flagGetTime=0; flagNextFile=0; flagSendFileName=0; flagSendFileSize=0; flagSendFile=0; flagSendFileDone=0; flagGetMaxCharge=0; sendingFile=0; flagStartFileTx=0; startCharge = false; flagHubNotReady=0; flagCheckOut=0; sending=0; // Protected interrupts button=NULL; txWatch=NULL; delay=NULL; //Private variables initialisation maxRT=false; // ***** End of variables initialisation ***** // 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; //INFO("intNrf"); // //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) { if (flagStartFileTx==1) { // Locker not ready to reacieve - wait 25s. flagHubNotReady = 1; nrf->clearStatus(); flag = &flagDirFileName; delay->detach(); delay->attach(this, &Battery::setFlag, 25.0f); } else { maxRT=true; DBG("MAX RT flag is set. PTB20= %d status=%x",(unsigned int) *ce,status); *ce = 0; DBG("PTB20= %d status=%x",(unsigned int) *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; flagHubNotReady = 0; *ce = 1; nrf->clearStatus(); switch (dataRx[0]) { case ('C'): { doCheckIn(); flagNextFile = 1; DBG("Flag Set"); break; } case ('D'): { flagStartFileTx=0; // Hub commmunicating. 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 ('O'): { doCheckOut(); 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); // was 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",timeInf->tm_year+1900,timeInf->tm_mon+1,timeInf->tm_mday,timeInf->tm_hour, timeInf->tm_min,timeInf->tm_sec); break; } case ('M'): { #ifdef USEHUBCHARGERATE sscanf (&dataRx[2],"%f",&maxChargeRate ); if(maxChargeRate>2.0f) { maxChargeRate=2.0f; } if (maxChargeRate<0.0f) { maxChargeRate=0.0f; } DBG ("Max charge %f",maxChargeRate); #else DBG("Max charge rate being ignored..."); #endif 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(); } if ((!sendingFile)&&(checkedIn == 1)) { flagGetTime=1; flagGetMaxCharge=1; } } // ------------------------------------------------------------------------ // 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 out. Sends O %d, ID to locker * */ void Battery::checkOut() { sprintf(dataTx, "O %04X", (int) (id&0XFFFF)); DBG("Check out locker [%s]", dataTx); spiNRF(); nrf->transmitData(dataTx, strlen(dataTx)); // Reset to locker public comms channel } /** * 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() { //INFO("In Battery Loop"); *ledGreen = !checkedIn; if (flagGetTime) { flagGetTime=0; requestTime(); } if (flagGetMaxCharge) { flagGetMaxCharge=0; requestMaxCharge(); } if (flagNextFile) { flagNextFile = 0; sending=1; DBG("NextFile called"); requestTime(); nextFileToTx(); if (fileLength>0) { INFO("Sending file %s.",txFileName) flagDirFileName=1; } else { sendingFile=0; flagStartFileTx=0; INFO("No more files to send.") startCharge = true; checkOut(); sending=0; } } if (flagDirFileName) { flagDirFileName=0; sendDirName(); } if (flagSendFileName) { flagSendFileName = 0; sendFileName(); } if (flagSendFileSize) { flagSendFileSize = 0; sendFileSize(); } if (flagSendFile) { flagSendFile = 0; sending=1; sendFile(); } if (flagSendFileDone) { flagSendFileDone = 0; sendFileDone(); INFO("File sent <%s>",txFileName); //flag = &flagNextFile; //delay->detach(); //delay->attach(this, &Battery::setFlag, 2.5); flagNextFile = 1; } if (flagCheckOut) { flagCheckOut=0; doCheckOut(); } //INFO("Out Battery Loop"); return; } /** * sends a request for time update. */ void Battery::requestTime() { if(sending==0) { DBG("getTime"); nrf->transmitData("T ",2); } } /** * sends a request for time update. */ void Battery::requestMaxCharge() { if(sending==0) { DBG("Get Max Charge Rate"); nrf->transmitData("M ",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, "0"); } fclose(fp); } else { sprintf(lastFileName, "0"); txLength = 0; } 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() { flagStartFileTx=1; sprintf(dataTx, "D %s", logDir); DBG("send Dir Name [%s].", 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; } sendingFile=1; 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() { char * packet; unsigned int packetSize=32; spiNRF(); while (packetSize>0) { packet = getPacket(&packetSize,fullTxFilePath); nrf->transmitData(packet, packetSize); }; resetPackets(); flagSendFileDone=1; DBG("Done sending"); } /** * Update the last file sent file */ void Battery::sendFileDone() { int check; if (strlen(txFileName)>0) { spiSD(); FILE *fp = fopen("/sd/lastFileTx.txt", "w"); if (fp != NULL) { check = fprintf(fp, "%s %u \n", txFileName, fileLength); fclose(fp); DBG("sendFileDone> updated lastFileTx.txt %s %u chk = %d", txFileName, fileLength, check); } 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; } /** * Returns the max current that can be drawn from the system, in amps */ float Battery::getMaxCurrent() { return maxChargeRate; } /** * returns a string of the log directory */ char* Battery::getLogDirectory() { return logDir; } /** * Returns true if we are authorized to start charging. */ bool Battery::startCharging(void) { return startCharge; } bool Battery::isCheckedIn(void) { if(checkedIn == 1) { return true; } else { return false; } } void Battery::disableInt(void) { // Detaches all interrupts: txWatch->detach(); delay->detach(); nrf->setPwrDown(); return; } /** * Resets the buffers to start reading the file from the beginning again. * */ void Battery::resetPackets() { sdBuffPnt=0; fileLeft = fileLength; } /** * Gathers a packet from the file defined by fullTxFilePath * @param readOnly if true then it does not move the internal pointers on. */ char* Battery::getPacket(unsigned int *sizePackett,char * fullTxFilePath) { //DBG("Get packet"); // 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) { DBG("File %s",fullTxFilePath); spiSD(); FILE *fp; fp= fopen(fullTxFilePath, "rb"); wait(0.1); DBG("Open"); while (fp == NULL) { WARN("sendFile> File %s not found for reading",fullTxFilePath); fp= fopen(fullTxFilePath, "rb"); } spiSD(); //DBG("Seek"); fseek(fp, fileLength - fileLeft, SEEK_SET); //DBG("Read"); sizeRead = fread(sdBuffer, 1,SDBUFFERSIZE, fp); //DBG("Read %d",sizeRead); fileLeft -= sizeRead; fclose(fp); DBG("File %s %d \n\r",fullTxFilePath,sizeRead); //spiNRF(); } unsigned int bpNow =sdBuffPnt; unsigned int size=*sizePackett; if (sizeRead<size) { size=sizeRead; } if ((fileLeft==0)&&(sizeRead==0)) { sdBuffPnt=0; //flagSendFileDone=1; *sizePackett = 0; INFO("Done sending file %s",fullTxFilePath); } else { sizeRead -= size; //sendPacket(&(sdBuffer[sdBuffPnt]), size); sdBuffPnt+=size; //*sizePackett = size; DBG("Left to send %d",(fileLeft+sizeRead)); return &(sdBuffer[bpNow]); } return NULL; }