// Full schematic and software for the controller
// of a missile launching vehicle
// by DedGzus
// Started on 1-17-2024
#include "LCDBank.h"
#include "ProcessManager.h"
#include "Process.h"
// global const defines
#define totalLCDs 2
// IO pin definitions
#define lcdDataPin 2
#define lcdShiftPin 3
#define lcdLatchPin 4
#define throttlePin A0
#define steeringPin A1
#define pitchPin A2
#define launchBtnPin 7
#define dirSwPin 8
// create the LCD Bank
LCDBank* pLcd;
// create the process manager
ProcessManager* pManager;
// global variables for controls
volatile byte launchBtn(HIGH);   // launches when set LOW
volatile byte dirSw(LOW);        // LOW = fwd, HIGH = rev
volatile int throttleRead(0);    // 0-1023 analog input for throttle
volatile int steeringRead(512);    // 0[right] 1023[left] 512[center]
volatile int pitchRead(512);       // 0[up] 1023[down] 512[center]
//--------------------------------------
// setup function
//--------------------------------------
void setup()
{
  // acquire an LCD bank
  pLcd = new LCDBank(lcdDataPin, lcdShiftPin, lcdLatchPin);
  // initialize the LCDs
  pLcd->init(totalLCDs);
  // acquire a process manager
  pManager = new ProcessManager();
  // start processes for reading input from controls
  pManager->attach(new digitalReadProcess(launchBtnPin, &launchBtn));
  pManager->attach(new digitalReadProcess(dirSwPin, &dirSw));
  pManager->attach(new analogReadProcess(throttlePin, &throttleRead));
  pManager->attach(new analogReadProcess(steeringPin, &steeringRead));
  pManager->attach(new analogReadProcess(pitchPin, &pitchRead));
  displaySetup();
}
//--------------------------------------
// main loop function
//--------------------------------------
void loop()
{
  // update processes
  pManager->onLoop();
  // update LCDs
  displayUpdate();
}
//--------------------------------------
// Setup the display
//--------------------------------------
void displaySetup()
{
  // clear all displays
  pLcd->all();
  pLcd->clear();
  // setup lcd 0
  pLcd->set(0);
  pLcd->pos(0, 0);
  pLcd->send("T: ");
  pLcd->sendI(mapPct(throttleRead));
  pLcd->send("%");
  pLcd->pos(0, 1);
  pLcd->send("S: ");
  writeSteering(steeringRead);
  pLcd->pos(8, 1);
  pLcd->send("P: ");
  writePitch(pitchRead);
  // setup lcd 1
  pLcd->set(1);
  pLcd->pos(0, 0);
  pLcd->send("L: ");
  pLcd->send(armedLaunch(launchBtn));
  pLcd->pos(0, 1);
  pLcd->send("D: ");
  pLcd->send(fwdRev(dirSw));
}
void displayUpdate()
{
  static int oldT, oldS, oldP;
  static byte oldD, oldL;
  // update lcd 0
  pLcd->set(0);
  // if throttle changes update on display
  int newVal = throttleRead;
  if (newVal != oldT)
  {
    pLcd->pos(3, 0);
    pLcd->send("    ");
    pLcd->pos(3, 0);
    pLcd->sendI(mapPct(newVal));
    pLcd->send("%");
    oldT = newVal;
  }
  // if steering changes update on display
  newVal = steeringRead;
  if (newVal != oldS)
  {
    pLcd->pos(3, 1);
    writeSteering(newVal);
    oldS = newVal;
  }
  // if pitch changes update on display
  newVal = pitchRead;
  if (newVal != oldP)
  {
    pLcd->pos(11, 1);
    writePitch(newVal);
    oldP = newVal;
  }
  // update lcd 1
  pLcd->set(1);
  // if launch button changes update on display
  newVal = launchBtn;
  if (newVal != oldL)
  {
    pLcd->pos(3, 0);
    pLcd->send(armedLaunch(newVal));
    oldL = newVal;
  }
  // if direction switch changes update on display
  newVal = dirSw;
  if (newVal != oldD)
  {
    pLcd->pos(3, 1);
    pLcd->send(fwdRev(newVal));
    oldD = newVal;
  }
}
char* fwdRev(byte sw)
{
  if(sw)
  {
    return "Reverse";
  }
  return "Forward";
}
char* armedLaunch(byte btn)
{
  if(btn)
  {
    return "Armed  ";
  }
  return "Launch!";
}
int mapPct(int val)
{
  return map(val,0,1023,0,100);
}
void writeSteering(int val)
{
  if(val==512)
  {
    pLcd->send("0   ");
  }
  if(val<512)
  {
    int i = map(val,511,0,1,100);
    pLcd->sendI(i);
    pLcd->send("R");
  }
  if(val>512)
  {
    int i = map(val,513,1023,1,100);
    pLcd->sendI(i);
    pLcd->send("L");
  }
}
void writePitch(int val)
{
  if(val==512)
  {
    pLcd->send("0   ");
  }
  if(val<512)
  {
    int i = map(val,511,0,1,100);
    pLcd->sendI(i);
    pLcd->send("D");
  }
  if(val>512)
  {
    int i = map(val,513,1023,1,100);
    pLcd->sendI(i);
    pLcd->send("U");
  }
}