OLED working with small fonts, update @100ms
Now restart Serial1 if CRC errors or other issues with reception
This commit is contained in:
parent
9d79c107c5
commit
a36af395ea
5 changed files with 278 additions and 122 deletions
|
@ -180,7 +180,6 @@ void Adafruit_SH1106::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) {
|
|||
|
||||
// set pin directions
|
||||
if (sid != -1){
|
||||
Serial.println("SH1106 pin set");
|
||||
pinMode(dc, OUTPUT);
|
||||
pinMode(cs, OUTPUT);
|
||||
csport = portOutputRegister(digitalPinToPort(cs));
|
||||
|
@ -197,7 +196,6 @@ void Adafruit_SH1106::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) {
|
|||
mosipinmask = digitalPinToBitMask(sid);
|
||||
}
|
||||
if (hwSPI){
|
||||
Serial.println("SH1106 SPI begin");
|
||||
SPI.begin ();
|
||||
#ifdef __SAM3X8E__
|
||||
SPI.setClockDivider (9); // 9.3 MHz
|
||||
|
@ -527,8 +525,6 @@ void Adafruit_SH1106::display(void) {
|
|||
TWBR = 12; // upgrade to 400KHz!
|
||||
#endif
|
||||
#endif
|
||||
//Serial.println(TWBR, DEC);
|
||||
//Serial.println(TWSR & 0x3, DEC);
|
||||
|
||||
// I2C
|
||||
for (int8_t i = (SH1106_LCDHEIGHT/8)-1; i >= 0; i--)
|
||||
|
|
|
@ -109,13 +109,16 @@ static UARTClass& BlueWireSerial(Serial1);
|
|||
static HardwareSerial& BlueWireSerial(Serial1);
|
||||
#endif
|
||||
|
||||
void initBlueWireSerial();
|
||||
bool validateFrame(const CProtocol& frame, const char* name);
|
||||
|
||||
// DS18B20 temperature sensor support
|
||||
OneWire ds(DS18B20_Pin); // on pin 5 (a 4.7K resistor is necessary)
|
||||
DallasTemperature TempSensor(&ds);
|
||||
long lastTemperatureTime; // used to moderate DS18B20 access
|
||||
unsigned long lastAnimationTime;
|
||||
float fFilteredTemperature = 0;
|
||||
const float fAlpha = 0.995;
|
||||
const float fAlpha = 0.95;
|
||||
|
||||
CommStates CommState;
|
||||
CTxManage TxManage(TxEnbPin, BlueWireSerial);
|
||||
|
@ -127,7 +130,10 @@ CSmartError SmartError;
|
|||
sRxLine PCline;
|
||||
long lastRxTime; // used to observe inter character delays
|
||||
bool hasOEMController = false;
|
||||
bool stateDebug = false;
|
||||
bool verboseDebug = false;
|
||||
|
||||
const CProtocol* pRxFrame = NULL;
|
||||
const CProtocol* pTxFrame = NULL;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -213,18 +219,7 @@ void setup() {
|
|||
pinMode(LED_Pin, OUTPUT); // On board LED indicator
|
||||
digitalWrite(LED_Pin, LOW);
|
||||
|
||||
// initialize serial port to interact with the "blue wire"
|
||||
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
||||
// Tx/Rx data to/from heater,
|
||||
// Note special baud rate for Chinese heater controllers
|
||||
#if defined(__arm__) || defined(__AVR__)
|
||||
BlueWireSerial.begin(25000);
|
||||
pinMode(Rx1Pin, INPUT_PULLUP); // required for MUX to work properly
|
||||
#elif ESP32
|
||||
// ESP32
|
||||
BlueWireSerial.begin(25000, SERIAL_8N1, Rx1Pin, Tx1Pin); // need to explicitly specify pins for pin multiplexer!
|
||||
pinMode(Rx1Pin, INPUT_PULLUP); // required for MUX to work properly
|
||||
#endif
|
||||
initBlueWireSerial();
|
||||
|
||||
// prepare for first long delay detection
|
||||
lastRxTime = millis();
|
||||
|
@ -248,6 +243,7 @@ void setup() {
|
|||
pNVStorage = &NVStorage;
|
||||
pNVStorage->init();
|
||||
pNVStorage->load();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -317,8 +313,8 @@ void loop()
|
|||
val--;
|
||||
bSendVal = true;
|
||||
}
|
||||
else if(rxVal == 's') {
|
||||
stateDebug = !stateDebug;
|
||||
else if(rxVal == 'v') {
|
||||
verboseDebug = !verboseDebug;
|
||||
}
|
||||
}
|
||||
if(bSendVal) {
|
||||
|
@ -361,6 +357,8 @@ void loop()
|
|||
DebugPort.println("Timeout collecting BTC heater response data, returning to Idle State");
|
||||
}
|
||||
|
||||
DebugPort.println("\007Recycling blue wire serial interface");
|
||||
initBlueWireSerial();
|
||||
CommState.set(CommStates::Idle); // revert to idle mode
|
||||
}
|
||||
}
|
||||
|
@ -370,21 +368,21 @@ void loop()
|
|||
// Reads data from the "blue wire" Serial port, (to/from heater)
|
||||
// If an OEM controller exists we will also see it's data frames
|
||||
// Note that the data is read now, then held for later use in the state machine
|
||||
//s
|
||||
//
|
||||
sRxData BlueWireData;
|
||||
|
||||
if (BlueWireSerial.available()) {
|
||||
// Data is avaialable, read and store it now, use it later
|
||||
// Note that if not in a recognised data receive frame state, the data
|
||||
// will be deliberately lost!
|
||||
unsigned long dT = timenow - lastRxTime;
|
||||
lastRxTime = timenow; // tickle last rx time, for rx data timeout purposes
|
||||
BlueWireData.setValue(BlueWireSerial.read()); // read hex byte, store for later use
|
||||
|
||||
if(stateDebug) {
|
||||
Serial.print("dT{");
|
||||
Serial.print(dT);
|
||||
Serial.print("}");
|
||||
unsigned long dT = timenow - lastRxTime;
|
||||
lastRxTime = timenow; // tickle last rx time, for rx data timeout purposes
|
||||
if(verboseDebug) {
|
||||
DebugPort.print("dT{");
|
||||
DebugPort.print(dT);
|
||||
DebugPort.print("}");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -397,14 +395,14 @@ void loop()
|
|||
|
||||
case CommStates::Idle:
|
||||
|
||||
if(stateDebug) {
|
||||
Serial.print(":0");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":0");
|
||||
}
|
||||
|
||||
// only update OLED when not processing blue wire
|
||||
tDelta = timenow - lastAnimationTime;
|
||||
if(tDelta >= 250) {
|
||||
lastAnimationTime += 250;
|
||||
if(tDelta >= 100) {
|
||||
lastAnimationTime += 100;
|
||||
animateOLED();
|
||||
}
|
||||
|
||||
|
@ -444,8 +442,8 @@ void loop()
|
|||
|
||||
|
||||
case CommStates::OEMCtrlRx:
|
||||
if(stateDebug) {
|
||||
Serial.print(":1");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":1");
|
||||
}
|
||||
|
||||
#if RX_LED == 1
|
||||
|
@ -453,8 +451,8 @@ void loop()
|
|||
#endif
|
||||
// collect OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if(stateDebug) {
|
||||
Serial.print(",RD1");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(",RD1");
|
||||
}
|
||||
if(CommState.collectData(OEMCtrlFrame, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::OEMCtrlReport); // collected 24 bytes, move on!
|
||||
|
@ -464,12 +462,18 @@ void loop()
|
|||
|
||||
|
||||
case CommStates::OEMCtrlReport:
|
||||
if(stateDebug) {
|
||||
Serial.print(":2");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":2");
|
||||
}
|
||||
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, LOW);
|
||||
#endif
|
||||
// test for valid CRC, abort and restarts Serial1 if invalid
|
||||
if(!validateFrame(OEMCtrlFrame, "OEM")) {
|
||||
break;
|
||||
}
|
||||
|
||||
// filled OEM controller frame, report
|
||||
// echo received OEM controller frame over Bluetooth, using [OEM] header
|
||||
// note that Rotary Knob and LED OEM controllers can flood the Bluetooth
|
||||
|
@ -488,16 +492,16 @@ void loop()
|
|||
|
||||
|
||||
case CommStates::HeaterRx1:
|
||||
if(stateDebug) {
|
||||
Serial.print(":3");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":3");
|
||||
}
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, HIGH);
|
||||
#endif
|
||||
// collect heater frame, always in response to an OEM controller frame
|
||||
if(BlueWireData.available()) {
|
||||
if(stateDebug) {
|
||||
Serial.print(",RD2");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(",RD2");
|
||||
}
|
||||
if( CommState.collectData(HeaterFrame1, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport1);
|
||||
|
@ -507,12 +511,18 @@ void loop()
|
|||
|
||||
|
||||
case CommStates::HeaterReport1:
|
||||
if(stateDebug) {
|
||||
Serial.print(":4");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":4");
|
||||
}
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, LOW);
|
||||
#endif
|
||||
|
||||
// test for valid CRC, abort and restarts Serial1 if invalid
|
||||
if(!validateFrame(HeaterFrame1, "RX1")) {
|
||||
break;
|
||||
}
|
||||
|
||||
// received heater frame (after controller message), report
|
||||
|
||||
// do some monitoring of the heater state variable
|
||||
|
@ -545,14 +555,17 @@ void loop()
|
|||
CommState.set(CommStates::BTC_Tx);
|
||||
}
|
||||
else {
|
||||
CommState.set(CommStates::Idle); // "Listen Only" input is held low, don't send out Tx
|
||||
// CommState.set(CommStates::Idle); // "Listen Only" input is held low, don't send out Tx
|
||||
pRxFrame = &HeaterFrame1;
|
||||
pTxFrame = &OEMCtrlFrame;
|
||||
CommState.set(CommStates::TemperatureRead); // "Listen Only" input is held low, don't send out Tx
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::BTC_Tx:
|
||||
if(stateDebug) {
|
||||
Serial.print(":5");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":5");
|
||||
}
|
||||
// Handle time interval where we send data to the blue wire
|
||||
lastRxTime = timenow; // *we* are pumping onto blue wire, track this activity!
|
||||
|
@ -567,33 +580,52 @@ void loop()
|
|||
|
||||
|
||||
case CommStates::HeaterRx2:
|
||||
if(stateDebug) {
|
||||
Serial.print(":6");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":6");
|
||||
}
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, HIGH);
|
||||
#endif
|
||||
// collect heater frame, in response to our control frame
|
||||
if(BlueWireData.available()) {
|
||||
if(stateDebug) {
|
||||
Serial.print(",RD(");
|
||||
Serial.print(BlueWireData.getValue(), HEX);
|
||||
Serial.print(")");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(",RD(");
|
||||
DebugPort.print(BlueWireData.getValue(), HEX);
|
||||
DebugPort.print(")");
|
||||
}
|
||||
if( CommState.collectDataEx(HeaterFrame2, BlueWireData.getValue()) ) {
|
||||
#ifdef BADSTARTCHECK
|
||||
if(!CommState.checkValidStart(BlueWireData.getValue())) {
|
||||
DebugPort.println("***** \007 Invalid start of frame - restarting Serial port *****");
|
||||
initBlueWireSerial();
|
||||
CommState.set(CommStates::Idle);
|
||||
}
|
||||
else {
|
||||
if( CommState.collectData(HeaterFrame2, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if( CommState.collectData(HeaterFrame2, BlueWireData.getValue()) ) {
|
||||
CommState.set(CommStates::HeaterReport2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CommStates::HeaterReport2:
|
||||
if(stateDebug) {
|
||||
Serial.print(":7");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":7");
|
||||
}
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, LOW);
|
||||
#endif
|
||||
|
||||
// test for valid CRC, abort and restarts Serial1 if invalid
|
||||
if(!validateFrame(HeaterFrame2, "RX2")) {
|
||||
break;
|
||||
}
|
||||
|
||||
// received heater frame (after our control message), report
|
||||
|
||||
// do some monitoring of the heater state variables
|
||||
|
@ -603,29 +635,30 @@ void loop()
|
|||
delay(5);
|
||||
if(!hasOEMController) {
|
||||
// only convey these frames to Bluetooth when NOT using an OEM controller!
|
||||
// Bluetooth.sendFrame("[BTC]", TxManage.getFrame(), TERMINATE_BTC_LINE); // BTC => Bluetooth Controller :-)
|
||||
Bluetooth.sendFrame("[HTR]", HeaterFrame2, true); // pin not grounded, suppress duplicate to BT
|
||||
}
|
||||
CommState.set(CommStates::TemperatureRead);
|
||||
pRxFrame = &HeaterFrame2;
|
||||
pTxFrame = &TxManage.getFrame();
|
||||
break;
|
||||
|
||||
case CommStates::TemperatureRead:
|
||||
if(stateDebug) {
|
||||
Serial.print(":8");
|
||||
if(verboseDebug) {
|
||||
DebugPort.print(":8");
|
||||
}
|
||||
// update temperature reading,
|
||||
// synchronised with serial reception as interrupts do get disabled in the OneWire library
|
||||
unsigned Tdelta = timenow - lastTemperatureTime;
|
||||
if(Tdelta > TEMPERATURE_INTERVAL) { // maintain a minimum holdoff period
|
||||
tDelta = timenow - lastTemperatureTime;
|
||||
if(tDelta > TEMPERATURE_INTERVAL) { // maintain a minimum holdoff period
|
||||
lastTemperatureTime += TEMPERATURE_INTERVAL; // reset time to observe temeprature
|
||||
fTemperature = TempSensor.getTempCByIndex(0); // read sensor
|
||||
// exponential mean to stabilse readings
|
||||
fFilteredTemperature = fFilteredTemperature * (1-fAlpha) + fAlpha * fTemperature;
|
||||
fFilteredTemperature = fFilteredTemperature * fAlpha + (1-fAlpha) * fTemperature;
|
||||
DefaultBTCParams.setTemperature_Actual((unsigned char)(fFilteredTemperature + 0.5)); // update [BTC] frame to send
|
||||
TempSensor.requestTemperatures(); // prep sensor for future reading
|
||||
|
||||
updateOLED(TxManage.getFrame(), HeaterFrame2);
|
||||
|
||||
// updateOLED(TxManage.getFrame(), HeaterFrame2);
|
||||
updateOLED(*pTxFrame, *pRxFrame);
|
||||
}
|
||||
CommState.set(CommStates::Idle);
|
||||
break;
|
||||
|
@ -729,3 +762,36 @@ void Command_Interpret(const char* pLine)
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
void initBlueWireSerial()
|
||||
{
|
||||
// initialize serial port to interact with the "blue wire"
|
||||
// 25000 baud, Tx and Rx channels of Chinese heater comms interface:
|
||||
// Tx/Rx data to/from heater,
|
||||
// Note special baud rate for Chinese heater controllers
|
||||
#if defined(__arm__) || defined(__AVR__)
|
||||
BlueWireSerial.begin(25000);
|
||||
pinMode(Rx1Pin, INPUT_PULLUP); // required for MUX to work properly
|
||||
#elif ESP32
|
||||
// ESP32
|
||||
BlueWireSerial.begin(25000, SERIAL_8N1, Rx1Pin, Tx1Pin); // need to explicitly specify pins for pin multiplexer!
|
||||
pinMode(Rx1Pin, INPUT_PULLUP); // required for MUX to work properly
|
||||
#endif
|
||||
}
|
||||
|
||||
bool validateFrame(const CProtocol& frame, const char* name)
|
||||
{
|
||||
if(!frame.verifyCRC()) {
|
||||
// Bad CRC - restart blue wire Serial port
|
||||
DebugPort.print("\007Bad CRC detected for ");
|
||||
DebugPort.print(name);
|
||||
DebugPort.println(" frame - restarting Serial1");
|
||||
char header[16];
|
||||
sprintf(header, "[CRC_%s]", name);
|
||||
DebugReportFrame(header, frame, "\r\n");
|
||||
initBlueWireSerial();
|
||||
CommState.set(CommStates::Idle);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -23,10 +23,15 @@ const unsigned char BatteryIcon [] PROGMEM = {
|
|||
0x80, 0x02, 0xff, 0xfe
|
||||
};
|
||||
|
||||
// 'GlowPlugIcon', 16x10px
|
||||
// 'GlowPlugIcon', 16x9px
|
||||
const unsigned char GlowPlugIcon [] PROGMEM = {
|
||||
0x00, 0x00, 0xe3, 0x8e, 0x1c, 0x70, 0x28, 0x28, 0x24, 0x48, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
|
||||
0x14, 0x50, 0x1c, 0x70
|
||||
0x71, 0xc7, 0x0e, 0x38, 0x14, 0x14, 0x12, 0x24, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x0a, 0x28,
|
||||
0x0e, 0x38
|
||||
};
|
||||
|
||||
// 'HeatRise', 17x2px
|
||||
const unsigned char GlowHeatIcon [] PROGMEM = {
|
||||
0x80, 0x00, 0x80, 0x40, 0x01, 0x00
|
||||
};
|
||||
|
||||
// 'Fan3_1a', 16x16px
|
||||
|
@ -62,19 +67,25 @@ const unsigned char TargetIcon [] PROGMEM = {
|
|||
0x88, 0x88, 0x47, 0x10, 0x20, 0x20, 0x10, 0x40, 0x0f, 0x80
|
||||
};
|
||||
|
||||
|
||||
// # # ## ### # # ### ## ### ### ###
|
||||
// # # ## # # # # # # # # # # #
|
||||
// # # # # ## ### ## ### # ### ###
|
||||
// # # # # # # # # # # # # #
|
||||
// # ### ### ### # ## ### # ### ##
|
||||
// '0', 3x5px
|
||||
const unsigned char Mini0 [] PROGMEM = {
|
||||
0xe0, 0xb0, 0xb0, 0xb0, 0xe0
|
||||
0x40, 0xb0, 0xb0, 0xb0, 0x40
|
||||
};
|
||||
|
||||
// '1', 3x5px
|
||||
const unsigned char Mini1 [] PROGMEM = {
|
||||
0x40, 0xc0, 0x40, 0x40, 0x40
|
||||
0x40, 0xc0, 0x40, 0x40, 0xe0
|
||||
};
|
||||
|
||||
// '2', 3x5px
|
||||
const unsigned char Mini2 [] PROGMEM = {
|
||||
0xe0, 0x20, 0xe0, 0x80, 0xe0
|
||||
0xc0, 0x20, 0x40, 0x80, 0xe0
|
||||
};
|
||||
|
||||
// '3', 3x5px
|
||||
|
@ -84,17 +95,17 @@ const unsigned char Mini3 [] PROGMEM = {
|
|||
|
||||
// '4', 3x5px
|
||||
const unsigned char Mini4 [] PROGMEM = {
|
||||
0x80, 0xb0, 0xe0, 0x20, 0x20
|
||||
0xb0, 0xb0, 0xe0, 0x20, 0x20
|
||||
};
|
||||
|
||||
// '5', 3x5px
|
||||
const unsigned char Mini5 [] PROGMEM = {
|
||||
0xe0, 0x80, 0xe0, 0x20, 0xe0
|
||||
0xe0, 0x80, 0xc0, 0x20, 0xc0
|
||||
};
|
||||
|
||||
// '6', 3x5px
|
||||
const unsigned char Mini6 [] PROGMEM = {
|
||||
0xe0, 0x80, 0xe0, 0xb0, 0xe0
|
||||
0x60, 0x80, 0xe0, 0xb0, 0xe0
|
||||
};
|
||||
|
||||
// '7', 3x5px
|
||||
|
@ -109,7 +120,7 @@ const unsigned char Mini8 [] PROGMEM = {
|
|||
|
||||
// '9', 3x5px
|
||||
const unsigned char Mini9 [] PROGMEM = {
|
||||
0xe0, 0xb0, 0xe0, 0x20, 0xe0
|
||||
0xe0, 0xb0, 0xe0, 0x20, 0xc0
|
||||
};
|
||||
|
||||
// 'DP', 3x5px
|
||||
|
@ -142,6 +153,16 @@ const unsigned char MiniSpc [] PROGMEM = {
|
|||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// 'V', 3x5px
|
||||
const unsigned char MiniV [] PROGMEM = {
|
||||
0xb0, 0xb0, 0xb0, 0xb0, 0x40
|
||||
};
|
||||
|
||||
// 'W', 3x5px
|
||||
const unsigned char MiniW [] PROGMEM = {
|
||||
0xb0, 0xb0, 0xb0, 0xe0, 0xb0
|
||||
};
|
||||
|
||||
const char* Runstates [] PROGMEM = {
|
||||
" Stopped/Ready ",
|
||||
"Starting...",
|
||||
|
|
|
@ -41,6 +41,13 @@ public:
|
|||
Frame.Data[m_Count++] = val;
|
||||
return m_Count >= limit;
|
||||
}
|
||||
bool checkValidStart(unsigned char val)
|
||||
{
|
||||
if(m_Count)
|
||||
return true;
|
||||
else
|
||||
return val == 0x76;
|
||||
}
|
||||
|
||||
private:
|
||||
eCS m_State;
|
||||
|
|
|
@ -6,13 +6,28 @@
|
|||
#include "BluetoothAbstract.h"
|
||||
#include "OLEDconsts.h"
|
||||
|
||||
#define X_FANICON 60 //46
|
||||
#define X_FANICON 55
|
||||
#define Y_FANICON 39
|
||||
#define X_FUELICON 90 // 80
|
||||
#define X_FUELICON 81
|
||||
#define Y_FUELICON 39
|
||||
#define X_TARGETICON 30
|
||||
#define X_TARGETICON 31
|
||||
#define Y_TARGETICON 39
|
||||
#define Y_BASELINE 57
|
||||
#define Y_BASELINE 58
|
||||
#define X_BATTICON 95
|
||||
#define Y_BATTICON 0
|
||||
#define X_GLOWICON 97
|
||||
#define Y_GLOWICON 38
|
||||
#define X_BODYBULB 119
|
||||
#define X_BULB 1 // >= 1
|
||||
#define Y_BULB 4
|
||||
|
||||
#define MINI_BATTLABEL
|
||||
#define MINI_TEMPLABEL
|
||||
#define MINI_TARGETLABEL
|
||||
#define MINI_FANLABEL
|
||||
#define MINI_GLOWLABEL
|
||||
#define MINI_FUELLABEL
|
||||
#define MINI_BODYLABEL
|
||||
|
||||
//
|
||||
// **** NOTE: There are two very lame libaries conspiring to make life difficult ****
|
||||
|
@ -28,8 +43,9 @@
|
|||
SPIClass SPI; // default constructor opens HSPI on pins
|
||||
Adafruit_SH1106 display(LCDpin_DC, -1, LCDpin_CS);
|
||||
|
||||
int prevPump;
|
||||
int prevRPM;
|
||||
bool animatePump = false;
|
||||
bool animateRPM = false;
|
||||
bool animateGlow = false;
|
||||
|
||||
|
||||
extern float fFilteredTemperature;
|
||||
|
@ -65,7 +81,7 @@ void updateOLED(const CProtocol& CtlFrame, const CProtocol& HtrFrame)
|
|||
display.clearDisplay();
|
||||
|
||||
float desiredT = 0;
|
||||
if(runstate) {
|
||||
if(runstate && (runstate <= 5)) {
|
||||
if(CtlFrame.isThermostat())
|
||||
desiredT = CtlFrame.getTemperature_Desired();
|
||||
else
|
||||
|
@ -81,10 +97,15 @@ void updateOLED(const CProtocol& CtlFrame, const CProtocol& HtrFrame)
|
|||
float voltage = HtrFrame.getVoltage_Supply() * 0.1f;
|
||||
showBatteryIcon(voltage);
|
||||
|
||||
animateRPM = false;
|
||||
animatePump = false;
|
||||
animateGlow = false;
|
||||
|
||||
if(runstate) {
|
||||
float power = HtrFrame.getGlowPlug_Current() * 0.01 * HtrFrame.getGlowPlug_Voltage() * 0.1;
|
||||
if(power > 1)
|
||||
if(power > 1) {
|
||||
showGlowPlug(int(power));
|
||||
}
|
||||
|
||||
showFan(HtrFrame.getFan_Actual());
|
||||
|
||||
|
@ -92,10 +113,6 @@ void updateOLED(const CProtocol& CtlFrame, const CProtocol& HtrFrame)
|
|||
|
||||
showBodyThermometer(HtrFrame.getTemperature_HeatExchg());
|
||||
}
|
||||
else {
|
||||
prevRPM = 0;
|
||||
prevPump = 0;
|
||||
}
|
||||
|
||||
showRunState(runstate, errstate);
|
||||
|
||||
|
@ -106,18 +123,19 @@ void animateOLED()
|
|||
{
|
||||
static int fan = 0;
|
||||
static int drip = 0;
|
||||
static int heat = 0;
|
||||
|
||||
if(prevPump || prevRPM) {
|
||||
if(animatePump || animateRPM || animateGlow) {
|
||||
|
||||
if(prevPump) {
|
||||
if(animatePump) {
|
||||
// erase region of fuel icon
|
||||
display.fillRect(X_FUELICON, Y_FUELICON, 7, 16, BLACK);
|
||||
display.drawBitmap(X_FUELICON, Y_FUELICON+drip, FuelIcon, 7, 12, WHITE);
|
||||
display.drawBitmap(X_FUELICON, Y_FUELICON+(drip/2), FuelIcon, 7, 12, WHITE);
|
||||
drip++;
|
||||
drip &= 0x03;
|
||||
drip &= 0x07;
|
||||
}
|
||||
|
||||
if(prevRPM) {
|
||||
if(animateRPM) {
|
||||
// erase region of fuel icon
|
||||
display.fillRect(X_FANICON, Y_FANICON, 16, 16, BLACK);
|
||||
switch(fan) {
|
||||
|
@ -129,66 +147,86 @@ void animateOLED()
|
|||
fan++;
|
||||
fan &= 0x03;
|
||||
}
|
||||
|
||||
if(animateGlow) {
|
||||
display.fillRect(X_GLOWICON, Y_GLOWICON, 17, 10, BLACK);
|
||||
display.drawBitmap(X_GLOWICON, Y_GLOWICON, GlowPlugIcon, 16, 9, WHITE);
|
||||
display.drawBitmap(X_GLOWICON, Y_GLOWICON + 2 + heat, GlowHeatIcon, 17, 2, WHITE);
|
||||
heat -= 2;
|
||||
heat &= 0x07;
|
||||
}
|
||||
}
|
||||
display.display();
|
||||
}
|
||||
|
||||
|
||||
#define TEMP_YPOS(A) ((((20 - A) * 3) / 2) + 22)
|
||||
#define BULB_X 1 // >= 1
|
||||
#define BULB_Y 4
|
||||
void showThermometer(float desired, float actual)
|
||||
{
|
||||
char msg[16];
|
||||
display.clearDisplay();
|
||||
// draw bulb design
|
||||
display.drawBitmap(BULB_X, BULB_Y, thermometerBitmap, 8, 50, WHITE);
|
||||
display.drawBitmap(X_BULB, Y_BULB, thermometerBitmap, 8, 50, WHITE);
|
||||
// draw mercury
|
||||
int yPos = BULB_Y + TEMP_YPOS(actual);
|
||||
display.drawLine(BULB_X + 3, yPos, BULB_X + 3, BULB_Y + 42, WHITE);
|
||||
display.drawLine(BULB_X + 4, yPos, BULB_X + 4, BULB_Y + 42, WHITE);
|
||||
int yPos = Y_BULB + TEMP_YPOS(actual);
|
||||
display.drawLine(X_BULB + 3, yPos, X_BULB + 3, Y_BULB + 42, WHITE);
|
||||
display.drawLine(X_BULB + 4, yPos, X_BULB + 4, Y_BULB + 42, WHITE);
|
||||
// print actual temperature
|
||||
#ifdef MINI_TEMPLABEL
|
||||
sprintf(msg, "%.1f`C", actual);
|
||||
printMiniNumericString(0, Y_BASELINE, msg);
|
||||
#else
|
||||
display.setTextColor(WHITE);
|
||||
display.setCursor(0, Y_BASELINE);
|
||||
display.print(actual, 1);
|
||||
// draw set point
|
||||
#endif
|
||||
|
||||
// draw set point
|
||||
if(desired) {
|
||||
char msg[16];
|
||||
int desY = 19;
|
||||
display.drawBitmap(X_TARGETICON, Y_TARGETICON, TargetIcon, 13, 13, WHITE); // set indicator against bulb
|
||||
desY += 14;
|
||||
char msg[16];
|
||||
if(desired > 0) {
|
||||
int yPos = BULB_Y + TEMP_YPOS(desired) - 2;
|
||||
display.drawBitmap(BULB_X-1, yPos, thermoPtr, 3, 5, WHITE); // set indicator against bulb
|
||||
sprintf(msg, "%.0fC", desired);
|
||||
int yPos = Y_BULB + TEMP_YPOS(desired) - 2;
|
||||
display.drawBitmap(X_BULB-1, yPos, thermoPtr, 3, 5, WHITE); // set indicator against bulb
|
||||
sprintf(msg, "%.0f`C", desired);
|
||||
}
|
||||
else {
|
||||
sprintf(msg, "%.1fHz", -desired);
|
||||
}
|
||||
int xPos = X_TARGETICON + 6 - ( strlen(msg) * 3); // 3 = 1/2 width font
|
||||
#ifdef MINI_TARGETLABEL
|
||||
int xPos = X_TARGETICON + 7 - strlen(msg) * 2; // 2 = 1/2 width mini font
|
||||
printMiniNumericString(xPos, Y_BASELINE, msg);
|
||||
#else
|
||||
int xPos = X_TARGETICON + 6 - strlen(msg) * 3; // 3 = 1/2 width normal font
|
||||
display.setCursor(xPos, Y_BASELINE);
|
||||
display.print(msg);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#define BODYBULB_X 119
|
||||
#define BODY_YPOS(A) ((((100 - A) * 3) / 16) + 22) // 100degC centre - ticks +- 80C
|
||||
void showBodyThermometer(int actual)
|
||||
{
|
||||
// draw bulb design
|
||||
display.drawBitmap(BODYBULB_X, BULB_Y, thermometerBitmap, 8, 50, WHITE);
|
||||
display.drawBitmap(X_BODYBULB, Y_BULB, thermometerBitmap, 8, 50, WHITE);
|
||||
// draw mercury
|
||||
int yPos = BULB_Y + BODY_YPOS(actual);
|
||||
display.drawLine(BODYBULB_X + 3, yPos, BODYBULB_X + 3, BULB_Y + 42, WHITE);
|
||||
display.drawLine(BODYBULB_X + 4, yPos, BODYBULB_X + 4, BULB_Y + 42, WHITE);
|
||||
int yPos = Y_BULB + BODY_YPOS(actual);
|
||||
display.drawLine(X_BODYBULB + 3, yPos, X_BODYBULB + 3, Y_BULB + 42, WHITE);
|
||||
display.drawLine(X_BODYBULB + 4, yPos, X_BODYBULB + 4, Y_BULB + 42, WHITE);
|
||||
// print actual temperature
|
||||
display.setTextColor(WHITE);
|
||||
char label[16];
|
||||
sprintf(label, "%d", actual);
|
||||
// determine width and position right justified
|
||||
#ifdef MINI_BODYLABEL
|
||||
sprintf(label, "%d`C", actual);
|
||||
int width = strlen(label) * 4;
|
||||
printMiniNumericString(127-width, Y_BASELINE, label);
|
||||
#else
|
||||
sprintf(label, "%d", actual);
|
||||
int width = strlen(label) * 6;
|
||||
display.setCursor(127-width, Y_BASELINE);
|
||||
display.print(label);
|
||||
#endif
|
||||
}
|
||||
|
||||
void showBTicon()
|
||||
|
@ -198,54 +236,78 @@ void showBTicon()
|
|||
|
||||
void showBatteryIcon(float voltage)
|
||||
{
|
||||
display.drawBitmap(95, 0, BatteryIcon, 15, 10, WHITE);
|
||||
display.drawBitmap(X_BATTICON, Y_BATTICON, BatteryIcon, 15, 10, WHITE);
|
||||
#ifdef MINI_BATTLABEL
|
||||
char msg[16];
|
||||
sprintf(msg, "%.1fV", voltage);
|
||||
int xPos = X_BATTICON + 7 - strlen(msg) * 2;
|
||||
printMiniNumericString(xPos, Y_BATTICON+12, msg);
|
||||
#else
|
||||
display.setCursor(85, 12);
|
||||
display.setTextColor(WHITE);
|
||||
display.print(voltage, 1);
|
||||
display.print("V");
|
||||
#endif
|
||||
|
||||
// nominal 10.5 -> 13.5V bargraph
|
||||
int Capacity = int((voltage - 11.0) * 4.5);
|
||||
// int Capacity = int((voltage - 11.0) * 4.5);
|
||||
// int Capacity = (voltage - 11.4) * 7;
|
||||
int Capacity = (voltage - 10.7) * 4;
|
||||
if(Capacity < 0) Capacity = 0;
|
||||
if(Capacity > 11) Capacity = 11;
|
||||
display.fillRect(97 + Capacity, 2, 11-Capacity, 6, BLACK);
|
||||
display.fillRect(X_BATTICON+2 + Capacity, Y_BATTICON+2, 11-Capacity, 6, BLACK);
|
||||
}
|
||||
|
||||
#define XPOS_GLOW 35
|
||||
#define YPOS_GLOW 0
|
||||
void showGlowPlug(int power)
|
||||
{
|
||||
display.drawBitmap(XPOS_GLOW, YPOS_GLOW, GlowPlugIcon, 16, 10, WHITE);
|
||||
display.setCursor(XPOS_GLOW, YPOS_GLOW+12);
|
||||
display.setTextColor(WHITE);
|
||||
display.drawBitmap(X_GLOWICON, Y_GLOWICON, GlowPlugIcon, 16, 9, WHITE);
|
||||
// animateGlow = true;
|
||||
#ifdef MINI_GLOWLABEL
|
||||
char msg[16];
|
||||
sprintf(msg, "%dW", power);
|
||||
int xPos = X_GLOWICON + 9 - strlen(msg) * 2;
|
||||
printMiniNumericString(xPos, Y_GLOWICON+12, msg);
|
||||
#else
|
||||
display.setCursor(X_GLOWICON, Y_GLOWICON+12);
|
||||
display.print(power);
|
||||
display.print("W");
|
||||
#endif
|
||||
}
|
||||
|
||||
void showFan(int RPM)
|
||||
{
|
||||
// NOTE: fan rotation animation performed in animateOLED
|
||||
prevRPM = RPM; // used by animation routine
|
||||
animateRPM = RPM != 0; // used by animation routine
|
||||
|
||||
display.setTextColor(WHITE);
|
||||
char msg[16];
|
||||
sprintf(msg, "%d", RPM);
|
||||
#ifdef MINI_FANLABEL
|
||||
int xPos = X_FANICON + 8 - strlen(msg) * 2; // 3 = 1/2 width font
|
||||
printMiniNumericString(xPos, Y_BASELINE, msg);
|
||||
#else
|
||||
int xPos = X_FANICON + 8 - ( strlen(msg) * 3); // 3 = 1/2 width font
|
||||
display.setCursor(xPos, Y_BASELINE);
|
||||
display.print(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void showFuel(float rate)
|
||||
{
|
||||
// NOTE: fuel drop animation performed in animateOLED
|
||||
prevPump = rate > 0; // used by animation routine
|
||||
animatePump = rate != 0; // used by animation routine
|
||||
if(rate) {
|
||||
char msg[16];
|
||||
sprintf(msg, "%.1f", rate);
|
||||
#ifdef MINI_FUELLABEL
|
||||
int xPos = X_FUELICON + 3 - strlen(msg) * 2; // 3 = 1/2 width font
|
||||
printMiniNumericString(xPos, Y_BASELINE, msg);
|
||||
#else
|
||||
int xPos = X_FUELICON + 3 - ( strlen(msg) * 3); // 3 = 1/2 width font
|
||||
display.setCursor(xPos, Y_BASELINE);
|
||||
display.setTextColor(WHITE);
|
||||
display.print(rate, 1);
|
||||
display.print(msg);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,11 +318,13 @@ void showRunState(int runstate, int errstate)
|
|||
int yPos = 25;
|
||||
display.setTextColor(WHITE, BLACK);
|
||||
if(runstate >= 0 && runstate <= 8) {
|
||||
if(runstate == 0 && errstate) {
|
||||
if(((runstate == 0) || (runstate > 5)) && errstate) {
|
||||
// create an "E-XX" message to display
|
||||
char msg[16];
|
||||
sprintf(msg, "E-%02d", errstate);
|
||||
int xPos = 64 - ((strlen(msg)/2) * 6);
|
||||
if(runstate > 5)
|
||||
yPos -= 8;
|
||||
display.setCursor(xPos, yPos);
|
||||
yPos += 8;
|
||||
// flash error code
|
||||
|
@ -309,6 +373,8 @@ void printMiniNumericString(int xPos, int yPos, const char* str)
|
|||
case 'H': pBmp = MiniH; break;
|
||||
case 'z': pBmp = Miniz; break;
|
||||
case ' ': pBmp = MiniSpc; break;
|
||||
case 'V': pBmp = MiniV; break;
|
||||
case 'W': pBmp = MiniW; break;
|
||||
}
|
||||
if(pBmp) {
|
||||
display.drawBitmap(xPos, yPos, pBmp, 3, 5, WHITE);
|
||||
|
|
Loading…
Reference in a new issue