//
// Functions associated with display data at the bottom of the TFT display
// these are run under Core0 and called from there

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

void Display_AccOffsets() {
  // called to display the accelerometer offsets
  //  Display_Clear();
  Display_TextLft(42, 0,"Acc X = " + String(AccRawX),2);
  Display_TextLft(42,20,"Acc Y = " + String(AccRawY),2);
  Display_TextLft(42,40,"Acc Z = " + String(AccRawZ),2);
  DispMode = 0; // only drawn once
  StatMode = 0; // don't include status
}

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

void Display_Active() {
  // display the ACTIVE message
  Message$ = "ACTIVE";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 3000; // display for 3 seconds
}

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

void Display_AngleAcc() {
  // displays the accelerometer angle
  Message$ = " A=" + String(angle_acc,1) + Deg + " ";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 200; // update at 4Hz
}

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

void Display_AngleGyro() {
  // displays the combined gyro angle
  Message$ = " G=" + String(angle_gyro,1) + Deg + " ";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 200; // update at 4Hz
}

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

void Display_Autonomous() {
  // display the AUTONOMOUS message
  Message$ = "AUTONOMOUS";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_Balance() {
  // display the BALANCE message
  Message$ = "BALANCE";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_BattLow() {
  // critical battery condition
  Message$ = "BATTERY LOW";
  Display_TextCtr(120,0,Message$,3);
  DispMode = 0; FaceShow = 0; StatMode = 0;
}

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

void Display_Calibrating() {
  // display the CALIBRATING message
  Message$ = "CALIBRATING";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 10000; // update every 10 seconds
}

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

void Display_Clear() {
  // erases the bottom part of the display, 240x64 pixel area
  tft.fillRect(0,256,240,64,DispCol);
  if (TEST) {tft.drawRect(0,0,scr_w,scr_h,ILI9341_WHITE);}  // outer border 240x320}
}

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

void Display_Gear() {
  // display the Gear change message
  Message$ = "GEAR " + String(Gear);
  Display_TextCtr(120,0,Message$,3);
  DispDel = 3000; // display for 3 seconds
}

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

void Display_GyrOffsets() {
  // called to display the gyro offsets
  // if not in TEST mode it will revert to displaying gyro angles
  Status_Clear(); // remove the status line
  Display_TextLft(42, 0,"Gyr X = " + String(GyrRawX),2);
  Display_TextLft(42,20,"Gyr Y = " + String(GyrRawY),2);
  Display_TextLft(42,40,"Gyr Z = " + String(GyrRawZ),2);
  if (!TEST) {DispDel = 3000; DispMode = 5; StatDel = 3000;}
  else {DispMode = 0;}  // only drawn once in TEST mode
}

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

void Display_Happy() {
  // display the Happy! message
  Message$ = "HAPPY!";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // update every second
}

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

void Display_Intro() {
  // used immediately after reset
  //  Display_Clear();  // blank out the lower portion 240x64 of the display
  Display_TextCtr(120,0,"BalanceBot",2);
  Display_TextCtr(120,20,"Mk1",2);
  if (TEST) {tft.drawRect(0,0,scr_w,scr_h,ILI9341_WHITE);}  // outer border 240x320}
  DispMode = 0; // only drawn once
  StatMode = 0;
}

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

void Display_Mirrored() {
  // display robot type when DispMon is first connected
  // we clear current flags so that this is displayed immediately
  
  Display_clear();      // remove current display content
  Display_display();    // clears mirrored display immediately
  if (Brightness != 255) {Display_setBrightness(255);}  // display may be in sleep mode
  // Y64 vertical text spacing, from Y=0 to Y=63
  // 0123456789012345678901234567890123456789012345678901234567890123
  //      1111111111111111 2222222222222222           3333333333
  Display_setFont(16); Display_setColor(WHITE);
  Display_setTextAlignment(TEXT_ALIGN_CENTER);
  Display_drawString(64, 5, "BalanceBot");
  Display_setFont(10);
  Display_drawString(64,22, "Mk1 vR1");
  Display_drawString(64,49, "Display Mirror");
  Display_display();    // display immediately
  DispCnt = 2;          // hold this for a short period
}

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

void Display_Pilot() {
  // display the PILOT ON message
  Message$ = "PILOT";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_Play() {
  // display the PLAY ON message
  Message$ = "PLAY";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_P_Only() {
  // display the P ONLY message
  Message$ = "P Only";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_Range() {
  // display the LTOF range message
  if (Range > 500) {
    Message$ = " <500>mm ";
    Display_TextCtr(120,0,Message$,3);
  } else {
    Message$ = " " + String(Range) + "mm ";
    Display_TextCtr(120,0,Message$,3);
  }
  DispDel = 200; // update every second
}

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

void Display_Ready() {
  // display the Ready message
  Message$ = "READY";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // update every second
}

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

void Display_Safe() {
  // display the SAFE message
  Message$ = "SAFE";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 1000; // display for 1 second
}

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

void Display_Sleeping() {
  // display SLEEPING
  Message$ = "SLEEPING";
  Display_TextCtr(120,0,Message$,3);
  DispDel = 10000; // update every 10 seconds
}

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

void Display_Status() {
  // called whenever the Display Monitor app is connected as part, of OLED update
  // a counter is used initially to hold the mirrored statement
  if (DispCnt > 0) {DispCnt--; return;}

  // then after that we limit updates to 4 per second
  if ((millis() - Dispms) >= 250) {
    Dispms = millis();
    Display_clear();      // remove current display content
    // Y64 vertical text spacing, from Y=0 to Y=63
    // 0123456789012345678901234567890123456789012345678901234567890123
    //      1111111111111111                            2222222222
    Display_setFont(16); Display_setColor(WHITE);
    Display_setTextAlignment(TEXT_ALIGN_CENTER);
    Display_drawString(64, 5, Message$);
    Display_setFont(10);
    Display_drawString(64,49,Status$);
    Display_display();    // display immediately
  }
}

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

void Display_TextCtr(int16_t zX,int16_t zY,String zT$,uint8_t zS) {
  // displays text zT$ centred on zX,zY in the display area in font size zS
  zY+= 256; // change zY co-ordinate for display area
  tft.setTextSize(zS);  // size 1, fonts are 6-bits wide, 8-bits heigh
  zX = zX - ((zT$.length() * zS * 6)/2);
  tft.setCursor(zX,zY);
  tft.setTextColor(TextCol,DispCol);
  tft.print(zT$);
}

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

void Display_TextLft(int16_t zX,int16_t zY,String zT$,uint8_t zS) {
  // displays text zT$, left justified, at zX,zY in the display area in font size zS
  zY+= 256; // change zY co-ordinate for display area
  tft.setTextSize(zS);  // size 1, fonts are 6-bits wide, 8-bits heigh
  tft.setCursor(zX,zY);
  tft.setTextColor(TextCol,DispCol);
  tft.print(zT$);
}

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

void Display_TextRht(int16_t zX,int16_t zY,String zT$,uint8_t zS) {
  // displays text zT$, right justified, at zX,zY in the display area in font size zS
  zY+= 256; // change zY co-ordinate for display area
  tft.setTextSize(zS);  // size 1, fonts are 6-bits wide, 8-bits heigh
  zX = zX - (zT$.length() * zS * 6);
  tft.setCursor(zX,zY);
  tft.setTextColor(TextCol,DispCol);
  tft.print(zT$);
}

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

void Status_Auto() {
  // this function automatically selected the status data to present
  // periodically it will display battery status
  int16_t zSA = 1;
  if (safeMode == 4) {
    if (pid_setpoint != 0.0) {zSA = 3;} // PID setpoint
    else {zSA = 2;}                     // PID self balance setpoint
  }
  if (StatSet > 0) {zSA = StatSet;}     // user has selected a specific status mode
  StatCnt++; if (StatCnt > 100) {StatCnt = 0; zSA = 1;} // occasionally show a battery reading
  if (zSA != StatAuto) {Status_Clear();}
  switch (zSA) {
    case  1: Status_Batteries(); break;
    case  2: Status_PIDselfBal(); break;
    case  3: Status_PIDsetfPnt(); break;
    case  4: Status_PIDoutput(); break;
    case  5: Status_PID_PWM(); break;
    case  6: Status_SbTrend(); break;
    case  7: Status_Trip(); break;
    case  8: Status_Slots(); break;
    case  9: Status_SlotCnts(); break;
    case 10: Status_RPM(); break;
    case 11: Status_PwmTrend(); break;
  }
  StatAuto = zSA;
}

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

void Status_Batteries() {
  // display battery status on bottom line
  AnyLong = (BatAvg - BatCritical)*100/(BatMax - BatCritical);
  if (AnyLong > 100) {AnyLong = 100;} // limit max to 100%
  if (AnyLong < 0) {AnyLong = 0;}     // limit min to 0%
  Status$ = " Batt " + String((float(BatAvg)/BatCal),1) + "v " + String(AnyLong) + "% ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 1000; // update every second
}

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

void Status_Clear() {
  // erases the bottom status part of the display, 240x16 pixel area
  tft.fillRect(0,304,240,16,DispCol);
  if (TEST) {tft.drawRect(0,0,scr_w,scr_h,ILI9341_WHITE);}  // outer border 240x320}
}

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

void Status_PIDoutput() {
  // display the value of PID output  
  Status$ = " PID O/p=" + String(pid_output,2) + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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

void Status_PID_PWM() {
  // display the value of PID output  
  Status$ = " PID PWM=" + String(pid_PWM,2) + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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

void Status_PIDselfBal() {
  // display PID self balance point status on bottom line
  Status$ = " PID SpB=" + String(self_balance_pid_setpoint,2) + Deg + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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

void Status_PIDsetfPnt() {
  // display PID self balance point status on bottom line
  Status$ = " PID Sp=" + String(pid_setpoint,2) + Deg + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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

void Status_PwmTrend() {
  // display the values of DIR_LTnd nad DIR_RTnd
  Status_Clear();
  Display_TextLft(  0,48,String(DIR_RTnd),2);
  Display_TextCtr(120,48,"PwmTrend=",2);
  Display_TextRht(239,48,String(DIR_LTnd),2);
  StatDel = 200; // update 200ms
}

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

void Status_RPM() {
  // display the value of slot rpms  
  Status_Clear();
  Display_TextLft(  0,48,String(Int35RPM),2);
  Display_TextCtr(120,48,"RPM",2);
  Display_TextRht(239,48,String(Int34RPM),2);
  StatDel = 100; // update 200ms
}

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

void Status_SbTrend() {
  // display the value of PID output  
  Status$ = " SbTrend=" + String(pid_output_trend) + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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

void Status_SlotCnts() {
  // display the count value of each slot sensor  
  Status_Clear();
  Display_TextLft(  0,48,String(IntP35Cnt),2);
  Display_TextCtr(120,48," Count ",2);
  Display_TextRht(239,48,String(IntP34Cnt),2);
  Display_TextCtr(120,48," Count ",2);
  StatDel = 100; // update 200ms
}

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

void Status_Slots() {
  // display the value of each slot sensor  
  String zT$ = " ";
  if (IntP35State) {zT$ = "1";} else {zT$ = "0";}
  Display_TextLft(  0,48,zT$,2);
  Display_TextCtr(120,48," Slots ",2);
  if (IntP34State) {zT$ = "1";} else {zT$ = "0";}
  Display_TextRht(239,48,zT$,2);
  StatDel = 200; // update 200ms
}

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

void Status_Trip() {
  // display the value of Trip
  Status$ = " Trip=" + String(Trip) + " ";
  Display_TextCtr(120,48,Status$,2);
  StatDel = 200; // update 200ms
}

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