Data log for logging enviornmental, process and system state to FRAM or EPROM chips that do not have support for a file system. Includes support for multiple record types, evolving record types, automatic date and time stamp and copying contents to serial. Will soon support journaling to micro SD file system. We always log to fram first for speed and power conserfaction then copy in bulk to SD cards when we have charging power available.

Dependencies:   data_log mbed

Flexible Data Logger Example Use and Test Code

Detailed Documentation

See home page for data log library https://developer.mbed.org/users/joeata2wh/code/data_log/

License

By Joseph Ellsworth CTO of A2WH Take a look at A2WH.com Producing Water from Air using Solar Energy March-2016 License: https://developer.mbed.org/handbook/MIT-Licence Please contact us http://a2wh.com for help with custom design projects.

Committer:
joeata2wh
Date:
Thu Mar 31 05:02:57 2016 +0000
Revision:
1:58f86fb1fb22
Parent:
0:0cfc06f9f18c
Child:
2:74a52e5fd1ed
write functions basically working still working on testing the read chunk-ed version.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
joeata2wh 0:0cfc06f9f18c 1 /* xj-data-log-test-and-exmple.c
joeata2wh 0:0cfc06f9f18c 2 Shows basic usage of dat_log library and
joeata2wh 0:0cfc06f9f18c 3 performs some basic tests.
joeata2wh 0:0cfc06f9f18c 4
joeata2wh 0:0cfc06f9f18c 5 By Joseph Ellsworth CTO of A2WH
joeata2wh 0:0cfc06f9f18c 6 Take a look at A2WH.com Producing Water from Air using Solar Energy
joeata2wh 0:0cfc06f9f18c 7 March-2016 License: https://developer.mbed.org/handbook/MIT-Licence
joeata2wh 0:0cfc06f9f18c 8 Please contact us http://a2wh.com for help with custom design projects.
joeata2wh 0:0cfc06f9f18c 9 */
joeata2wh 0:0cfc06f9f18c 10
joeata2wh 0:0cfc06f9f18c 11 #include "mbed.h"
joeata2wh 0:0cfc06f9f18c 12 #include "dataLog.h"
joeata2wh 0:0cfc06f9f18c 13
joeata2wh 0:0cfc06f9f18c 14 const float adc_ref = 3.3f;
joeata2wh 0:0cfc06f9f18c 15 // SPI PINS
joeata2wh 0:0cfc06f9f18c 16 #define SPI1_SCK PA_5
joeata2wh 0:0cfc06f9f18c 17 #define SPI1_MISO PA_6
joeata2wh 0:0cfc06f9f18c 18 #define SPI1_MOSI PA_7
joeata2wh 0:0cfc06f9f18c 19
joeata2wh 0:0cfc06f9f18c 20 // SPI PINS for Data Log chip
joeata2wh 0:0cfc06f9f18c 21 #define dataLogMISOPin SPI1_MISO
joeata2wh 0:0cfc06f9f18c 22 #define dataLogMOSIPin SPI1_MOSI
joeata2wh 0:0cfc06f9f18c 23 #define dataLogCLKPin SPI1_SCK
joeata2wh 0:0cfc06f9f18c 24 #define dataLogSelectPin PC_12
joeata2wh 0:0cfc06f9f18c 25
joeata2wh 1:58f86fb1fb22 26 //#define DO_LOG_ERASE // uncomment to erase the existing log.
joeata2wh 1:58f86fb1fb22 27
joeata2wh 0:0cfc06f9f18c 28 AnalogIn waterTempSense(A0);
joeata2wh 0:0cfc06f9f18c 29 AnalogIn oxygenLevelSense(A1);
joeata2wh 0:0cfc06f9f18c 30 AnalogIn solarStrengthSense(A2);
joeata2wh 0:0cfc06f9f18c 31 AnalogIn waterSpeedSense(A3);
joeata2wh 0:0cfc06f9f18c 32 // imagine for sake of example that we have
joeata2wh 0:0cfc06f9f18c 33 // circuitry that actually convert these Volt
joeata2wh 0:0cfc06f9f18c 34 // readings to useful readings.
joeata2wh 0:0cfc06f9f18c 35
joeata2wh 0:0cfc06f9f18c 36 DigitalOut led(LED1);
joeata2wh 1:58f86fb1fb22 37 Serial pc(USBTX, USBRX);
joeata2wh 0:0cfc06f9f18c 38
joeata2wh 1:58f86fb1fb22 39 // simulated process generating log entries
joeata2wh 1:58f86fb1fb22 40 // based on ADC readings.
joeata2wh 1:58f86fb1fb22 41 void generateSimulatedLog(struct DLOG *lgr, int numCycles, float sleepBetween) {
joeata2wh 1:58f86fb1fb22 42 char stateHappy[] = "happy";
joeata2wh 1:58f86fb1fb22 43 char stateSad[] = "sad";
joeata2wh 1:58f86fb1fb22 44 char stateDead[] = "dead fish";
joeata2wh 1:58f86fb1fb22 45 char *currState = stateHappy;
joeata2wh 1:58f86fb1fb22 46 char *lastState = 0;
joeata2wh 1:58f86fb1fb22 47 int cycleCnt;
joeata2wh 1:58f86fb1fb22 48
joeata2wh 1:58f86fb1fb22 49
joeata2wh 1:58f86fb1fb22 50 for(cycleCnt=0; cycleCnt < numCycles; cycleCnt++) {
joeata2wh 0:0cfc06f9f18c 51 float waterTemp = waterTempSense.read() * adc_ref;
joeata2wh 0:0cfc06f9f18c 52 float oxygenLevel = oxygenLevelSense.read() * adc_ref;
joeata2wh 0:0cfc06f9f18c 53 float solarStrength = solarStrengthSense.read() * adc_ref;
joeata2wh 0:0cfc06f9f18c 54 float waterSpeed = waterSpeedSense.read() * adc_ref;
joeata2wh 0:0cfc06f9f18c 55
joeata2wh 1:58f86fb1fb22 56 char tbuff[256];
joeata2wh 1:58f86fb1fb22 57 sprintf(tbuff, "%0.2f,%0.2f,%0.2f,%0.2f", waterTemp, oxygenLevel, solarStrength,waterSpeed);
joeata2wh 1:58f86fb1fb22 58 dlLog(lgr, "sensors",tbuff);
joeata2wh 1:58f86fb1fb22 59 // date and time are automatically recorded with the call.
joeata2wh 1:58f86fb1fb22 60 // time is only recorded to the second granularity and dates
joeata2wh 1:58f86fb1fb22 61 // are actually recorded as separate records when the date changes.
joeata2wh 1:58f86fb1fb22 62
joeata2wh 1:58f86fb1fb22 63 pc.printf("cycleCnt=%d logged %s\r\n", cycleCnt, tbuff);
joeata2wh 1:58f86fb1fb22 64
joeata2wh 1:58f86fb1fb22 65 currState = stateHappy;
joeata2wh 1:58f86fb1fb22 66 if (oxygenLevel < 20)
joeata2wh 1:58f86fb1fb22 67 currState = stateSad;
joeata2wh 1:58f86fb1fb22 68 if (oxygenLevel < 12)
joeata2wh 1:58f86fb1fb22 69 currState = stateDead;
joeata2wh 1:58f86fb1fb22 70
joeata2wh 1:58f86fb1fb22 71 if (currState != lastState) {
joeata2wh 1:58f86fb1fb22 72 // Only generate a new log if the current state has changed
joeata2wh 1:58f86fb1fb22 73 lastState = currState;
joeata2wh 1:58f86fb1fb22 74 sprintf(tbuff,"%s,%0.2f", currState, oxygenLevel);
joeata2wh 1:58f86fb1fb22 75 dlLog(lgr,"state", tbuff);
joeata2wh 1:58f86fb1fb22 76 pc.printf("cycleCnt=%d logged stateChange %s\r\n", cycleCnt, tbuff);
joeata2wh 0:0cfc06f9f18c 77 }
joeata2wh 1:58f86fb1fb22 78 // lgr will internally log time. Whenever the date changes
joeata2wh 1:58f86fb1fb22 79 // it will log a new date records.
joeata2wh 1:58f86fb1fb22 80 led = !led;
joeata2wh 1:58f86fb1fb22 81 wait(sleepBetween);
joeata2wh 0:0cfc06f9f18c 82 }
joeata2wh 0:0cfc06f9f18c 83 }
joeata2wh 1:58f86fb1fb22 84
joeata2wh 1:58f86fb1fb22 85 int main() {
joeata2wh 1:58f86fb1fb22 86 pc.baud(9600);
joeata2wh 1:58f86fb1fb22 87 pc.printf("\nData Logger Example example\n");
joeata2wh 1:58f86fb1fb22 88 set_time(1459380179);
joeata2wh 1:58f86fb1fb22 89
joeata2wh 1:58f86fb1fb22 90 // NOTE: You need to initialize the clock to some meaningful value
joeata2wh 1:58f86fb1fb22 91 // I use a clock chip but here is a manual setting
joeata2wh 1:58f86fb1fb22 92 time_t seconds = time(NULL);
joeata2wh 1:58f86fb1fb22 93 pc.printf("time set to %s\r\n", ctime(&seconds));
joeata2wh 1:58f86fb1fb22 94
joeata2wh 1:58f86fb1fb22 95 char dlbuff[81]; // buffer used internally by this instance of data log
joeata2wh 1:58f86fb1fb22 96 DataLogChipType dlchip(dataLogMOSIPin, dataLogMISOPin, dataLogCLKPin, dataLogSelectPin);
joeata2wh 1:58f86fb1fb22 97 pc.printf("\r\nInitialized Data Log Chip");
joeata2wh 1:58f86fb1fb22 98 struct DLOG *lgr = dlMake(&dlchip, dlbuff, 80);
joeata2wh 1:58f86fb1fb22 99 pc.printf("\r\nInitialized Logger\r\n");
joeata2wh 1:58f86fb1fb22 100 pc.printf("logger nextWritePos=%ld", lgr->nextWritePos);
joeata2wh 1:58f86fb1fb22 101
joeata2wh 1:58f86fb1fb22 102 #ifdef DO_LOG_ERASE
joeata2wh 1:58f86fb1fb22 103 //Erase the log But only if you really want to loose the
joeata2wh 1:58f86fb1fb22 104 // data
joeata2wh 1:58f86fb1fb22 105 pc.printf("ERASE LOG");
joeata2wh 1:58f86fb1fb22 106 dlEraseLog(lgr);
joeata2wh 1:58f86fb1fb22 107 pc.printf("afer erase logger nextWritePos=%ld", lgr->nextWritePos);
joeata2wh 1:58f86fb1fb22 108 #endif
joeata2wh 1:58f86fb1fb22 109
joeata2wh 1:58f86fb1fb22 110 // Manually Read first 1,000 bytes from the log
joeata2wh 1:58f86fb1fb22 111 char rbuff[1001];
joeata2wh 1:58f86fb1fb22 112 memset(rbuff,1001,0);
joeata2wh 1:58f86fb1fb22 113 dlchip.readStream(dlFirstLogEntry, rbuff, 1000);
joeata2wh 1:58f86fb1fb22 114 pc.printf("first 1000 characters from log\r\n%s\r\n", rbuff);
joeata2wh 1:58f86fb1fb22 115
joeata2wh 1:58f86fb1fb22 116 // Send Log Contents to Serial port
joeata2wh 1:58f86fb1fb22 117 // sends from byte zero of the log
joeata2wh 1:58f86fb1fb22 118 // to byte 100,000 or end of log which ever comes
joeata2wh 1:58f86fb1fb22 119 // first.
joeata2wh 1:58f86fb1fb22 120 pc.printf("\r\nSend the contents of log to PC automated way\r\n");
joeata2wh 1:58f86fb1fb22 121 dlReadSend(lgr, &pc, 0, 100000);
joeata2wh 1:58f86fb1fb22 122
joeata2wh 1:58f86fb1fb22 123
joeata2wh 1:58f86fb1fb22 124 // Record our record headers. These need to match the records we will
joeata2wh 1:58f86fb1fb22 125 // write later. It is OK to change the defintion of the headers as the
joeata2wh 1:58f86fb1fb22 126 // parser will use the correct defenition provided you always record the
joeata2wh 1:58f86fb1fb22 127 // defenition before writing the log entries.
joeata2wh 1:58f86fb1fb22 128 dlLog(lgr, "HEAD\tsensors", "waterTemp.f,oxygenLevel.f,solarStrength.f,waterSpeed.f");
joeata2wh 1:58f86fb1fb22 129 dlLog(lgr, "HEAD\ttstate", "currState.s,oxygenLevel.f");
joeata2wh 1:58f86fb1fb22 130 pc.printf("\r\nWrote record type headers\n");
joeata2wh 1:58f86fb1fb22 131 // by convention I record the record header every time the system starts.
joeata2wh 1:58f86fb1fb22 132 // in future will have a fast way to retrieve active header for each record
joeata2wh 1:58f86fb1fb22 133 // type so you can determine if new header is differnt that exisitng header and
joeata2wh 1:58f86fb1fb22 134 // only record if they chanaged.
joeata2wh 1:58f86fb1fb22 135 // The .f suffix is a hint to down stream parser to parse as a float.
joeata2wh 1:58f86fb1fb22 136 // .f - float, .i - int or long, .s-string, .d - ISO date, .b - byte
joeata2wh 1:58f86fb1fb22 137 // at the very least you should record a new HEAD record the first time
joeata2wh 1:58f86fb1fb22 138 // a given record type is used and every time you add or change the fields or field ordering.
joeata2wh 1:58f86fb1fb22 139
joeata2wh 1:58f86fb1fb22 140 generateSimulatedLog(lgr, 20, 10.0);
joeata2wh 1:58f86fb1fb22 141
joeata2wh 1:58f86fb1fb22 142 while(1) {
joeata2wh 1:58f86fb1fb22 143
joeata2wh 1:58f86fb1fb22 144
joeata2wh 1:58f86fb1fb22 145 }
joeata2wh 1:58f86fb1fb22 146
joeata2wh 1:58f86fb1fb22 147
joeata2wh 1:58f86fb1fb22 148 }