/*
* display.cpp
*
* Created on: 30 Nov 2020
* Author: mike
*/
#include "main.h"
#include "display.h"
#include "switches.h"
#include "nvram.h"
#include <cstring>
#include "libOLED/stm32_halDisplay.H"
#include "libOLED/fontclass.H"
#include "libOLED/displayDial.H"
#include "libPlx/displayInfo.H"
#include "libOLED/ap_math.h"
#include "splash.H"
namespace
{
int const WIDTH = 128;
int const HEIGHT = 64;
int const DISPLAY_RAMWIDTH = 132;
}
uint8_t displayBuffer[2][dataSize(WIDTH, HEIGHT)];
stm32_halDisplay_t displays[MAX_DISPLAYS] =
{stm32_halDisplay_t(WIDTH, HEIGHT, DISPLAY_RAMWIDTH, displayBuffer[0],
&hspi1,
SPI_CD_GPIO_Port,
SPI_CD_Pin,
SPI_RESET_GPIO_Port,
SPI_RESET_Pin,
SPI_NSS1_GPIO_Port,
SPI_NSS1_Pin),
stm32_halDisplay_t(WIDTH, HEIGHT,
DISPLAY_RAMWIDTH,
displayBuffer[1],
&hspi1,
SPI_CD_GPIO_Port,
SPI_CD_Pin,
SPI_RESET_GPIO_Port,
SPI_RESET_Pin,
SPI_NSS2_GPIO_Port,
SPI_NSS2_Pin)};
displayDial_t dials[MAX_DISPLAYS] =
{displayDial_t(displays[0], 64, 60, 60, 90), displayDial_t(displays[1], 64,
60, 60, 90)};
#if defined __cplusplus
extern "C"
{
#endif
static void
showMinMax(display_t &display, uint8_t dp_pos, int16_t int_min,
uint16_t int_max)
{
const char padding[]=" ";
// left justified display of minimum
int8_t width=display.fontSigDigits(small_font, 0, 0, 0, dp_pos, int_min, WHITE);
// pad with spaces if fewer than 6 characters are used.
if(width !=6)
display.printString(small_font,padding,6-width,WHITE);
display.gotoxy(0, 8);
display.printString(small_font, "Min", 3, WHITE);
// right justified display of maximum
width = display.fontSigDigits(small_font, 120, 0, 1, dp_pos, int_max, WHITE);
// right justified display of maximum : pad spaces to left
if(width !=6)
display.printString(small_font,padding,6-width,WHITE);
display.gotoxy(110, 8);
display.printString(small_font, "Max", 3, WHITE);
}
void
cc_init()
{
for (auto i = 0; i < MAX_DISPLAYS; i++)
{
display_t &display = displays[i];
if (i == 0)
display.reset();
display.init();
display.clearDisplay(BLACK);
displaySplash(display);
display.gotoxy(8, 32);
display.printString(large_font, i == 0 ? "1" : "2", 1, BLACK);
display.display();
}
HAL_Delay(1000);
for (auto i = 0; i < MAX_DISPLAYS; i++)
{
display_t &display = displays[i];
display.clearDisplay(BLACK);
display.setPixelMode(WHITE);
display.display();
context_t &context = contexts[i];
context.dial_timer = 200; // enough time to see at least one frame of PLX before NVRAM check
context.dial1 = -1;
context.OldObservation = -1;
context.OldObservationIndex = -1;
}
}
// Check to see if there is an observation/instance in the dynamic data array
// that matches the current observation/instance in the NVRAM
void
cc_check_nvram(int dialIndex)
{
if (dialIndex < 0 && dialIndex > MAX_DISPLAYS)
return;
context_t &context = contexts[dialIndex];
// check for timer timeout on consistent timer
if (context.dial_timer)
{
context.dial_timer--;
if (context.dial_timer == 0)
{
context.dial_timer = DialTimeout;
int i;
if (context.knobPos < 0)
{
for (i = 0; i < PLXItems; i++)
if (Info[i].observation == dial_nvram[dialIndex].data.observation && Info[i].instance == dial_nvram[dialIndex].data.instance)
{
context.knobPos = i;
return;
}
}
if (context.knobPos == -1)
context.knobPos = dialIndex; // timed out , not in NVRAM, use a default
// is this a change since the last timeout ?
if (Info[context.knobPos].observation != dial_nvram[dialIndex].data.observation || Info[context.knobPos].instance != dial_nvram[dialIndex].data.instance)
{
// store the observation and instance in the NVRAM, not dial position.
nvram_info_t curr_val;
curr_val.data.observation = Info[context.knobPos].observation;
curr_val.data.instance = Info[context.knobPos].instance;
uint32_t addr = (uint32_t)(&dial_nvram[dialIndex]);
WriteUint32NVRAM(addr, curr_val.u32);
}
}
}
}
int
cc_display(int dialIndex, int suppressIndex)
{
if (dialIndex < 0 && dialIndex > MAX_DISPLAYS)
return -1;
context_t &context = contexts[dialIndex];
displayDial_t &dial = dials[dialIndex];
stm32_halDisplay_t &display = displays[dialIndex];
int itemIndex = context.knobPos;
char buff[10];
int i;
// check for item suppression
if (itemIndex == suppressIndex)
{
context.dial1 = -1;
context.OldObservation = -1;
context.OldObservationIndex = -1;
display.clearDisplay();
display.display();
return -1; // we suppressed this display
}
// clear startup display off the screen
if (context.OldObservation == -1)
display.clearDisplay(BLACK);
int DataVal = Info[itemIndex].data; // data reading
int Observation = Info[itemIndex].observation;
int ObservationIndex = Info[itemIndex].instance;
// now to convert the readings and format strings
// find out limits
char *msg;
int len;
// if the user presses the dial then reset min/max to current value
if (push_pos[dialIndex] == 1)
{
Info[itemIndex].Max = DataVal;
Info[itemIndex].Min = DataVal; // 12 bit max value
}
if (Observation < PLX_MAX_OBS)
{
if (Observation != context.OldObservation || ObservationIndex != context.OldObservationIndex)
{
display.clearDisplay();
dial.draw_scale(DisplayInfo[Observation].Low,
DisplayInfo[Observation].High, 12, 1,
DisplayInfo[Observation].TickScale);
dial.draw_limits();
msg = DisplayInfo[Observation].name;
len = 7;
int len1 = ObservationIndex > 0 ? len - 1 : len;
for (i = 0; i < len1 && msg[i]; i++)
{
buff[i] = msg[i];
}
if (ObservationIndex > 0 && i < len)
{
buff[i++] = ObservationIndex + '1';
}
display.gotoxy(64 - i * 4, 48);
display.printString(large_font, buff, i, WHITE);
context.OldObservation = Observation;
context.OldObservationIndex = ObservationIndex;
context.dial1 = -1; // do not display old needl, cleared screen
display.display();
}
}
double max_rdg;
double min_rdg;
double cur_rdg;
int int_rdg;
int int_max;
int int_min;
max_rdg = ConveriMFDRaw2Data(Observation, DisplayInfo[Observation].Units,
Info[itemIndex].Max);
min_rdg = ConveriMFDRaw2Data(Observation, DisplayInfo[Observation].Units,
Info[itemIndex].Min);
cur_rdg = ConveriMFDRaw2Data(Observation, DisplayInfo[Observation].Units,
Info[itemIndex].data);
int dp_pos; // where to print the decimal place
float scale = 1.0;
switch (DisplayInfo[Observation].DP)
{
default:
case 0:
scale = 1.0;
dp_pos = display_t::NO_DECIMAL;
break;
case 1:
scale = 10.0;
dp_pos = 1;
break;
case 2:
scale = 100.0;
dp_pos = 2;
break;
}
int_rdg = (int)(cur_rdg * scale);
int_max = (int)(max_rdg * scale);
int_min = (int)(min_rdg * scale);
cur_rdg -= DisplayInfo[Observation].Low;
cur_rdg = ap_math::SINE_STEPS * cur_rdg / (DisplayInfo[Observation].High - DisplayInfo[Observation].Low);
context.dial0 = (int)cur_rdg;
display.gotoxy(32, 28);
display.fontDigits(large_font, 4, dp_pos, int_rdg, WHITE);
display.printString(small_font, DisplayInfo[Observation].suffix,
strlen(DisplayInfo[Observation].suffix));
display.printString(small_font, " ",
3 - strlen(DisplayInfo[Observation].suffix));
// print value overlaid by needle
/* old needle un-draw */
if (context.dial1 >= 0)
{
dial.draw_needle(context.dial1);
}
dial.draw_needle(context.dial0);
context.dial1 = context.dial0;
showMinMax(display, dp_pos, int_min, int_max);
display.gotoxy(0,32);
// display BT connection status
display.printString(small_font,btConnected() ? "\x81": " ",1);
display.display();
return itemIndex;
}
}