/* Copyright 2025 by COG9 LLC
 * All rights reserved
 * Title: powerard.ino
 * Author: Jed Marti KI7NNP
 * Description: AREDN power box with 5,12,18 volt output. Monitors battery voltage and current
 *   draw.
 * Created: Sat Oct  4 10:25:04 2025
 * Revision History:
 */

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <stdint.h>
#include <Wire.h>

#include "powerard.h"
#include "ssd1306.h"
#include "ds1340.h"
#include "mcp9808.h"
#include "record.h"
#include "batv.h"
#include "led.h"
#include "push.h"
#include "screens.h"
#include "eepromconst.h"
#include "ina219.h"
#include "queue.h"
#include "graph.h"


// Serial input.
extern volatile uint8_t serialReady;

// The display object. Very inefficient, uses lots of RAM which is why we're using a 1284.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

extern uint8_t batState;

// See screens.ino
extern uint32_t whenLastShown;
extern int8_t   whichScreen;

// See record.ino. This is when the next sample should occur.
uint32_t nextSample;
extern uint8_t  recording;
extern uint16_t sampleMS;

// See graph.ino. When we should sample.
uint32_t nextGraph;
uint16_t graphMS;

// Configuration.
extern eePROMValues E;

// Graph queues.
Queue16 maA;
Queue16 maB;
Queue16 maC;
Queue8  TA;
Queue8  TB;
Queue8  TC;
Queue8  TAUX;
QueueF  BAT;


// Used everywhere to avoid println sending lf/cr.
void terpri(void) { Serial.print(F("\n")); }


void setup(void)
/*     Arduino first call.  Initialize everything. Start recording if one or more pushbuttons
 *   are pressed at startup.
 * Parameters: none
 * External References:
 *   Serial: Arduino serial port object. 115.2k baud
 *   Wire: I2C interface, runs at 400 kilohertz.
 *   nextGraph: Used time graphics update.
 *   nextSampe: Used to time sample collection.
 *   E: RAM copy of EEPROM storage.
 * Returned values: none
 * Errors detected: some bad stuff may halt startup.
 */
{
  char    msg[30];
  uint8_t rc;


  Serial.begin(115200);

  // Program control values.
  initEEPROM();
  
  // Initialize graphics queues instead of waiting around for serial to start.
  initGraphics();

  // Logo.
  sprintf(msg, "Powerard V%d.%02d.%03d\n", VERSION, RELEASE, PATCH);
  delay(35);
  Serial.print(msg);
  
  // Get configuration from EEPROM.
  if (E.eeOwner[0] != 0)
  {
    Serial.print("Owner: ");
    Serial.print(E.eeOwner);
    terpri();
  }

  // Battery - get constants from EEPROM or set defaults if not initialized.
  initBatv();
  
  // Fire up I2C, fast but not real fast for now.
  Serial.print(F("Starting I2C\n"));
  Wire.begin();
  Wire.setClock(400000);

  // Display After this we roll stuff.
  Serial.print(F("Starting Display\n"));
  initSSD1306();
  initRoll();
  rollString(msg);
  
  // Fire up RTC.
  rollString("Starting RTC");
  initDateTime();

  // Fire up Serial EEPROM
  rollString("Starting SEEPROM");
  initSEEPROM();

  // Temperature sensors.
  rollString("Starting temperature");
  initTempSensors();

  // current monitors.
  rollString("Starting current sensors");
  initRecorder();

  // Initializing LED.
  rollString("Starting LED");
  ledInit();
  ledBlink(25, 2000);

  // Battery monitor.
  rollString("Checking battery");
  Serial.print(F("Battery "));
  Serial.print(raw2Voltf(batRaw()));
  Serial.println(" volts");
  checkBatState();

  // EEPROM defaults should be set.
  updateEEPROM();

  rollString("Done");

  // Set up starting screen.
  initScreens();

  // Push buttons. If one or more pushed during startup, then start recording.
  rollString("Starting pushbuttons");
  rc = initPushButtons();
  if (rc > 0) autoStartRecording(rc);
  initPushInterrupts();
  
  // Our timer.
  nextGraph = nextSample = millis();

  Serial.print("?");
}



void loop(void)
/*     Called by Arduino OS when there's nothing to do. Keep serial port input, blink LED,
 *   sample data, record data, update graphics.
 * Parameters: none
 * External References:
 *   Serial: Arduino serial port object.
 *   batSate: What we think about the battery.
 *   nextSample, sampleMS: For data sampling timing.
 *   nextGraph: When to update graph data and dispolay.
 *   whenLastShown: When to update the screen.
 * Returned values: none
 * Errors detected: none here.
 */
{
  // Serial port. Collect characters asynchronously until a full line. Then parse the command.
  if (Serial.available() > 0) accumulateCharacter();
  if (serialReady) serialCommand();

  // Battery check. If it degrades too far then start shutting down.
  checkBatState();
  
  // Led.
  ledCheck();

  // Battery state check. No more recording if in bad state.
  //  if (batState == batDead) return;

  // We do the totals whether or not we're recording.
  if (millis() >= nextSample)
  {
    // Schedule the next sample time.
    nextSample = millis() + sampleMS;

    // Get the total even if not recording. 
    getLifeTime();

    // Now do the recording.
    if (recording) getReadings();
  }

  // Graphics raw data update.
  if (millis() >= nextGraph)
  {
    graphicsSample();
    nextGraph += graphMS;
  }
  
  // Update the current display screen.
  if ((millis() - whenLastShown) >= SCREENUPDATE)
  {      //      Serial.print("screen: "); Serial.println(whichScreen);
      showScreen();
  }
}



// EOF
