
#include "logBuffer.h"

#ifdef LOGGING_ENABLED

//log buffer and control
volatile logevent logBuffer[LOGBUFSIZE];
volatile int logCount;
volatile int logWriteIndex;
volatile byte logMode = LOGMODE_ROLL;
volatile byte trig_state;
volatile bool trig_ignore_state = true;
volatile byte trig_event;
volatile bool trig_ignore_event = true;
volatile int trig_count;
volatile bool trig_ignore_count = true;
volatile byte trig_flags = 0;
volatile byte trig_flagmask = 0;
volatile bool trig_ignore_flags = true;

void clearLogBuffer() {
  logCount = 0;
  logWriteIndex = 0;
}

void initLogBuffer() {
  clearLogBuffer();
  logMode = LOGMODE_STOP;
}

void startLog(byte theLogMode) {
  logMode = theLogMode;
}

extern void writeLog(byte sta, byte evt, int cnt, byte flgs, byte aux, String ltx) {
    if (logMode==LOGMODE_STOP) return;
    if (logMode==LOGMODE_TRIG_ONESHOT || logMode==LOGMODE_TRIG_ROLL) {
      if (((trig_ignore_state) || (sta==trig_state)) && 
          ((trig_ignore_event) || (evt==trig_event)) && 
          ((trig_ignore_count) || (cnt==trig_count)) && 
          ((trig_ignore_flags) || ((flgs & trig_flagmask)==trig_flags))) {
        logMode = (logMode==LOGMODE_TRIG_ONESHOT)?LOGMODE_ONESHOT:LOGMODE_ROLL;
      }
    }
    if ((logMode==LOGMODE_ROLL) ||
      ((logMode==LOGMODE_ONESHOT) && (logCount<LOGBUFSIZE))) {
      logBuffer[logWriteIndex].timestamp = micros();
      logBuffer[logWriteIndex].state = sta;
      logBuffer[logWriteIndex].event = evt;
      logBuffer[logWriteIndex].count = cnt;
      logBuffer[logWriteIndex].flags = flgs;
      logBuffer[logWriteIndex].auxData = aux;
      logBuffer[logWriteIndex].logtext = new String(ltx);
      logWriteIndex = (logWriteIndex>=LOGBUFSIZE)?0:(logWriteIndex+1);
      logCount = (logCount>=LOGBUFSIZE)?LOGBUFSIZE:logCount+1;
      if ((logMode==LOGMODE_ONESHOT) && (logCount>=LOGBUFSIZE)) logMode = LOGMODE_STOP;
    }
}

extern void writeLog(byte sta, byte evt, int cnt, byte flgs, byte aux) {
  writeLog(sta,evt,cnt,flgs,aux,"");
}

extern void writeLog(String ltx) {
  writeLog(0,0,0,0,0,ltx);
}

extern void dumpLogBuffer() {
  int i;
  int first;
  int c;
  int v;
  if (logCount>=LOGBUFSIZE) {
    first = (logWriteIndex<(LOGBUFSIZE-1))?logWriteIndex+1:0;
  } else {
    if (logWriteIndex>=logCount) {
      first = logWriteIndex-logCount;
    } else {
      first = LOGBUFSIZE-(logCount-logWriteIndex);
    }
  }
  long lastTS = logBuffer[first].timestamp;
  SERIAL_PRINTLN(F("====== Log Buffer ======="));
  SERIAL_PRINT(F("Mode:"));
  SERIAL_PRINT(logMode);
  SERIAL_PRINT(F(", Count: "));
  SERIAL_PRINT(logCount);
  SERIAL_PRINT(F(", writeIndex: "));
  SERIAL_PRINT(logWriteIndex);
  SERIAL_PRINT(F(", size: "));
  SERIAL_PRINTLN(LOGBUFSIZE);
  for (int i=first, c=logCount; c>0; c--) {
    SERIAL_PRINT(i);
    SERIAL_PRINT(F(": TIME="));
    SERIAL_PRINT(logBuffer[i].timestamp);
    SERIAL_PRINT(F("(+"));
    SERIAL_PRINT(logBuffer[i].timestamp-lastTS);
    lastTS = logBuffer[i].timestamp;
    SERIAL_PRINT(F("us).STATE="));
    SERIAL_PRINT(logBuffer[i].state);
    SERIAL_PRINT(F(".EVENT="));
    SERIAL_PRINT(logBuffer[i].event);
    SERIAL_PRINT(F(".COUNT.DIV="));
    v = logBuffer[i].count;
    SERIAL_PRINT(v%100);
    v = v / 100;
    SERIAL_PRINT(F(".COUNT.COL="));
    SERIAL_PRINT(v%100);
    v = v/100;
    SERIAL_PRINT(F(".COUNT.CHR="));
    SERIAL_PRINT(v);
    SERIAL_PRINT(F(".FLAGS=0b"));
    SERIAL_PRINT(logBuffer[i].flags,2);
    SERIAL_PRINT(F(".AUX=0x"));
    SERIAL_PRINTLN(logBuffer[i].auxData,16);
    SERIAL_PRINT(F(".LOGTEXT=\""));
    const char* cltx = logBuffer[i].logtext->c_str();
    SERIAL_PRINT(cltx);
    SERIAL_PRINTLN("\"");
    i++;
    if (i>=LOGBUFSIZE) i=0;
  }
  SERIAL_PRINTLN(F("========================"));
}

#endif
