diff --git a/Arduino/BTCDieselHeater/Adafruit_SH1106.cpp b/Arduino/BTCDieselHeater/Adafruit_SH1106.cpp index 1d41710..7369cc6 100644 --- a/Arduino/BTCDieselHeater/Adafruit_SH1106.cpp +++ b/Arduino/BTCDieselHeater/Adafruit_SH1106.cpp @@ -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--) diff --git a/Arduino/BTCDieselHeater/BTCDieselHeater.ino b/Arduino/BTCDieselHeater/BTCDieselHeater.ino index 38c9314..f053f9e 100644 --- a/Arduino/BTCDieselHeater/BTCDieselHeater.ino +++ b/Arduino/BTCDieselHeater/BTCDieselHeater.ino @@ -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; +} \ No newline at end of file diff --git a/Arduino/BTCDieselHeater/OLEDconsts.h b/Arduino/BTCDieselHeater/OLEDconsts.h index 8b50ab6..bf05f02 100644 --- a/Arduino/BTCDieselHeater/OLEDconsts.h +++ b/Arduino/BTCDieselHeater/OLEDconsts.h @@ -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...", diff --git a/Arduino/BTCDieselHeater/UtilClasses.h b/Arduino/BTCDieselHeater/UtilClasses.h index 6ff23b6..612d496 100644 --- a/Arduino/BTCDieselHeater/UtilClasses.h +++ b/Arduino/BTCDieselHeater/UtilClasses.h @@ -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; diff --git a/Arduino/BTCDieselHeater/display.cpp b/Arduino/BTCDieselHeater/display.cpp index d159d54..c1ab60e 100644 --- a/Arduino/BTCDieselHeater/display.cpp +++ b/Arduino/BTCDieselHeater/display.cpp @@ -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);