Proivdes data log data structure for FRAM, EPROM chip with functions to read chip and send back on serial data string.

Dependencies:   W25Q80BV multi-serial-command-listener

Dependents:   xj-data-log-test-and-example

Data Logging Data structure

Both Read and write seem to be working fine but testing has been limited.

Motivation

I needed a flexible data log structure that could tolerate evolving data structures as I discovered more things that needed to be measured. I also wanted something that is mostly human readable while remaining sufficiently concise to make efficient use of expensive storage resources.

I found it challenging to track everything needed to perform after the fact analysis we need to improve our state machine. In addition what I wanted to measure changed with time and I needed a robust way to log this data so we could analyze it latter. without breaking or converting all the old data. A self describing data format like JSON or XML would work but FRAM is expensive so I wanted something flexible but still concise.

I am working on A2WH which is a electronic controller for a sophisticated product that balances many sensors, battery charging from photo voltaic panels, controlling speed of many different fans, humidity and environmental data. Our main challenge is we never have enough battery power to run everything so we have to make decisions about what to run in an effort to produce the maximum amount of water from the available solar power resource. Our 2nd challenge is that balancing system actions such as increasing or decreasing fan speeds is driven by a complex internal prediction model that attempts balance many competing thermodynamic requirements. To get all this right requires substantial after the fact analysis and that requires logging a large amount of evolving data.

Design Notes

See: data-log-read.me.txt in the same project

Sample Use and Basic Test

Serial Command Interface

COMMANDS
  readall= send entire contents of log
  readlast 999
     999 = number of bytes from tail of log to retrieve
  tread 333 444
     333 = starting offset to start reading log
     444 = number of bytes to retrieve from log
  erase = erase log and start a new one
  help  = display this help

Other Chips

For legacy reasons I am using the library for "W25Q80BV.h" simply because I started with it. The actual FRAM chip I am using is 2 MBit FRAM MB85RS2MTPH-G-JNE I also tested it with SRAM 23LCV1024-I/P

Simplifying Design Decision

I made a simplifying assumption that every-time we generate a log entry I record the offset of the next write at a specific location in the chip. This works and is fast but it causes lots of updates against a single location. I prefer FRAM because this would rapidly fatigue FLASH chips like the W25Q80BV. Storing this pointer data in the CPU has the same fatigue problem.

Another other option would be to store this offset and our other critical configuration data in the clock chip but it is susceptible to loosing power and loosing this critical data.

One reason I don't log directly to the micro-sd is for the same fatigue problem but it is mostly for power management.

The FRAM chip provides adequate durability and data retention through power outage. The power outage retention is critical because the A2WH systems can be buried under feet of snow in the winter and solar panels do not provide much recharge under that condition.

One design option I have considered but not yet implemented is using a much smaller FRAM chip critical configuration data and rapid update data and then log directly to a larger and less expensive FLASH chip .

Journaling to micro-SD

I latter decided to add features to allow after the fact copying of the data to micro-sd cards to obtain larger log storage without soldering in more chips. I found the micro-sd consume quite a lot of power so I still want to log direct to the FRAM then copy to the micro-sd when I have surplus power available. Still thinking about consolidation tactics to allow re-use of FRAM after the data has been copied ot micro-sd.

