#include <MTP.h>
#include <Storage.h>
#include <usb1_mtp.h>
#include <DataLogger.h>
#include <CMDHandler.h>
#include <ADC.h>
const int admarkpin = 12;
// Add stuff for MTP
#define DO_DEBUG 0
MTPStorage_SD storage;
MTPD mtpd(&storage);
SdFs *fsptr;
// instantiate a datalogger object
DataLogger mydl;
CMDHandler mycmds;
bool MTPLoopOK = true; // start up with MTP Active---no loop only when logging
bool autostarted = false;
#define LEDON digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);
const char compileTime [] = " Compiled on " __DATE__ " " __TIME__;
const char *autoname = "Solar";
const char *extype = "005";
void LoggerISR(void) { // call the data logger collection ISR handler
mydl.TimerChore();
}
#define SAMPLERATE 1000
#define SAVEINTERVAL 2 // seconds between records
// use our own buffer on the T3.6
// rawdat is 16 bytes and we need at least 1200
#define MAXBUFFER 24000
uint8_t mybuffer[MAXBUFFER];
char logfilename[64];
bool logging = false;
uint64_t fsreserved;
elapsedMillis el_autostart;
// raw data for buffer 16 bytes long
struct rawdat {
uint32_t icount;
float ival, vs, vt;
};
// processed data storage structure
struct datrec {
uint32_t unixtime;
float mAvg, mPeak, vsAvg, vtAvg;
};
// instantiate a new ADC object
ADC *adc = new ADC(); // adc object;
#define AUTODELAY 300000 // 5 minutes
void setup() {
uint32_t bufflen;
TLoggerStat *tsp;
pinMode(ledpin, OUTPUT);
pinMode(A3, INPUT); // A3 is voltage at teensy
pinMode(A2, INPUT); // A2 is solar/battery voltage
pinMode(A0, INPUT); // a0 is current sensor output
Serial.begin(9600);
delay(500);
Serial.print("\n\nSolar Data Logger ");
Serial.println(compileTime);
mydl.SetDBPrint(false); // turn on debug output
fsptr = mydl.InitStorage();// try starting SD Card and file system
if (fsptr == NULL) {
// initializing SD Card failed
fastBlink();
}
// now try to initialize buffer. Check that request falls within
// size of local buffer or if it will fit on heap
bufflen = mydl.InitializeBuffer(sizeof(rawdat), SAMPLERATE, 1200, mybuffer);
if ((bufflen == 0) || (bufflen > MAXBUFFER)) {
Serial.println("Not enough buffer space! Reduce buffer time or sample rate.");
fastBlink();
}
adc->adc0->setAveraging(1 ); // set number of averages
adc->adc0->setResolution(12); // set bits of resolution
adc->adc0->setReference(ADC_REFERENCE::REF_1V2); // use the 1.2V reference
adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed
LEDON
delay(1000); // Need a delay while SDFat checks free clusers for first time
tsp = mydl.GetStatus();
LEDOFF
Serial.printf("Free Space: %6.2f\n", (float)(tsp->spaceavailable) / (1024.0 * 1024.0));
Serial.println("Calculating reserved space.");
fsreserved = tsp->spaceavailable / 20; //reserve the last 5% of space available;
StartMTP();
// Now attach our customized callback functions
mydl.AttachCollector(&myCollector); // specify our collector callback function
mydl.AttachWriter(&myBinaryWriter); // logger saves processed binary data you generate
mydl.AttachDisplay(&myBinaryDisplay, 2000); // display written data once per 2 seconds
mydl.AutoFile(autoname, extype, 6);
delay(200);
el_autostart = 0;
InitCommands();
}
void InitCommands(void) {
mycmds.AddCommand(&StartLogging, "SL", 0);
mycmds.AddCommand(&QuitLogging, "QL", 0);
mycmds.AddCommand(&ShowStatus, "SS", 0);
mycmds.AddCommand(&Directory, "DI", 0);
}
void Directory(void *cmdline) {
mydl.ShowDirectory();
}
void loop() {
// put your main code here, to run repeatedly:
TLoggerStat *tsp;
do {
tsp = mydl.GetStatus();
delay(1);
} while (tsp->spaceavailable == 0);
if (logging)mydl.CheckLogger(); // check for data to write to SD at regular intervals
if ((tsp->spaceavailable < fsreserved) && logging) { //we are near end of card
Serial.println("Halting logging. Getting near end of SD Card.");
Serial.printf("Space Available = %6.1f Space reserved = %6.1f\n",
(float)tsp->spaceavailable / (1024.0 * 1024.0), (float)fsreserved / (1024.0 * 1024.0));
QuitLogging(NULL);
ShowStatus(NULL);
logging = false;
}
if (mycmds.CheckCommandInput()) {
el_autostart = 0; // reset autostart timer
}
if (MTPLoopOK) {
mtpd.loop();
}
if (!autostarted) {
if (el_autostart > AUTODELAY) {
StartLogging(NULL);
}
}
//asm("WFI\n");
}
void StartMTP(void) {
Serial.println("Starting MTP Responder");
usb_mtp_configure();
if (!Storage_init(fsptr)) {
Serial.println("Could not initialize MTP Storage!");
fastBlink();
} else MTPLoopOK = true;
}
void StartLogging(void *cmdline) {
TLoggerStat *tsp;
tsp = mydl.GetStatus();
Serial.println("Starting Logger.");
logging = true;
autostarted = true;
MTPLoopOK = false;
mydl.MakeFileName(autoname, extype);
strncpy(logfilename, tsp->filename, strlen(tsp->filename));
mydl.StartLogger(logfilename, 1000); // sync once per second
Serial.print("\n");
}
void QuitLogging(void *cmdline) {
Serial.println("Stopping Logger.");
mydl.StopLogger();
logging = false;
MTPLoopOK = true;
}
// blink at 500Hz forever to signal unrecoverable error
void fastBlink(void) {
while (1) {
LEDON
delay(100);
LEDOFF
delay(100);
}
}
// can be called before, during, and after logging.
void ShowStatus(void *cmdline) {
TLoggerStat *tsp;
tsp = mydl.GetStatus();
Serial.println("\nLogger Status:");
Serial.printf("Bytes Written: %lu\n", tsp->byteswritten);
Serial.printf("Collection time: %lu seconds\n", tsp->collectionend - tsp->collectionstart);
Serial.printf("Max Collection delay: %lu microseconds\n", tsp->maxcdelay);
Serial.printf("Average Write Time: %6.3f milliseconds\n", tsp->avgwritetime / 1000.0);
Serial.printf("Maximum Write Time: %6.3f milliseconds\n\n", tsp->maxwritetime / 1000.0);
}
/***************************************************
Callback function to handle user-defined collection
and buffering
struct rawdat{
uint32_t spare
float ival, vs, vt;
};
******************************************************/
// called from the datalogger timer handler
// The collector simply collects three adc inputs
// and saves them in a rawdat record
void myCollector( void* vdp) {
struct rawdat *rp;
rp = (struct rawdat *)vdp;
uint16_t adval;
float vadc, ival;
adval = (uint16_t)adc->adc0->analogRead(A0); // MAX 471current sensor
vadc = 5.0 * 1.2 * (float)adval / 4096.0; // parallel resistance is 4K for sensor
ival = 500.0 * vadc; // 500mA/volt
rp->ival = ival;
adval = (uint16_t)adc->adc0->analogRead(A2); // Solar Volts
vadc = 5.0 * 1.2 * (float)adval / 4096.0; // correct for 4:1 attenuator
rp->vs = vadc;
adval = (uint16_t)adc->adc0->analogRead(A3); // T3 Power Volts
vadc = 5.0 * 1.2 * (float)adval / 4096.0;// correct for 4:1 attenuator
rp->vt = vadc;
}
char *TString(time_t tm) {
static char dstr[12];
// sprintf(dstr,"%02u/%02u/%04u ",month(tm),day(tm),year(tm));
sprintf(dstr, "%02u:%02u:%02u", hour(tm), minute(tm), second(tm));
return dstr;
}
// called from the datalogger CheckLoggger function
void myBinaryDisplay( void* vdp) {
struct datrec *dp;
dp = (struct datrec *)vdp;
if (!logging) return;
Serial.printf("%s\t", TString(dp->unixtime));
Serial.printf("%4.1f\t%4.1f\t%4.3f\t%4.3f\n", dp->mAvg, dp->mPeak, dp->vsAvg, dp->vtAvg);
}
/************************************************
struct datrec {
uint32_t unixtime,
float mAvg, mPeak,vsAvg, vtAvg;
};
***************************************************/
// Used to write processed processed binary data. Input to function is
// a pointer to a rawdat record.
// This gets called once for each rawdat buffered at the 1000Hz rate.
// A binary record is saved every saveinterval seconds
uint16_t myBinaryWriter(void *bdp, void* rdp) {
static uint16_t rcounter = 0;
uint16_t rval;
static struct datrec dr;
struct rawdat *rp;
rp = (struct rawdat *)bdp;
static float isum, vssum, vtsum, ipeak;
char** sptr;
sptr = (char**) rdp;
// add data to sums and check peaks
isum += rp->ival;
if (rp->ival > ipeak) ipeak = rp->ival;
vssum += rp->vs;
vtsum += rp->vt;
rcounter++;
if (rcounter >= (SAMPLERATE * SAVEINTERVAL)) {
dr.mPeak = ipeak;
dr.mAvg = isum / rcounter;
dr.vsAvg = vssum / rcounter;
dr.vtAvg = vtsum / rcounter;
dr.unixtime = now();
ipeak = 0.0;
isum = 0.0;
vssum = 0.0;
vtsum = 0.0;
*sptr = (char *)&dr;
rval = sizeof(dr);
rcounter = 0;
} else {
*sptr = NULL;
rval = 0;// return nothing until end of interval
}
return rval;
}