diff --git a/README.md b/README.md index ca3163c..739cd43 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Enguino is intended to work with the [Stratux] ADS-B receiver which is also open The hardware consists of a tiny single board computer called an [Arduino]. This board is similar to the Raspberry Pi used in the Stratux, although the Arduino has a much simpler computer on it. Despite being a simple computer, the Arduino is much better at connecting to the real world. -Because Enguino is experimental, it is recommended that you don't replace your legally required gauges with Enguino. Also tablets and and wifi communication alone shouldn't be counted upon for critical flight information. Furthermore you may not have a dedicated tablet for Enguino. For these reasons an auxiliary display is an optional part of Enguino. It consists of a simple LED display that normally displays tachometer and fuel gauges but can also display engine alerts and warnings. +Because Enguino is experimental, it is recommended that you don't replace your legally required gauges with Enguino until you've confirmed yourself that its readings are accurate and reliable. Also tablets and and wifi communication alone shouldn't be counted upon for critical flight information. Furthermore you may not have a dedicated tablet for Enguino. For these reasons an auxiliary display is an optional part of Enguino. It consists of a simple LED display that normally displays tachometer and fuel gauges but can also display engine alerts and warnings. ## Hardware @@ -28,6 +28,8 @@ The firmware is installed on the Arduino using the Arduino IDE. First install th ## Configuration +Due to hardware limitations all calculations are done using integers. A decimal point is assumed during the calcuation and added when numbers are displayed. + ### Sensors ### Layout @@ -38,7 +40,7 @@ During design and testing of the layout it may be helpful to connect the Enguino Setting the ranges of the gauges (green, yellow, red regions) will require updating a spreadsheet and then pasting the values into a file. Details are **TBD**. ## Stratux -The Stratux has to be configured to route network traffic between the wired ethernet to the Enguino and the wifi connecting to a tablet. Note - these instructions are for Stratux v0.8r2, newer versions may require modification. +The Stratux is configured to route network traffic between the wired ethernet to the Enguino and the wifi connecting to a tablet. Note - these instructions are for Stratux v0.8r2, newer versions may require modification. * Boot the Stratux. For first boot, wait 3 minutes, for rebooting wait 30 seconds. * Either connect a monitor and keyboard to the Rapberry Pi and login with un: `pi`, pw: `raspberry` then skip ahead in these instructions to sudo nano... @@ -84,9 +86,9 @@ Browse to 192.168.0.111, confirm Engiuno panel shows up. ### Arduino -The Leonardo is rated to run from 6-20 volts although they suggest keeping it between 7-12 volts. They claim to worry about the voltage regulator overheating and 'damaging the board', but the regulator chip (88% efficient) does have a thermal shutdown feature at 150 deg C. The text appears to be a carry over from previous Arduino's which used a linear supply. Typical power draw is 70mA for Arduino, no more than 90mA for pull ups, TBD for auxiliary display. **TBD** if heating is a problem. **TBD** if voltage sag during starting is a problem. +The Leonardo is rated to run from 6-20 volts although they suggest keeping it between 7-12 volts. They claim to worry about the voltage regulator overheating and 'damaging the board', but the regulator chip (88% efficient) does have a thermal shutdown feature at 150 deg C. The text appears to be a carry over from previous Arduino's which used a linear supply. **TBD** if voltage sag during starting is a problem. -The supply is rated for 1000 ma. The Leonardo uses 82 mA. Testing will need to be done to determine actual power used. +The supply is rated for 1000 ma. The Leonardo uses 82 mA (confirmed by testing). **Leonardo Pins Mapping to ATmega 32U4** @@ -127,11 +129,11 @@ The main webpage has a timer running in Javascript on the tablet that invokes a The sensor system is fairly generic but currently only Van's Aircraft engine sensors have predefined configurations. The resistive sensors will have a 240 ohm(1%) pull up to +5V. This will require up to 18 ma per sensor, or for the typical 5 sensors (fuel x 2, oil-p, oil-t, fuel-p) 90 ma total. This provides a good compromise between power usage, heat and loss of resolution. This provides 9 bits of resolution. To limit resistor heating to reasonable levels, .5 watt resistors should be used. Resistor temp. rise should be no more than 100 deg. C in free air. A resistance significantly out of range will mark the sensor inoperative. To convert from ADC units to ohms use this formula `ohms = 240 * (adc / (1024-adc))`, this will require long divided by long division unfortunately or a lookup/interpolation table. -All but the oil-temp sensor are 240-33.5 ohm sensors. These usually scale linearly by resistance. For those that don't, a custom interpolation table may be required. The oil temperature sensor (for a Rochester 3080-37) as follows (degF=ohms): 100=497, 150=179, 200=72, 250=34. This is a thermistor. Using a Steinhar-Hart calculator the conversion formula becomes `degrees Kelvin = 1 / (0.0016207535760566691 + 0.0002609330007304247 * log(R) + -1.0278556187396396e-7 * log(R)^3)`. An interpolation table is used to convert this. +Many of the sensors are 240-33.5 ohm sensors. These usually scale linearly by resistance. For those that don't, a custom interpolation table may be required. The oil temperature sensor (for a Rochester 3080-37) as follows (degF=ohms): 100=497, 150=179, 200=72, 250=34. This is a thermistor. Westach has different values: http://www.acro.co.uk/html/westach_calibration.htm Using a Steinhar-Hart calculator the conversion formula becomes `degrees Kelvin = 1 / (0.0016207535760566691 + 0.0002609330007304247 * log(R) + -1.0278556187396396e-7 * log(R)^3)`. An interpolation table is used to convert this. For resistive sensors still attached to the gauge, the gauge itself provides the pull up resistance and voltage. For Vans Aircraft engine instruments the pull up is 5 volts and the resistor is about 227 ohms(measured externally, internally the resistor appears to be 240 ohms, 5%). The pin can be directly connected if the voltage can't exceed Vcc by more than .5v. Otherwise a 15K series resistor could be attached to help isolate the pin. -For thermocouple sensors the board will detect both open and short. It directly reads out in degrees C (.25 resolution). This will optionally be converted to F. To support J style thermocouples, the C output will be adjusted by taking the thermocouple reading (before the CJT adjustment) `newC = oldC * 46677 / 65536` +For thermocouple sensors the board will detect both open and short. It directly reads out in degrees C (.25 resolution). This will optionally be converted to F. To support J style thermocouples, the C output will be adjusted by taking the thermocouple reading (before the CJT adjustment) `newC = oldC * 25599 / 32768` For the voltage sensor a 4:1 voltage divider consisting of a 1k and 3.01k (1%) resistor is used. This limits the draw to .1 watt at 20 volts or .05 at 14 volts. @@ -139,11 +141,13 @@ Typical sensors are Stewart Warner. The tachometer is supplied with 12 volts, a For a sensor that might contain a voltage higher than Vcc using a voltage divider as used on the voltage sensor will cause a significant load which could create issues if still attached to a backup gauge. Alternatively a 15K ohm resistor between the sensor and the pin will safely clip voltages between 20.5 and -15.5 volts. The goal here is to limit the internal clamping diodes to no more than 1ma after the .7 volt diode drop. +The tachometer measures RPM by recording the uS time whenever the pin has a rising edge. RPM = 60,000,000 / (time - last_time). The division may be replaced by an interpolation table. The time is only accurate to 4 uS so it could be pre-divided by 4. Other interrupt functions (thermocouple and time keeping) will cause occasional jitter. Collecting 4 samples, throwing out the highest and lowest and averaging the last 2 should fix that. + ### Auxiliary Display The auxiliary display consists of two lines of a 4 digit [7 segment LED displays]. Limited text would be shown on the s. Some letters are displayed in the wrong case, for example 't' instead of 'T'. The letters 'M', 'W' and 'X' can not be displayed in an any form. Others like 'V' end up looking the same as 'U'. -A caution/warning [bicolor LED] is reworked by soldering onto the 'colon' column of the top display. This would be easier to see and interpret than the decimal point indicators. Red - warning, yellow - alert, green - ok. +A caution/warning [bicolor LED] is reworked by soldering onto the 'colon' column of the top display. Red - warning(fix it now or land), yellow - alert(look into it before it becomes a problem), green - ok. An acknowledge pushbutton is also part of the display. @@ -184,27 +188,31 @@ To prevent having to re-acknowledge warnings there would be both temporal and ra * T 1 3/4 LED holder for panel - Digikey 67-1332-ND * 2 Adafruit 7 segment displays - Digikey 1528-1473-ND * 10 240 ohm 1% resistors - Digikey A121513CT-ND -* 15K ohm 5% resistors - Digikey +* 15K ohm 5% resistors - Digikey 15.0KXBK-ND * 3K ohm 1% resistor - Digikey 3.01KXBK-ND * 1k ohm 1% resistor - Digikey 1.00KXBK-ND -* 10 input screw terminal block - Digikey ED10567-ND +* 12 input screw terminal block - Digikey ED10568-ND * .025 square breakaway headers - Digikey 929834-04-36-ND (tin) or 929647-04-36-ND (gold) - will probably work well on the thermocouple board w/o a header extension. * jack for auxiliary display 6 pin - Digikey 455-2271-ND * header for auxiliary display 6 pin - Digikey 455-2218-ND * contacts for header x 10 - Digikey 455-1135-1-ND * pushbutton switch - Digikey EG2015-ND * K style thermocouple wire, 24-26 gauge, EBay -* Bigger filter caps?, thermocouples Digikey 1276-1246-1-ND * Enclosure - Electrical box - B108R - Home Depot ### Future stuff -* It may be possible to support 2 thermocouples without the thermocouple multiplexer shield by using the differential mode ADC, 40x gain and a thermistor. Only 8 bits are usable with 40x. 488 uV per count works out to 21.5 deg. F resolution with a K type thermocouple. The 2.56 volt internal reference would double the resolution and oversampling could probably double it again. +* Record engine data by having the Engiuno pipe text to a port on the Stratux. The startup script on the stratux starts netcat (nc) in the background to record the text to a file. The script would also truncate the file at on powerup to limit its growth. +* It may be possible to support 2 thermocouples without the thermocouple multiplexer shield by using the differential mode ADC, 40x gain and a thermistor. Only 8 bits are usable (the noisy lower bits help with oversampling though) with 40x. 488 uV per count works out to 21.5 deg. F resolution with a K type thermocouple. The 2.56 volt internal reference would double the resolution and oversampling could probably quadruple it (16x oversample). * The Arduino Yun would support airplanes lacking a Stratux. The code would need to use the 'bridge' objects instead of the ethernet objects. Use #ifdef AVR_YUN to flex the code. * Themes - a dark theme could be created easily enough by adjusting the styles. A larger text theme for the gauges would involve more defines and stringizing them for the SVG. * Warning lights instead of auxillary display? A board with 4 caution/warning LEDs (red/green common cathode [bicolor LED]). Turning red and green on produces yellow. Alternatively use a module like the [BOB-13884] to provide 3 RGB LED's. * Create another TCP or UDP port that can be read from the Stratux (perhaps with netcat). This would be a comma separated text stream of engine data to be logged. * Use digitalFastWrite for smaller code - https://github.com/NicksonYap/digitalWriteFast -* Create mult16x16to32 function for smaller code - https://github.com/rekka/avrmultiplication +* Percent power resources: +table - www.kilohotel.com/rv8/rvlinks/o360apwr.xls www.kilohotel.com/rv8/rvlinks/io360apwr.xls +GRT - tables for mp_at_55%(rpm), mp_at_75%(rpm), delta_hp(pres.alt), also uses OAT. The delta-hp is a constant rpm, mp in the cruise range. +MGL - formula (3 constant) http://www.mglavionics.co.za/Docs/MGL%20EFIS%20G2%20HP%20calculation.pdf +O-320 power chart http://preflight.dynonavionics.com/2014/02/did-you-know-percent-power-dynon-way.html [open source]:https://en.wikipedia.org/wiki/Open-source_model diff --git a/enguino/config.h b/enguino/config.h index 39df0f2..943cc7c 100644 --- a/enguino/config.h +++ b/enguino/config.h @@ -1,3 +1,6 @@ +// Uncommenting the following line shows a box around each instrumment and around the viewable area of the page. Use to help arrange gauges. +// #define BOUNDING_BOX + const char *green = "green"; const char *yellow = "yellow"; const char *red = "red"; @@ -10,32 +13,26 @@ const char *red = "red"; #define GB(low) (int)(-((low) + 0.5)) #define ADCtoDivV (5.0/1023.0) // multiply this by adc input to get DC volts #define ADCtoV10 (57 * ADCtoDivV) // Using 1:5.7 divider for now !!! -#define V10toADC (1/(57 * ADCtoDivV)) // Using 1:5.7 divider for now !!! - - -const int thermistorADC[] = {}; -const int thermistorC10[] = {}; - -const int resist240ADC[] = {}; -const int resist240p1000[] = {}; +#define V10toADC (1/(57 * ADCtoDivV)) // Using 1:5.7 divider for now !!! // Sensor defintions and scaling // ----------------------------- -// Sensors are scaled using the formula: y = m * x + b, where y is either numeric value displayed or the gauge pointer postion. +// The sensors numeric values, y in the following forumala, are scaled as follow: y = m * x + b. +// Sensors gauge position are scaled a bit differerently with this formuala: y = (m + b) * x // All of these numbers must be integers. Factors are represented as a ratio with an integer numerator and a denominator of 8192. // Some numberic values are multipled by 10 and then have a decimal point added when displayed. // The MX macro converts a floating point factor for m into an integer factor. The gauge pointers vary from 0 to 1000. // Use GB() and GMX to set the graphs b and m values based on lowest input and input range (hi-low) respectively. // -const Sensor opS = { st_r240to33, 0, MX(0.1), 0, MX(1.0)}; // 0 - 100 -const Sensor otS = { st_thermistor, 32, MX(1.8*.1), GB((50-32)*5./9.*10), GMX(200*10*5./9.)}; // 50 - 250 -const Sensor vtS = { st_volts, 0, MX(ADCtoV10), GB(100*V10toADC), GMX(60*V10toADC)}; // 100 - 160 (10 - 16) -const Sensor fpS = { st_r240to33, 0, MX(0.1), 0, MX(1.0)}; // 0 - 100 (0 - 10) -const Sensor flS = { st_r240to33, 0, MX(0.16), 0, MX(1.0)}; // 0 - 160 (0 - 16) -const Sensor taS = { st_tachometer, 0, 12000, 0, 8008 }; // 0 - 3000 -const Sensor maS = { st_volts, 100, 2000, 0, 8008}; // 100 - 350 (10 - 35) -const Sensor chS = { st_k_type_tc, 32, MX(1.8/4), GB((100-32)*5./9.*4), GMX(400*5./9.*4)}; // 100 - 500, input is .25 C, convert to whole F -const Sensor egS = { st_k_type_tc, 32, MX(1.8/4), GB((1000-32)*5./9.*4), GMX(600*5./9.*4)}; // 1000 - 1600,input is .25 C, convert to to whole F +const Sensor opS = { st_r240to33, 0, MX(0.1), 0, MX(1.0)}; // 0 - 100 +const Sensor otS = { st_thermistorF, 0, MX(.1), GB(50*10), GMX(200*10)}; // 50 - 250 +const Sensor vtS = { st_volts, 0, MX(ADCtoV10), GB(100*V10toADC), GMX(60*V10toADC)}; // 100 - 160 (10 - 16) +const Sensor fpS = { st_r240to33, 0, MX(0.1), 0, MX(1.0)}; // 0 - 100 (0 - 10) +const Sensor flS = { st_r240to33, 0, MX(0.16), 0, MX(1.0)}; // 0 - 160 (0 - 16) +const Sensor taS = { st_tachometer, 0, 12000, 0, 8008 }; // 0 - 3000 +const Sensor maS = { st_volts, 100, 2000, 0, 8008}; // 100 - 350 (10 - 35) +const Sensor chS = { st_k_type_tcF, 0, MX(.25), GB(100*4), GMX(400*4)}; // 100 - 500, input is .25 deg. F +const Sensor egS = { st_k_type_tcF, 0, MX(.25), GB(1000*4), GMX(600*4)}; // 1000 - 1600,input is .25 deg. F // Labels // ------ @@ -59,9 +56,9 @@ const int egLP[] = { 2000, 4000, 6000 }; string opRC[] = { red, yellow, green, red }; int opRP[] = { 1000, 2200, 3800, 4000 }; string otRC[] = { yellow, green, red }; -int otRP[] = { 1800, 3900, 4000 }; +int otRP[] = { 1800, 3925, 4000 }; string vtRC[] = { red, yellow, green, yellow, red }; -int vtRP[] = { 700, 2000, 3330, 3900, 4000 }; +int vtRP[] = { 700, 2000, 3330, 3925, 4000 }; string fpRC[] = { red, yellow, green, yellow, red }; int fpRP[] = { 200, 800, 2400, 3200, 4000 }; string flRC[] = { red, yellow, green }; @@ -89,7 +86,8 @@ const Gauge gauges[] = { {bank+7000, 0, gs_pair, 1, "FUEL", "", "gal", flLV, flLP, N(flLV), flRC, flRP, N(flRC), &flS, 4}, // pins 4 and 5 {100, 0, gs_round, 0, "TACH", "", "rpm", 0, 0, 0, taRC, taRP, N(taRC), &taS, -1}, {100, 3200, gs_round, 1, "MP", "", "in-hg", 0, 0, 0, maRC, maRP, N(maRC), &maS, -1}, - {3000, 6250, gs_horiz, 0, "CHT", "", "", chLV, chLP, N(chLV), chRC, chRP, N(chRC), &chS, 16}, - {3000, 6250, gs_aux, 0, "EGT", "", "", egLV, egLP, N(egLV), 0, 0, 0, &egS, 20} + {2950, 6150, gs_horiz, 0, "CHT", "", "", chLV, chLP, N(chLV), chRC, chRP, N(chRC), &chS, 16}, + {2950, 6150, gs_aux, 0, "EGT", "", "", egLV, egLP, N(egLV), 0, 0, 0, &egS, 20}, + {700, 6500, gs_infobox,0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0} }; diff --git a/enguino/egTypes.h b/enguino/egTypes.h index e3f1ac1..e3a7bc2 100644 --- a/enguino/egTypes.h +++ b/enguino/egTypes.h @@ -13,7 +13,7 @@ typedef struct { const int *result; } InterpolateTable; -enum SensorType {st_r240to33, st_thermistor, st_volts, st_k_type_tc, st_j_type_tc, st_tachometer, st_fuel_flow}; +enum SensorType {st_r240to33, st_thermistorF, st_thermistorC, st_volts, st_k_type_tcF, st_j_type_tcF, st_k_type_tcC, st_j_type_tcC, st_tachometer, st_fuel_flow}; // st_r240to33 - 0 - 1000 proportional resistive sensor // st_thermistor - 0 - 1500 degrees C. in tenths // st_volts - 0 - 1023 ADC units 4.88 mV/per @@ -35,14 +35,14 @@ typedef struct { int mfactor; // 0-4000 vertical gauge, 0-8000 horizontal gauge, 0-2400 round gauge } Sensor; -enum GaugeStyle { gs_vert, gs_pair, gs_round, gs_horiz, gs_aux }; +enum GaugeStyle { gs_vert, gs_pair, gs_round, gs_horiz, gs_aux, gs_infobox }; typedef struct { int x; int y; GaugeStyle style; - int decimal; // add decimal point 'decimal' positons from the right (0 is integer) + byte decimal; // add decimal point 'decimal' positons from the right (0 is integer) string label1; string label2; @@ -50,15 +50,15 @@ typedef struct { string *labelValues; const int *labelPts; // prescaled from low,high and unscaled pts - int n_labels; + byte n_labels; string *regionColors; const int *regionEndPts; // prescaled from low,high and unscaled pts - int n_regions; + byte n_regions; const Sensor *sensor; - int pin; // first pin if multiple sensors (cht/egt, fuel) + signed char pin; // first pin if multiple sensors (cht/egt, fuel) } Gauge; enum GaugeColor { gc_green, gc_yellow, gc_red }; diff --git a/enguino/enguino.ino b/enguino/enguino.ino index c35675a..a963963 100644 --- a/enguino/enguino.ino +++ b/enguino/enguino.ino @@ -8,6 +8,8 @@ #include "utility.h" +#include "persist.h" + // configuration of sensors and layout of the gauges #include "config.h" @@ -28,10 +30,14 @@ EthernetServer server(80); EthernetClient client; int readGauge(const Gauge *g, byte n = 0); +bool leanMode = false; +int peakEGT[4]; // Performance 'print' functions to ethernet 'client' (includes flush) #include "printEthernet.h" +#include "printWeb.h" + // Implementation for printPrefix and pringGauge #include "printGauges.h" @@ -75,10 +81,10 @@ int readGauge(const Gauge *g, byte n = 0) { #ifdef RANDOM_SENSORS if (p < 16) return rand() & 0x3ff; - if (p < 20) // CHT - return rand() & 0x1ff; + if (p < 20) + return rand() & 0x7ff; // CHT if (p < 24) - return rand() & 0x1ff + 1000; // EGT + return rand() & 0x7ff + 4000; // EGT return FAULT; #else @@ -86,19 +92,29 @@ int readGauge(const Gauge *g, byte n = 0) { if (p < 0) return FAULT; + int t = g->sensor->type; + int toF = 0; if (p < 16) { v = analogRead(p); - int t = g->sensor->type; if (t == st_r240to33) v = interpolate(&r240to33, v); - else if (t == st_thermistor) + else if (t == st_thermistorC || t == st_thermistorF) { v = interpolate(&thermistor, v); - } - else if (p < 24) { + if (t == st_thermistorF) + toF = 32 * 10; + } + } + else if (p < 24) { noInterrupts(); v = tcTemp[p-16]; interrupts(); - } + if (t == st_j_type_tcC || t == st_j_type_tcF) + v = int(multiply(v - tcTemp[8], 25599) >> 15) + tcTemp[8]; + if (t == st_k_type_tcF || t == st_j_type_tcF) + toF = 32 * 4; + } + if (toF && v != FAULT) + v = (v*9)/5 + toF; return v; #endif } @@ -107,15 +123,20 @@ int readGauge(const Gauge *g, byte n = 0) { void serveUpWebPage(char url) { // unsigned long start = millis(); switch(url) { - case ' ': // static webpage - printPrefix(); + case ' ': // static webpage + printHomePage(); // logTime(start, "Load page /"); break; - case 'd': // dynamic webpage + case '?': // lean/cancel button pressed in main page + leanMode = !leanMode; + if (leanMode) + memset(peakEGT,0,sizeof(peakEGT)); + // fallthru to main page + case 'd': // dynamic webpage for (int i=0; i + +// both of these must be exactly 8 bytes in size +typedef struct { + word fullFuel; + word kFactor; // counts per 1/40 gallon + word filler1; + word filler2; +} EESettings; + +typedef struct { + byte sequence; + byte filler; + byte hobbs1k; // thousands of an hour rollover + word hobbs; // hobbs in 1/40 of an hour 0-999.975 (0-39,999) + word fuel; // fuel remaining in 1/40 of a gallon (10 GPH, changes every 9 seconds) +} EEStatus; + +EESettings ee_settings; +EEStatus ee_status; + +static byte nextSlot = 1; + +// slot 0 is for settings, slots 1 through 63 is for status, status' storage slot is distributed for 'wear-leveling' +// each slot has the data written twice, the second time is inverted +// if the first half doesn't match the inverted second half than return false (no valid data) +static bool eeRead(byte slot, void *buffer) { + int address = slot << 4; + byte *cp = buffer; + for (byte i=8; i; i--) + *cp++ = EEPROM.read(address++); + cp = buffer; + for (byte i=8; i; i--) + if (*cp++ != EEPROM.read(address++) ^ 0xFF) + return false; + return true; +} + +// slot 0 is for settings, 1 through 63 is for status +// this takes 53 ms to complete +static void eeWrite(byte slot, void *buffer) { + int address = slot << 4; + byte *cp = buffer; + for (byte i=8; i; i--) + EEPROM.write(address++, *cp++); + cp = buffer; + for (byte i=8; i; i--) + EEPROM.write(address++, *cp++ ^ 0xFF) ; +} + +// ---------------------------------------------------------- + +// only call in setup (assumes globals have been zeroed) +void eeInit() { + if (!eeRead(0, &ee_settings)) { + // ee_settings.fullFuel = 0; zeroed in initialization + ee_settings.kFactor = 1700; + eeWrite(0, &ee_settings); + } + + // search all the slots for the highest sequence number + bool found = false; + EEStatus temp; + while (nextSlot++ < 64) { + if (!eeRead(nextSlot, &temp)) + continue; + // handle rollover math for sequence number + if (found && (signed char)(temp.sequence - ee_status.sequence) <= 0) + continue; + ee_status = temp; + found = true; + } + nextSlot = 2; + // ee_status.ALL = 0; zeroed in initialization + eeWrite(1, (void *)&ee_status); +} + +// this takes 53 ms to complete +void eeUpdateSettings() { + eeWrite(0, &ee_settings); +} + +// this takes 53 ms to complete +// 15,000+ hour eeprom lifetime (at 10GPH) with updates whenever hobbs or gallons changes +void eeUpdateStatus() { + ee_status.sequence++; + eeWrite(0, &ee_status); + if (++nextSlot == 0) + nextSlot = 1; +} + diff --git a/enguino/printGauges.h b/enguino/printGauges.h index fd95d4a..dc19959 100644 --- a/enguino/printGauges.h +++ b/enguino/printGauges.h @@ -17,10 +17,13 @@ int scaleValue(const Sensor *s, int val) { // vertical gauge is // 1200 wide except extra room on right needed for labels (centered at 600) -// 6050 or so high +// 5950 high void printVertical(const Gauge *g, bool showLabels) { +#ifdef BOUNDING_BOX + print_P(F("\n")); +#endif // starts at 1100, 4000 high - print_P(F("\n")); + print_P(F("\n")); int val = readGauge(g); int mark = scaleMark(g->sensor, val) << 2; @@ -36,7 +39,7 @@ void printVertical(const Gauge *g, bool showLabels) { print_P(F("")); + print_P(F("")); print_text_close(g->label1); } - print_P(F("")); + print_P(F("")); print_text_close(g->label2); - print_P(F("")); + print_P(F("")); print_text_close(g->units); if (val == FAULT) color = yellow; if (color != 0 && color != green) { - print_P(F("")); + print_P(F("")); print(scaleValue(g->sensor, val), g->decimal); print_text_close(); if (val != FAULT) { print_P(F("\n")); +#endif + int offset = 0; for (int n=0; n\n")); +#endif int offset = 0; for (int n=0; n")); } + else if (leanMode) { + logValue(val,"val"); + logValue(peakEGT[n],"peak"); + if (val > peakEGT[n]) + peakEGT[n] = val; + if (val+11 < peakEGT[n]) + val -= peakEGT[n]; + } print_P(F("")); @@ -216,9 +234,13 @@ void printAuxHoriz(const Gauge *g, int count) { // vertical pair of gauges is // 2700 wide (centered at 1350) -// 6050 or so high +// 5950 or so high void printVerticalPair(const Gauge *g) { - print_P(F("")); +#ifdef BOUNDING_BOX + print_P(F("\n")); +#endif + + print_P(F("")); print_text_close(g->label1); Gauge t = *g; @@ -243,6 +265,10 @@ void printVerticalPair(const Gauge *g) { // 3000 wide (centered at 1500) // 2650 or so high void printRound(const Gauge *g) { +#ifdef BOUNDING_BOX + print_P(F("\n")); +#endif + // gauge sweeps 2400 units (-30.0 to 30.0 degrees) print_P(F("\n")); // border sweeps from -31 to 31 degrees @@ -314,6 +340,21 @@ void printRound(const Gauge *g) { } +void printInfoBox() { +#ifdef BOUNDING_BOX + print_P(F("\n")); +#endif + + print_P(F("\n" + "\n" + "")); + if (leanMode) + print_P(F("Cancel\n")); + else + print_P(F("Lean\n")); +} + + void printGauge(const Gauge *g) { print_P(F("\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - )); -} + diff --git a/enguino/printLED.h b/enguino/printLED.h index 38f833e..408cd1a 100644 --- a/enguino/printLED.h +++ b/enguino/printLED.h @@ -156,7 +156,7 @@ void printLED(byte line, byte *txt) { // print the fuel gauge (e.g. 2.5:17) (left tank : right tank) void printLEDFuel(int left, int right) { - memset(ledBuffer, 0, 11); + memset(ledBuffer, 0, sizeof(ledBuffer)); printLEDRawHalfDigits(4, right); printLEDRawHalfDigits(2, right); ledBuffer[6] = LED_COLON; diff --git a/enguino/printWeb.h b/enguino/printWeb.h new file mode 100644 index 0000000..dbaf151 --- /dev/null +++ b/enguino/printWeb.h @@ -0,0 +1,57 @@ +void printHomePage() { + print_P(F( + "\n" + "\n" + "\n" + "Enguino\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" +#ifdef BOUNDING_BOX + "\n" +#endif + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + )); +} diff --git a/enguino/utility.h b/enguino/utility.h index 768eac6..ac5cfce 100644 --- a/enguino/utility.h +++ b/enguino/utility.h @@ -1,3 +1,9 @@ +// compile time sin() and cos() for calculating round gauges position in an x, y plane +// https://github.com/pkhuong/polynomial-approximation-catalogue/tree/master/double +#define SIN(x) ( (x) + -0.166656810730001*(x)*(x)*(x) + 0.008312366210465815*(x)*(x)*(x)*(x)*(x) + -1.8492181558254177e-4*(x)*(x)*(x)*(x)*(x)*(x)*(x) ) +#define COS(x) ( 1.0 + -0.4999356307314411*(x)*(x) + 0.04150706685139252*(x)*(x)*(x)*(x) + -0.0012757519849685426*(x)*(x)*(x)*(x)*(x)*(x) ) + + void logTime(unsigned long start, const char *description) { Serial.print(description); Serial.print(' '); @@ -61,6 +67,11 @@ long multiply(int a, int b) { // return (long(a) * long(b); } +int multiplyAndScale(int a, int b, byte shift) { + return int(multiply(a, b) >> shift); +} + +// interpolate values using table, returns FAULT instead of extrapolating int interpolate(const InterpolateTable *table, int value) { int x = table->start; if (value < x) @@ -83,3 +94,14 @@ int interpolate(const InterpolateTable *table, int value) { } } +// sort a small list using insertion sort O(n^2) worst case +void sort(byte n, int *list) { + for (byte i=1; i0 && list[j-1] > list[j]; j--) { + int t = list[j]; + list[j] = list[j-1]; + list[j-1] = t; + } + } +} +