Future

  • Support fast indexing by date to only pull back log entries between two dates.
  • Record most recent record headers for each record types where they are fast to access so we can send them with the data when only sending back portions of the data.
  • Support wrap around use of data log to re-use storage on chip.
  • Copy Data to micro SD card and consolidate FRAM chip for re-use.

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:
Wed Apr 13 04:15:43 2016 +0000
Revision:
11:bf816d33be80
Parent:
4:fa5bbe31a039
Added Python parser to convert DLOG format captured from readall command in serial port into CSV format for use in excel an R.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
joeata2wh 0:2c10df524ced 1 To make the data log format somewhat flexible and
joeata2wh 0:2c10df524ced 2 some what easy to debug while remaining somewhat
joeata2wh 0:2c10df524ced 3 consise while remaining human readable. The format
joeata2wh 0:2c10df524ced 4 will be a custom format but is designed to be relatively
joeata2wh 0:2c10df524ced 5 easy to parse while accomodating the following caveates:
joeata2wh 0:2c10df524ced 6 * Fields logged over time will change as firmware is reved.
joeata2wh 0:2c10df524ced 7 * Old log entries for the same record type will have different fileds.
joeata2wh 0:2c10df524ced 8 * storage in fram is realtive expensive so self describing data
joeata2wh 0:2c10df524ced 9 formats like JSON would not be cost effective.
joeata2wh 0:2c10df524ced 10 * When things mess up we want to be able to parse it and
joeata2wh 0:2c10df524ced 11 analyze it and have some chance of recovery
joeata2wh 0:2c10df524ced 12 * We need fast access to pont in time for at least 1 day
joeata2wh 0:2c10df524ced 13 of data.
joeata2wh 0:2c10df524ced 14
joeata2wh 0:2c10df524ced 15 will use a custom format.
joeata2wh 0:2c10df524ced 16
joeata2wh 0:2c10df524ced 17 Each record type will have record type label which will be
joeata2wh 0:2c10df524ced 18 composed of 4 characters separated from the data by a The known
joeata2wh 0:2c10df524ced 19 record types are:
joeata2wh 0:2c10df524ced 20
joeata2wh 0:2c10df524ced 21 Records will be appended to the data log in sequential order. Each
joeata2wh 0:2c10df524ced 22 record will be terminated with a \n. Some records will contain fixed
joeata2wh 0:2c10df524ced 23 length data but will still be terminated with \n and will never contain
joeata2wh 0:2c10df524ced 24 a \n in the stored data. unless the first number after the record type
joeata2wh 0:2c10df524ced 25 is 16 bit number storing the number
joeata2wh 0:2c10df524ced 26
joeata2wh 0:2c10df524ced 27 The general assumption is that all data will be stored for the short
joeata2wh 0:2c10df524ced 28 term in high speed FRAM or SRAM chips and copied to EPROM or Micro
joeata2wh 0:2c10df524ced 29 SD chips in the background once sufficnet data has accumulated to
joeata2wh 0:2c10df524ced 30 minimize over-write fatigue in the long term storage. I used FRAM
joeata2wh 0:2c10df524ced 31 specifically to allow after power loss data retention without having
joeata2wh 0:2c10df524ced 32 to worry about overrite fatigue for specific segments that would need
joeata2wh 0:2c10df524ced 33 rapid updates. The other assumption is that data is stored and logged
joeata2wh 0:2c10df524ced 34 then will be accessed generally starting at a given date reading forward
joeata2wh 0:2c10df524ced 35
joeata2wh 0:2c10df524ced 36 Short term Simplification Notes:
joeata2wh 0:2c10df524ced 37 Each time the CPU reboots it will record current record header field
joeata2wh 0:2c10df524ced 38 names for all record types active at that time. This will create some
joeata2wh 0:2c10df524ced 39 duplicates but save some overhead in firmware.
joeata2wh 0:2c10df524ced 40
joeata2wh 0:2c10df524ced 41 The firmware will only record next log position internally. It will
joeata2wh 0:2c10df524ced 42 simply write next log item at end of prior one.
joeata2wh 0:2c10df524ced 43
joeata2wh 0:2c10df524ced 44 Firmware will not record day start indexes.
joeata2wh 0:2c10df524ced 45
joeata2wh 0:2c10df524ced 46 Firmware will provide simple dump feature to send all data to serial
joeata2wh 0:2c10df524ced 47 IO line.
joeata2wh 0:2c10df524ced 48
joeata2wh 0:2c10df524ced 49 TODO: How to read serial input in non blocking
joeata2wh 0:2c10df524ced 50 fashion.
joeata2wh 0:2c10df524ced 51
joeata2wh 0:2c10df524ced 52
joeata2wh 0:2c10df524ced 53 Beginning Address. Since the log is presumably stored in a FRAM chip
joeata2wh 0:2c10df524ced 54 without support for a file system driver we must know the offset of where
joeata2wh 0:2c10df524ced 55 the log begins. Space before the log is generally used for system configuration
joeata2wh 0:2c10df524ced 56 data.
joeata2wh 0:2c10df524ced 57
joeata2wh 0:2c10df524ced 58 Pre-Log Values:
joeata2wh 0:2c10df524ced 59 DATOFNDX:
joeata2wh 0:2c10df524ced 60 Date Offset Index. Array of 100 string formated number pairs
joeata2wh 0:2c10df524ced 61 containing dateOffset records. Each pair contains
joeata2wh 0:2c10df524ced 62 one number which is string containing the date of
joeata2wh 0:2c10df524ced 63 the first record in that date offset in the format
joeata2wh 0:2c10df524ced 64 ccyymmd,offset the assumption is we can quickly scan
joeata2wh 0:2c10df524ced 65 or binary search this array to find the first offset
joeata2wh 0:2c10df524ced 66 record that describes the date range we are seeking then
joeata2wh 0:2c10df524ced 67 jump and read that offset record. Each time we add a new
joeata2wh 0:2c10df524ced 68 date offset log item we update this value.
joeata2wh 0:2c10df524ced 69
joeata2wh 0:2c10df524ced 70
joeata2wh 0:2c10df524ced 71 Record Types:
joeata2wh 0:2c10df524ced 72
joeata2wh 0:2c10df524ced 73 date:
joeata2wh 0:2c10df524ced 74 Date types will be composed of the format ccyy-mm-dd hh:mm:ss
joeata2wh 0:2c10df524ced 75 a new date record will be recorded whenever the system detects
joeata2wh 0:2c10df524ced 76 a new date when preparing to generate a new log item. At items
joeata2wh 0:2c10df524ced 77 that occur after this date are presumed to occur on that date.
joeata2wh 0:2c10df524ced 78
joeata2wh 0:2c10df524ced 79 Record Type active defenition:
joeata2wh 0:2c10df524ced 80 A space at first of system that stores the iformation about the
joeata2wh 0:2c10df524ced 81 currently active record types.
joeata2wh 0:2c10df524ced 82
joeata2wh 0:2c10df524ced 83 Record Type defenition:
joeata2wh 0:2c10df524ced 84 Prefix RTDE,RecordType,List of Field Names This is written into
joeata2wh 0:2c10df524ced 85 the log whenever the system reads a record type defenition from the
joeata2wh 0:2c10df524ced 86 current record types that is different than the once currently used
joeata2wh 0:2c10df524ced 87 in the firmware. When ths occurs it will write a new record type
joeata2wh 0:2c10df524ced 88 defenition
joeata2wh 0:2c10df524ced 89
joeata2wh 0:2c10df524ced 90
joeata2wh 0:2c10df524ced 91 next_write_offset: NWOF
joeata2wh 0:2c10df524ced 92 Next write offset record stores the byte postion of the next
joeata2wh 0:2c10df524ced 93 postion in the log byte offset where the next
joeata2wh 0:2c10df524ced 94
joeata2wh 0:2c10df524ced 95 date_offset:
joeata2wh 0:2c10df524ced 96 Fixed Length Binary Data -
joeata2wh 0:2c10df524ced 97 Preix: DATOF
joeata2wh 0:2c10df524ced 98 NumRec
joeata2wh 0:2c10df524ced 99 Offset Of Next DATOF 32 bit number
joeata2wh 0:2c10df524ced 100 Offsets (array of 32 bit numbers)
joeata2wh 0:2c10df524ced 101 RecordOffset records are store in a region of storage
joeata2wh 0:2c10df524ced 102 after the before the actual data logs are written. These are
joeata2wh 0:2c10df524ced 103 fixed length records where the starting byte offset for each
joeata2wh 0:2c10df524ced 104 days of logging are stored as 32 bit unsigned integer numbers
joeata2wh 0:2c10df524ced 105 as an array. The first number contains the number of spaces
joeata2wh 0:2c10df524ced 106 pre-allocated. The last number written will be the offset to
joeata2wh 0:2c10df524ced 107 the next date_offset record. In general we will allocate 365
joeata2wh 0:2c10df524ced 108 365 days worht of space so the total row length will be
joeata2wh 0:2c10df524ced 109 32 + (365 * 32) + 32 bits = 11,744 bits
joeata2wh 0:2c10df524ced 110 X number of days with a a
joeata2wh 0:2c10df524ced 111
joeata2wh 0:2c10df524ced 112
joeata2wh 0:2c10df524ced 113 reading:
joeata2wh 0:2c10df524ced 114
joeata2wh 0:2c10df524ced 115 System state:
joeata2wh 0:2c10df524ced 116
joeata2wh 0:2c10df524ced 117