#include <TeeGridBanner.h>
#include <Wire.h>
#include <ControlPCM186x.h>
#include <InputTDM.h>
#include <SDCard.h>
#include <RTClockDS1307.h>
#include <DeviceID.h>
#include <Blink.h>
#include <MicroConfig.h>
#include <LoggerSettings.h>
#include <BlinkSettings.h>
#include <InputTDMSettings.h>
#include <Timing.h>
#include <SetupPCM.h>
#include <InputMenu.h>
#include <RTClockMenu.h>
#include <SDCardMenu.h>
#include <ESensorsMenu.h>
#include <DiagnosticMenu.h>
#include <BlinkMenu.h>
#include <TeensyBoard.h>
#include <SensorsLogger.h>
#include <ESensors.h>
#include <TemperatureDS18x20.h>
#include <TemperatureDS3231.h>
#include <TemperatureSTS4x.h>
#include <LightBH1750.h>
#include <DigitalIOPCA9536.h>


// Default settings: ----------------------------------------------------------
// (may be overwritten by config file logger.cfg)
#define NCHANNELS           16    // number of channels (even, from 2 to 16)
#define SAMPLING_RATE    48000    // samples per second and channel in Hertz
#define PREGAIN            1.0    // gain factor of preamplifier
#define GAIN               0.0    // dB

#define LABEL            "logger"              // may be used for naming files
#define DEVICEID         -1                    // may be used for naming pathes and files
#define PATH             "LABELID2-SDATETIMEM" // folder where to store the recordings, may include LABEL, ID, IDA, DATE, SDATE, TIME, STIME, DATETIME, SDATETIME, NUM
#define FILENAME         "LABELID2-SDATETIME"  // ".wav" is appended, may include LABEL, ID, IDA, DATE, SDATE, TIME, STIME, DATETIME, SDATETIME, NUM, ANUM, COUNT
#define FILE_SAVE_TIME   5*60     // seconds
#define INITIAL_DELAY    10       // seconds
#define RANDOM_BLINKS    false    // set to true for blinking the status LED randomly (sync LED is always blinked randomly)
#define BLINK_TIMEOUT    0        // time after which status LEDs are switched off in seconds
#define SYNC_TIMEOUT     0        // time after which synchronization LEDs are switched off in seconds
#define SENSORS_INTERVAL 30.0     // interval between sensors readings in seconds
#define LIGHT_THRESHOLD  50.0     // threshold for switching off LEDs in lux.


// ----------------------------------------------------------------------------

#define LED_PIN          26       // R4.1

int DIPPins[] = { 34, 35, 36, 37, -1 }; // Device ID pins:

#define TEMP_PIN_R41     35       // pin for DATA line of DS18x20 themperature sensor for R4.1
#define TEMP_PIN_R41b     9       // pin for DATA line of DS18x20 themperature sensor for R4.1b
#define STS4x_ADDR  STS4x_ADDR2   // I2C address of STS4x temperature sensor


// ----------------------------------------------------------------------------

#define SOFTWARE      "TeeGrid R4-sensors-logger v3.8"

EXT_DATA_BUFFER(AIBuffer, NAIBuffer, 16*512*256)
InputTDM aidata(AIBuffer, NAIBuffer);
#define NPCMS 4
ControlPCM186x pcm1(Wire, PCM186x_I2C_ADDR1, InputTDM::TDM1);
ControlPCM186x pcm2(Wire, PCM186x_I2C_ADDR2, InputTDM::TDM1);
ControlPCM186x pcm3(Wire1, PCM186x_I2C_ADDR1, InputTDM::TDM2);
ControlPCM186x pcm4(Wire1, PCM186x_I2C_ADDR2, InputTDM::TDM2);
Device *pcms[NPCMS] = {&pcm1, &pcm2, &pcm3, &pcm4};

RTClockDS1307 rtclock;
DeviceID deviceid(DEVICEID);
DigitalIOPCA9536 gpio;
Blink blink("Status", LED_BUILTIN);
Blink errorblink("Error");
Blink syncblink("Synchronization", LED_PIN, true);
SDCard sdcard;

ESensors sensors;
TemperatureDS3231 temprtc(&sensors);
TemperatureDS18x20 temp(&sensors);
TemperatureSTS4x tempsts(&sensors);
LightBH1750 light1(&sensors);
LightBH1750 light2(&sensors);

Config config("logger.cfg", &sdcard);
LoggerSettings settings(config, LABEL, DEVICEID, PATH, FILENAME, FILE_SAVE_TIME);
InputTDMSettings aisettings(config, SAMPLING_RATE, NCHANNELS, GAIN, PREGAIN);
Timing timing(config, INITIAL_DELAY, "", "", SENSORS_INTERVAL);
BlinkSettings blinksettings(config, RANDOM_BLINKS, BLINK_TIMEOUT, SYNC_TIMEOUT,
			    LIGHT_THRESHOLD);

