== NzBase Datalogging API == An instrument using an Intricon (RTI) circuit, which supports datalogging, will generate built-in log of some important events. === Decoding Events Datalog === The data logging feature on Ethos stores information associated with the following 4 events: # Startup # Volume Control # Push Button # Low Battery Warning This allows monitoring of such things as daily usage, battery life, number of times user adjusts VC, or adjusts the active program. Events only get logged when that particular event occurs. The actual logging or writing of the event doesn't happen for 30 seconds after the event was detected. This allows the user time to finish making an adjustments before logging the data associated with the event. The event clock is simply a 24-bit counter that increments its count every 10 minutes. The event clock is initialized during hybrid production and never allowed to be reset except of course by reloading the firmware image. If by chance there are 20 entries with the same count, it simply means that an entry is recorded every 30 secs for that 10 min period. In other words, any event happening within a 10 min period gets the same clock count. Events get recorded after 30 secs of no change. Startup events get recorded after 3 mins. === Data Structure === //--------------------------- // Event Data Logging //--------------------------- const MaxNumEvents = 512; type TEthos_Events = Packed Record EventStatus : LongInt; end; PEthos_DataLog = ^TEthos_DataLog; TEthos_DataLog = Packed record WorkOrder: LongInt; // Circuit batch number. (Previous field definition ==> DateCode : LongInt;) Clock : LongInt; // Real time clock, 24-bits (10 min incremental counter from Initialization) NumEvents: LongInt; // Events since chip birth (Event counter) EventPtr : LongInt; // Pointer to next available storage space in queue Events : Array[0..MaxNumEvents-1] of TEthos_Events; // 500 events with 1-2 status words per event end; ^ EEPROM Space | 1512 bytes | ^ Table length | 3 bytes / 24 bit word - 504 - 24 bit words | ^ Events | 500 events with 1-2 status words per event | ^ Field ^ Table Entry ^ Pointer ^ Description ^ | DateCode | 0 | | DateCode = WorkOrder (WorkOrder is entered during Hybrid test and is for internal tracking purposes) | | Clock | 1 | | 10 Min counter from Initialization | | Num Events | 2 | | Event counter | | Event Addr ptr | 3 | | Ptr to next available storage space | | Event 1 | 4 | 976 | | | ... | ... | ... | | | Event 500 | 504 | 1476 | | | Checksum | 505 | | | ^ Event Number ^ Status words ^ Description ^ | Startup | 2 | Upon Startup a 3 minute delay timer is started. After the delay the startup event is logged. | | Status word 1| | EEPPVCRTC EE= Event = 1 (bits 17 - 23) PP= Active Program (bits 15 , 16) VC = VC position (bits 10 - 14) bits 0 - 9 are all 0's) | | Status word 2| Real Time Clock (RTC) | 24bit counter | | PB Switch | 1 | Upon detection of a program switch event, a 30 sec delay timer is started. After the delay the program switch event is logged | | Status word| | EEPPVCRTC EE= Event = 3 (bits 17 - 23) PP= Active Program (bits 15 , 16) VC = VC position (bits 10 - 14) RTC (low 10 bits of RTC bits (0 - 9)) | | VC change | 1 | Upon detection of a VC change event, a 30 sec delay timer is started. After the delay the VC change event is logged | | Status word| | EEPPVCRTC EE= Event = 2 (bits 17 - 23) PP= Active Program (bits 15 , 16) VC = VC position (bits 10 - 14) RTC (low 10 bits of RTC bits (0 - 9)) | | Low Batt Warning | 1 | Upon detection of a VC change event, a 30 sec delay timer is started. After the delay the VC change event is logged | | Status word| | EEPPVCRTC EE= Event = 4 (bits 17 - 23) PP= Active Program (bits 15 , 16) VC = VC position (bits 10 - 14) RTC (low 10 bits of RTC bits (0 - 9)) | === Event Definitions === A definition of the Events and their associated status is as follows: === Event 1 = Startup === Upon Startup, a 3 minute delay timer is started. After the delay, the startup event is logged. The startup event has two 24-bit status words associated with it, and it occurs whenever the device is powered on. The two words are a 24-bit Event Status and a 24-bit real-time clock using this format: Event status format: EEEE EEEP PVVV VV00 0000 0000 E = 7 bit Event code ( --> Startup event code = 1) P = 2 bit Active program setting V = 5 bit VC position setting Real Time Clock: 24-bit counter where each count is 10 min. This field gets a timestamp copied from the circuit's real time clock. === Event 2 = Volume Control === Upon detection of a VC change event, a 30 sec delay timer is started. After the delay the VC change event is logged === Event 3 = Push Button === Upon detection of a program switch event, a 30 sec delay timer is started. After the delay the program switch event is logged. === Event 4 = Low Battery Warning === Upon detection of a VC change event, a 30 sec delay timer is started. After the delay the VC change event is logged. All these events (2, 3, 4) have one 24-bit status word associated with them: Event status format: EEEE EEEP PVVV VVCC CCCC CCCC E = 7 bit event code P = 2 bit Active program setting V = 5 bit VC position setting C = 10 least significant bits of the real time clock **Note**: Clock will cycle from 0 - 1023 counts (10-bits) for regular events, and from 0 - 16777215 counts for startup event time. === Sample Code === procedure TfrmEventDataLog.DisplayLogDetails(ALogEntry: integer); var CurLogEntry: TDataLogEntry; begin ShowMessage(format('Clock = %d, Work Order = %d, Number of Events = %d', [ CurNzBase.DataLog.Clock, // Clock count since circuit 'birth' (eg. 787) CurNzBase.DataLog.WorkOrder, // Batch number. Note: Used to be date of circuit 'birth' (eg. 206088) CurNzBase.DataLog.NumEvents // Number of events logged (eg. 15768) ])); for i:=0 to CurNzBase.Datalog.NumEvents - 1 do begin CurLogEntry := DecodeLogEntry(CurNzBase.DataLog.Events[i]); // Actual events (see DecodeLogEntry() ) ShowMessage(format('Event = %d, Active Program = %d, VC Pos = %d, Clock = %d', [ CurLogEntry.Event, CurLogEntry.ActiveProgram, CurLogEntry.VCpos, CurLogEntry.Clock ])); end; end; //------------------------------------------------------------------------------ // description: Decode an event data log entry. // parameters : ALogEntry: integer; RealTimeClock: integer // return : TDataLogEntry //------------------------------------------------------------------------------ function TfrmEventDataLog.DecodeLogEntry(ALogEntry: integer): TDataLogEntry; var CurClock: smallint; begin result.Event := ((integer(ALogEntry) shr 17) and 127 { 7-bit mask}); result.ActiveProgram := ((integer(ALogEntry) shr 15) and 3 { 2-bit mask}); result.VCpos := ((integer(ALogEntry) shr 10) and 31 { 5-bit mask}); CurClock := ((integer(ALogEntry) shr 0) and 1023 {10-bit mask}); if (result.Event > 0) and (CurClock > 0) then begin result.Clock := CurClock; // adjust relative clock to real time clock end else if (result.Event = 0) and (ALogEntry > 0) then begin // Startup Clock status (2nd status entry) // since it is a 0 event, but field contains data (i.e. the startup timestamp) result.ActiveProgram := 0; // clear it, since this is N/A result.VCpos := 0; // clear it, since this is N/A result.Clock := DecodeStartupClock(ALogEntry); end else begin result.Clock := 0; // no clock entry end; end; //------------------------------------------------------------------------------ // description: Decode the startup clock of an event data log entry. // parameters : ALogEntry: integer // return : integer //------------------------------------------------------------------------------ function TfrmEventDataLog.DecodeStartupClock(ALogEntry: integer): integer; begin result := (integer(ALogEntry) and 16777215 {24-bit mask}); // power-on clock end; //------------------------------------------------------------------------------ // Description: Encode the given DatalogEntry into an integer. // Parameters : ALogEntry: TDataLogEntry // Return : integer --> Encoded entry //------------------------------------------------------------------------------ function TfrmEventDatalog.EncodeLogEntry(ALogEntry: TDataLogEntry): integer; begin // To encode we do the following: result := integer(((ALogEntry.Event and 127 { 7-bit mask}) shl 17) xor ((ALogEntry.ActiveProgram and 3 { 2-bit mask}) shl 15) xor ((ALogEntry.VCpos and 31 { 5-bit mask}) shl 10) xor ((ALogEntry.Clock and 1023 {10-bit mask}) shl 0) ); end; //------------------------------------------------------------------------------ // description: Get the respective hours given a clock count (each count = 10 min). // parameters : ClockCount: integer // return : integer //------------------------------------------------------------------------------ function TfrmEventDataLog.GetHrs(ClockCount: integer): double; begin result := RoundTo((ClockCount * 10 {10 min for each count}) / 60 {min/hr}, -1); end; //------------------------------------------------------------------------------ // description: Get the days and hrs for the specified clock count. // parameters : ClockCount: integer // return : string //------------------------------------------------------------------------------ function TfrmEventDataLog.GetHrsToStr(ClockCount: integer; ShowDays: Boolean=False): string; var dd, hh, mm: integer; begin // For example: // DateCode (Decimal) = 206088 // DateCode (Binary) = 0011 0010 0101 0000 1000 // Extracted digits = 3 2 5 0 8 // Final Decoded Date = 03/25/08 // result := format('%d%d/%d%d/20%d%d', [ // ((ADateCode shr 20) and 15), // month // ((ADateCode shr 16) and 15), // month // ((ADateCode shr 12) and 15), // day // ((ADateCode shr 8) and 15), // day // ((ADateCode shr 4) and 15), // year // ((ADateCode shr 0) and 15) // year // ] ); dd := (ClockCount * 10 {10 min for each count}) div 60 {min/hr} div 24 {hrs/days}; hh := (ClockCount * 10 {10 min for each count}) div 60 {min/hr} mod 24 {hrs remaining in last day}; mm := (ClockCount * 10 {10 min for each count}) mod 60 {min remaining in last hr}; if ShowDays then begin //result := format('%d days %.2d:%.2d hrs (%d)', [dd, hh, mm, ClockCount]); //debug //result := format('%.3d days %.2d:%.2d hrs', [dd, hh, mm]); result := format('%3d days %.2d:%.2d hrs', [dd, hh, mm]); end else begin result := format('%.2d:%.2d hrs', [hh, mm]); end; end;