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:

  1. Startup
  2. Volume Control
  3. Push Button
  4. 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;