RTClockMenu rtclock_menu(config, rtclock);
ConfigurationMenu configuration_menu(config, sdcard);
SDCardMenu sdcard_menu(config, sdcard);
FirmwareMenu firmware_menu(config, sdcard);
InputMenu input_menu(config, aidata, aisettings, pcms, NPCMS, R4SetupPCMs);
ESensorsMenu sensors_menu(config, sensors);
DiagnosticMenu diagnostic_menu(config, &pcm1, &pcm2, &pcm3, &pcm4,
                               &rtclock, &gpio);
DeviceIDAction deviceid_act(diagnostic_menu, &deviceid); 
BlinkMenu blink_menu(diagnostic_menu, &blink, &errorblink, &syncblink);
Menu ampl_info(diagnostic_menu, "Amplifier board");
HelpAction help_act(config, "Help");

SensorsLogger logger(aidata, sensors, sdcard, rtclock,
                     blink, errorblink, syncblink);


void setupLEDs() {
  Wire2.begin();
  gpio.begin(Wire2);
  if (gpio.available()) {
    blink.setPin(gpio, 0);
    errorblink.setPin(gpio, 1);
    syncblink.setPin(gpio, 3);
    errorblink.switchOff();
    syncblink.switchOff();
  }
  blink.switchOn();
}


void setupMenu() {
  settings.setDeviceIDDevice();
  aisettings.setRateSelection(ControlPCM186x::SamplingRates,
                              ControlPCM186x::MaxSamplingRates);
  aisettings.enable("Pregain");
  timing.enable("StartTime");
  timing.enable("StopTime");
  timing.enable("SensorsInterval");
  blinksettings.enable("RandomBlinks");
  blinksettings.enable("BlinkTimeout");
  blinksettings.enable("SyncTimeout");
  sdcard_menu.CleanRecsAct.setRemove(true);
}


bool setupBoard() {
  Wire.begin();
  Wire1.begin();
  rtclock.begin();
  rtclock.check();
  bool R41b = (strncmp(rtclock.chip(), "DS", 2) == 0);
  if (R41b) {
     deviceid.setPins(DIPPins);
     settings.setDeviceIDAdmin();
     ampl_info.addConstString("Version", "R4.1b");
  }
  else {
     logger.R41powerDownCAN();
     ampl_info.addConstString("Version", "R4.1");
  }
  sdcard.begin();
  return R41b;
}


void setupSensors(int temp_pin) {
  temprtc.begin(Wire);
  temprtc.setName("logger-temperature");
  temprtc.setSymbol("Ti");
  temp.begin(temp_pin);
  temp.setName("water-temperature");
  temp.setSymbol("Tw");
  gpio.setMode(2, INPUT);
  light1.begin(Wire2, BH1750_TO_GROUND);
  //light1.setAutoRanging();
  light1.setQuality(BH1750_QUALITY_HIGH2);
  light1.setName("illuminance1");
  light1.setSymbol("I1");
  light2.begin(Wire2, BH1750_TO_VCC);
  //light2.setAutoRanging();
  light2.setQuality(BH1750_QUALITY_HIGH2);
  light2.setName("illuminance2");
  light2.setSymbol("I2");
  tempsts.begin(Wire2, STS4x_ADDR);
  tempsts.setPrecision(STS4x_HIGH);
  logger.setupSensors();
  if (light1.available() || light2.available())
    blinksettings.enable("LightThreshold");
}


// -----------------------------------------------------------------------------

void setup() {
  setupLEDs();
  setupMenu();
  Serial.begin(9600);
  while (!Serial && millis() < 2000) {};
  printTeeGridBanner(SOFTWARE);
  bool R41b = setupBoard();
  setupSensors(R41b ? TEMP_PIN_R41b : TEMP_PIN_R41);
  logger.configure(config);
  powerdownPCMs(pcms, NPCMS);
  logger.snooze(timing.startTime());
  logger.startSensors(timing.sensorsInterval(), blinksettings.lightThreshold());
  logger.reportBlink();
  logger.setCPUSpeed(aisettings.rate());
  deviceid.setID(settings.deviceID());
  if (R41b && deviceid.id() == -1)
    deviceid.read();
  settings.preparePaths(deviceid);
  R4SetupPCMs(aidata, aisettings, pcms, NPCMS);
  logger.startInput(aisettings.nchannels());
  logger.setup(settings.path(), settings.fileName(),
               SOFTWARE, blinksettings.randomBlinks(),
	       blinksettings.blinkTimeout(),
	       blinksettings.syncTimeout());
  logger.initialDelay(timing.initialDelay(), timing.stopTime());
  diagnostic_menu.updateCPUSpeed();
  logger.start(settings.fileTime(), config, ampl_info);
}


void loop() {
  logger.update();
}
