zamzara

MPGuino by tvago - working edit

Jan 23rd, 2016
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 245.18 KB | None | 0 0
  1. //
  2. // MPGuino - open source fuel consumption tracking system
  3. // GPL Software, mass production use rights reserved by opengauge.org
  4. // personal use is perfectly fine
  5. // no warranties expressed or implied
  6.  
  7. // Special thanks to the good folks at ecomodder.com, ardunio.cc, avrfreaks.net, cadsoft.de, atmel.com,
  8. // and all the folks who donate their time and resources and share their experiences freely
  9.  
  10. /* External connections:
  11.  
  12. Legacy MPGuino hardware is defined as anything that MPGuino was originally designed to run on. This includes
  13.    Arduino Duemilanove, Arduino Uno, JellyBeanDriver board, meelis11 board, iDuino, and any other board based off the
  14.    original MPGuino schematic, that can be found at http://ecomodder.com/wiki/index.php/MPGuino
  15.  
  16. Vehicle interface pins
  17.   legacy MPGuino hardware
  18.   injector sense open  PD2 (INT0)
  19.   injector sense close PD3 (INT1)
  20.   speed                PC0 (PCINT8)
  21.   (if configured) MAP  PC1 (ADC1)
  22.   (if configured) Baro PC2 (ADC2)
  23.  
  24.   TinkerKit! LCD module
  25.   injector sense open
  26.   injector sense close
  27.   speed                PB1 (PCINT1)
  28.   (if configured) MAP  PF7 (ADC7)
  29.   (if configured) Baro PF6 (ADC6)
  30.  
  31.   Arduino Mega 2560
  32.   injector sense open  PE4 (INT4)
  33.   injector sense close PE5 (INT5)
  34.   speed                PK0 (PCINT16)
  35.   (if configured) MAP  PF1 (ADC1)
  36.   (if configured) Baro PF2 (ADC2)
  37.  
  38.           --------------------------------------------
  39.          |                 MAP SENSOR                 |
  40.          |                                            |
  41.          |                                            |
  42.          |   +5V             SIGNAL          MAP      |
  43.          |   SUPPLY          GROUND          SIGNAL   |
  44.          |     3               2               1      |
  45.           --------------------------------------------
  46.                o               o               o
  47.                |               |               |
  48.                |               |               |              R7 (JBD)
  49.                |               |               o----------------vvv--o PC1 - legacy MPGuino hardware
  50.                |               |               |                2.2k   PF1 - Arduino Mega 2560
  51.                |               |               |                       PF7 - TinkerKit! LCD module
  52.                o               o               o
  53.           --------------------------------------------
  54.          |   C1-27           C2-27           C2-23    |
  55.          |   +5V             SIGNAL          MAP      |
  56.          |   SUPPLY          GROUND          SIGNAL   |
  57.          |                                            |
  58.          |                  CHRYSLER                  |
  59.          |       NGC POWERTRAIN CONTROL MODULE        |
  60.           --------------------------------------------
  61.                  (older Chrysler PCMs similar)
  62.  
  63.  
  64.           --------------------------------------------
  65.          |                Baro SENSOR                 |
  66.          |         (use a spare MAP sensor)           |
  67.          |                                            |
  68.          |   +5V             SIGNAL          Baro     |
  69.          |   SUPPLY          GROUND          SIGNAL   |
  70.          |     3               2               1      |
  71.           --------------------------------------------
  72.                o               o               o
  73.                |               |               |
  74.                |               |               |              R6 (JBD)
  75.                |               |               o----------------vvv--o PC2 - legacy MPGuino hardware
  76.                |               |                                2.2k   PF2 - Arduino Mega 2560
  77.                |               |                                       PF6 - TinkerKit! LCD module
  78.                o               o
  79.           --------------------------------------------
  80.          |   C1-27           C2-27                    |
  81.          |   +5V             SIGNAL                   |
  82.          |   SUPPLY          GROUND                   |
  83.          |                                            |
  84.          |                  CHRYSLER                  |
  85.          |       NGC POWERTRAIN CONTROL MODULE        |
  86.           --------------------------------------------
  87.                  (older Chrysler PCMs similar)
  88.  
  89.  
  90. LCD Pins - Legacy
  91.   legacy MPGuino hardware
  92.   DIR        PD4
  93.   DB4        PD7
  94.   DB5        PB0
  95.   DB6        PB4
  96.   DB7        PB5
  97.   Enable     PD5
  98.   Contrast   PD6, controlled by PWM on OC0A
  99.   Brightness PB1, controlled by PWM on OC1A
  100.  
  101.   TinkerKit! LCD module
  102.     RW         PF0
  103.   DIR        PF1
  104.   DB4        PF4
  105.   DB5        PD4
  106.   DB6        PD6
  107.   DB7        PB4
  108.   Enable     PE6
  109.   Contrast   PB5, controlled by PWM on OC1A
  110.   Brightness PB6, controlled by PWM on OC1B
  111.  
  112.   Arduino Mega 2560
  113.   DIR        PA4
  114.   DB4        PA3
  115.   DB5        PA2
  116.   DB6        PA1
  117.   DB7        PA0
  118.   Enable     PA5
  119.   Contrast   PB7, controlled by PWM on OC0A
  120.   Brightness PB5, controlled by PWM on OC1A
  121.  
  122. LCD Pins - Parallax Serial Interface
  123.   legacy MPGuino hardware
  124.   RX D1 (TXD)
  125.  
  126.   Arduino Mega 2560
  127.     RX E1 (TXD0)
  128.  
  129. Buttons - Legacy
  130.   legacy MPGuino hardware
  131.   left    PC3 (PCINT11)
  132.   middle  PC4 (PCINT12)
  133.   right   PC5 (PCINT13)
  134.  
  135.   Arduino Mega 2560
  136.   left    PK3 (PCINT19)
  137.   middle  PK4 (PCINT20)
  138.   right   PK5 (PCINT21)
  139.  
  140. Buttons - Multiplexed Analog (diagram courtesy of josemapiro)
  141.   legacy MPGuino hardware
  142.   left, middle, right, extra#1, extra#2 PC3 (ADC3)
  143.  
  144.   TinkerKit! LCD module
  145.   left, middle, right, extra#1, extra#2 PF7 (ADC7)
  146.  
  147.   Arduino Mega 2560
  148.   left, middle, right, extra#1, extra#2 PF3 (ADC3)
  149.  
  150.  
  151.              o---------------o---------------o---------------o---------------o--o GND
  152.         R2   |          R3   |          R4   |          R5   |          R6   |
  153.      o--vvv--o       o--VVV--o       o--vvv--o       o--vvv--o       o--vvv--o
  154.      |  2.2k         |  4.7k         |  10k          |  22k          |  47k
  155.      o               o               o               o               o
  156.       /               /               /               /               /
  157.      o left          o middle        o right         o Extra#1       o Extra#2
  158.      |               |               |               |               |
  159.      o---------------o---------------o---------------o---------------o--vvv--o--o 5V
  160.                                                                      | R1 1k
  161.                                                                      o----------o PC3 - legacy MPGuino hardware
  162.                                                                                   PF3 - Arduino Mega 2560
  163.                                                                                   PF7 - TinkerKit! LCD module
  164.  
  165. Buttons - Parallax 5-position switch (diagram based on josemapiro efforts)
  166.           (or any 5-position switch module with 10k pullup resistors on their switches)
  167.   legacy MPGuino hardware
  168.   left, middle, right, extra#1, extra#2 PC3 (ADC3)
  169.  
  170.   TinkerKit! LCD module
  171.   left, middle, right, extra#1, extra#2 PF7 (ADC7)
  172.  
  173.   Arduino Mega 2560
  174.   left, middle, right, extra#1, extra#2 PF3 (ADC3)
  175.  
  176.                                                                                   PF3 - Arduino Mega 2560
  177.                                                                                   PF7 - TinkerKit! LCD module
  178.                                                                      o----------o PC3 - legacy MPGuino hardware
  179.                                                                      | R1 1k
  180.      o---------------o---------------o---------------o---------------o--vvv--o--o 5V
  181.      |               |               |               |               |
  182.      |  left         | middle        |  right        | Extra#1       | Extra#2
  183.      |               |               |               |               |
  184.      |  R2           |  R3           |  R4           |  R5           |  R6
  185.      o--vvv--o       o--VVV--o       o--vvv--o       o--vvv--o       o--vvv--o
  186.         2.2k |          4.7k |          10k  |          22k  |          47k  |
  187.              |               |               |               |               |
  188.              |               |               |               |               |
  189.              o               o               o               o               o
  190.           -----------------------------------------------------------------------
  191.          |   4               7               2               6               3   |
  192.          |   LT              UP              RT             CTR              DN  |
  193.          |                                                                       |
  194.          |                                                                       |
  195.          |                  VCC             GND                                  |
  196.          |                   5               8                                   |
  197.           -----------------------------------------------------------------------
  198.                              o               o
  199.                              |               |
  200.                              o               o----------------------------------O GND
  201.                             N/C
  202. */
  203.  
  204. /* Program overview
  205.  set up timer hardware
  206.  set up interrupts
  207.  set up system constants
  208.  load system settings from EEPROM
  209.  set up LCD hardware
  210.  (if configured) set up serial UART output
  211.  
  212.  create accumulators for raw speed/injector data
  213.  
  214.  mainloop{
  215.  update instantaneous trip, current trip, tank trip, any other setup trip accumulators with raw data accumulators
  216.  reset raw data accumulators
  217.  (if configured) transmit instantaneous trip accumulators
  218.  display computations
  219.  scan for key presses and perform their function (change screen, reset a trip, goto setup, edit screen, restore trips, etc)
  220.  pause for remainder of 1/2 second
  221.  }
  222.  
  223. */
  224.  
  225. // if the below "#define"s are commented out, code will compile for an AtMega328-series processor
  226. //#define ArduinoMega2560 true
  227. //#define TinkerkitLCDmodule true
  228.  
  229. // if the below #define is commented out, 16 MHz system clock will be assumed
  230. #define use20MHz true // force 20 MHz system clock values
  231.  
  232. // only one of the below LCD options may be chosen - choosing more than one will cause a compilation error to occur
  233. // if TinkerkitLCDmodule is used, useLegacyLCD will automatically be used, and the below options will be ignored
  234. #define useLegacyLCD true
  235. //#define useParallaxLCD true
  236.  
  237. // only one of the below button options may be chosen - choosing more than one will cause a compilation error to occur
  238. #define useLegacyButtons true
  239. //#define useAnalogMuxButtons true
  240. //#define useParallax5PositionSwitch true
  241.  
  242. // the below options only work if useLegacyLCD is selected. If useLegacyLCD is not selected, the below options will not be inserted at all
  243. //#define useLegacyLCDinvertedBrightness true // For alternate LCD backlight connections
  244. #define useLegacyLCDbuffered true       // Speed up LCD output
  245.  
  246. // selectable options - all may be chosen independently of one another, save for serial data logging.
  247. // the serial data logging option will conflict with the Parallax LCD output option, if both are selected at the same time
  248. //#define blankScreenOnMessage true   // Completely blank display screen upon display of message
  249. #define trackIdleEOCdata true     // Ability to track engine idling and EOC modes
  250. //#define useSerialPortDataLogging true   // Ability to output 5 basic parameters to a data logger or SD card
  251. //#define useBufferedSerialPort true    // Speed up serial output
  252. #define useCalculatedFuelFactor true    // Ability to calculate that pesky us/gal (or L) factor from easily available published fuel injector data
  253. #define useWindowFilter true      // Smooths out "jumpy" instant FE figures that are caused by modern OBDII engine computers
  254. #define useBigFE true       // Show big fuel economy displays
  255. #define useBigDTE true        // Show big distance-to-empty displays
  256. #define useBigTTE true        // Show big time-to-empty displays
  257. // #define useClock true       // Show system clock, and provide means to set it
  258. // #define useSavedTrips true      // Ability to save current or tank trips to any one of 10 different trip slots in EEPROM
  259. // #define useScreenEditor true      // Ability to change any of 8 existing trip data screens, with 4 configurable figures on each screen
  260. // #define useBarFuelEconVsTime true   // Show Fuel Economy over Time bar graph
  261. #define useBarFuelEconVsSpeed true    // Show Fuel Economy vs Speed, Fuel Used vs Speed bar graphs
  262. #define useSpiffyBigChars true
  263. // #define useFuelCost true      // Show fuel cost
  264. //#define useChryslerMAPCorrection true   // Ability to perform on-the-fly fuel injector data correction for late-model Chrysler vehicles
  265. //#define useABresultViewer true      // Ability to graphically show current (B) versus stored (A) fuel consumption rates
  266. //#define useCoastDownCalculator true   // Ability to calculate C(rr) and C(d) from coastdown
  267.  
  268. // program measurement and debugging tools
  269. // #define useCPUreading true      // Show CPU loading and available RAM usage
  270. //#define useDebugReadings true
  271. //#define forceEEPROMsettingsInit true
  272. //#define useEEPROMviewer true      // Ability to directly examine EEPROM
  273. //#define useBenchMark true       // this is probably broken - last time I used it was in August 2013
  274. //#define useSerialDebugOutput true
  275.  
  276. // SWEET64 configuration/debugging
  277. //#define useSWEET64trace true      // Ability to view real-time 64-bit calculations from SWEET64 kernel
  278. //#define useSWEET64multDiv true      // shift mul64 and div64 from native C++ to SWEET64 bytecode
  279.  
  280. // these #defines are used to select various features to support the above choices
  281. // do not mess with them, or compilation errors will occur
  282. #ifdef TinkerkitLCDmodule
  283. #undef useParallaxLCD
  284. #define useLegacyLCD true
  285. #ifdef useLegacyButtons
  286. #undef useLegacyButtons
  287. #define useAnalogMuxButtons true
  288. #endif
  289. #endif
  290.  
  291. #ifdef useClock
  292. #define useBigTimeDisplay true
  293. #endif
  294.  
  295. #ifdef useBigTTE
  296. #define useBigTimeDisplay true
  297. #endif
  298.  
  299. #ifdef useBigTimeDisplay
  300. #define useBigNumberDisplay true
  301. #endif
  302.  
  303. #ifdef useBigDTE
  304. #define useBigNumberDisplay true
  305. #endif
  306.  
  307. #ifdef useBigFE
  308. #define useBigNumberDisplay true
  309. #endif
  310.  
  311. #ifdef useCalculatedFuelFactor
  312. #define useIsqrt true
  313. #endif
  314.  
  315. #ifdef useChryslerMAPCorrection
  316. #define useIsqrt true
  317. #define useAnalogRead true
  318. #endif
  319.  
  320. #ifdef useSerialPortDataLogging
  321. #define useSerialPort true
  322. #endif
  323.  
  324. #ifdef useParallaxLCD
  325. #define useSerialPort true
  326. #endif
  327.  
  328. #ifdef useAnalogMuxButtons
  329. #define useAnalogButtons true
  330. #endif
  331.  
  332. #ifdef useParallax5PositionSwitch
  333. #define useAnalogButtons true
  334. #endif
  335.  
  336. #ifdef useAnalogButtons
  337. #define useAnalogRead true
  338. #endif
  339.  
  340. #ifdef useLegacyLCD
  341. #define useAnalogInterrupt true
  342. #endif
  343.  
  344. #ifdef useAnalogRead
  345. #define useAnalogInterrupt true
  346. #endif
  347.  
  348. #ifdef useSWEET64trace
  349. #define useSerialDebugOutput true
  350. #endif
  351.  
  352. #ifdef useSerialDebugOutput
  353. #define useSerialPort true
  354. #endif
  355.  
  356. #ifdef useBarFuelEconVsTime
  357. #define useBarGraph true
  358. #endif
  359.  
  360. #ifdef useBarFuelEconVsSpeed
  361. #define useBarGraph true
  362. #endif
  363.  
  364. #ifdef useCoastDownCalculator
  365. #define useVehicleMass true
  366. #endif
  367.  
  368. #ifdef useBufferedSerialPort
  369. #define useBuffering true
  370. #endif
  371.  
  372. #ifdef useLegacyLCDbuffered
  373. #define useBuffering true
  374. #endif
  375.  
  376. #include <stdlib.h>
  377. #include <avr/interrupt.h>
  378. #include <avr/pgmspace.h>
  379. #include <avr/eeprom.h>
  380.  
  381. #ifdef ArduinoMega2560
  382. extern "C" {
  383.  
  384. void __vector_32()
  385. {
  386. }
  387.  
  388. }
  389.  
  390. #endif
  391.  
  392. typedef void (*pFunc)(void); // type for display function pointers
  393. #ifdef useBuffering
  394. typedef void (*qFunc)(uint8_t); // type for buffer function pointers
  395. #endif
  396.  
  397.  
  398. const uint8_t loopsPerSecond = 2; // how many times will we try and loop in a second
  399. const uint8_t samplesPerSecond = 2; // how many times will we try to sample the ADC output in a second
  400.  
  401. #ifdef use20MHz
  402. const uint8_t processorSpeed = 20; // processor speed in megahertz
  403. #ifdef useLegacyLCD
  404. const uint8_t lcdDelayTable[4] PROGMEM = { 1, 2, 51, 185 }; // LCD delay values, using ADC freewheeling and a divider of 128
  405. #endif
  406. #else
  407. const uint8_t processorSpeed = 16; // processor speed in megahertz
  408. #ifdef useLegacyLCD
  409. const uint8_t lcdDelayTable[4] PROGMEM = { 1, 1, 41, 148 }; // LCD delay values, using ADC freewheeling and a divider of 128
  410. #endif
  411. #endif
  412.  
  413. const unsigned long t2CyclesPerSecond = (unsigned long)(processorSpeed * 15625ul); // (processorSpeed * 1000000 / (timer 2 prescaler))
  414. const unsigned long loopSystemLength = (t2CyclesPerSecond / (loopsPerSecond * 10)); // divided by 10 to keep cpu loading value from overflowing
  415. const unsigned int loopTickLength = (unsigned int)(t2CyclesPerSecond / (loopsPerSecond * 256ul));
  416. const unsigned int sampleTickLength  = (unsigned int)(t2CyclesPerSecond / (samplesPerSecond * 256ul));
  417. const unsigned int myubbr = (unsigned int)(processorSpeed * 625ul / 96ul - 1);
  418. const unsigned int keyDelay = (unsigned int)(t2CyclesPerSecond / 256ul);
  419. const unsigned int keyShortDelay = keyDelay - (5 * keyDelay / 100); // wait 5/100 of a second before accepting button presses
  420. const unsigned int vssResetDelay = loopTickLength; // VSS pulse timeout is the same as the loop system length
  421.  
  422. const uint8_t holdDelay = loopsPerSecond * 2 - 1;
  423.  
  424. const unsigned int delay1500ms = (int)(1500ul * t2CyclesPerSecond / 256000ul);
  425. const unsigned int delay0005ms = (int)(5ul * t2CyclesPerSecond / 256000ul);
  426.  
  427. union union_16
  428. {
  429.  
  430.   unsigned int ui;
  431.   uint8_t u8[2];
  432.  
  433. };
  434.  
  435. union union_64
  436. {
  437.  
  438.   unsigned long long ull;
  439.   unsigned long ul[2];
  440.   unsigned int ui[4];
  441.   uint8_t u8[8];
  442.  
  443. };
  444.  
  445. #ifdef useChryslerMAPCorrection
  446. void readMAP(void);
  447. #endif
  448. #ifdef useIsqrt
  449. unsigned int iSqrt(unsigned int n);
  450. #endif
  451. void updateVSS(unsigned long cycle);
  452. void initStatusLine(void);
  453. void execStatusLine(void);
  454. void clrEOL(void);
  455. void gotoXY(uint8_t x, uint8_t y);
  456. void blinkFlash(const char * str, uint8_t condition);
  457. const char * findStr(const char * str, uint8_t strIdx);
  458. void printStr(const char * str, uint8_t strIdx);
  459. void printFlash(const char * str);
  460. void print(char * str);
  461. void charOut(uint8_t chr);
  462. void loadCGRAM(const char * c);
  463. #ifdef useBigNumberDisplay
  464. void displayBigStatus(uint8_t dIdx, const char * str);
  465. uint8_t fedSelect(uint8_t dIdx);
  466. void displayBigNumber(char * str);
  467. #endif
  468. #ifdef useBigTimeDisplay
  469. void displayBigTime(char * val, uint8_t b);
  470. #endif
  471. #ifdef useSavedTrips
  472. unsigned int getBaseTripPointer(uint8_t tripPos);
  473. #endif
  474. unsigned long SWEET64(const uint8_t * sched, uint8_t tripIdx);
  475. #ifdef useSerialDebugOutput
  476. void pushHexNybble(uint8_t val);
  477. void pushHexByte(uint8_t val);
  478. void pushHexWord(unsigned int val);
  479. void pushHexDWord(unsigned long val);
  480. #endif
  481. void copy64(union union_64 * an, union union_64 * ann);
  482. void tripVarLoad64(union union_64 * an, uint8_t tripIdx, uint8_t dataIdx);
  483. void EEPROMsave64(union union_64 * an, uint8_t dataIdx);
  484. void init64(union union_64 * an, unsigned long dWordL);
  485. void swap64(union union_64 * an, union union_64 * ann);
  486. void shr64(union union_64 * an);
  487. void shl64(union union_64 * an);
  488. void add64(union union_64 * an, union union_64 * ann, uint8_t mode);
  489. #ifndef useSWEET64multDiv
  490. void mul64(union union_64 * an, union union_64 * ann);
  491. void div64(union union_64 * an, union union_64 * ann);
  492. #endif
  493. uint8_t zeroTest64(union union_64 * an);
  494. uint8_t ltOrEtest64(union union_64 * an, union union_64 * ann);
  495. uint8_t lsbTest64(union union_64 * an);
  496. uint8_t msbTest64(union union_64 * an);
  497. char * doFormat(uint8_t tripIdx, uint8_t dispPos);
  498. unsigned long doCalculate(uint8_t calcIdx, uint8_t tripIdx);
  499. char * doFormat(uint8_t tripIdx, uint8_t calcIdx, uint8_t dispPos);
  500. char * format(unsigned long num, uint8_t ndp);
  501. char * format64(const uint8_t * prgmPtr, unsigned long num, char * str, uint8_t ndp);
  502. unsigned long rformat(void);
  503. unsigned long convertTime(unsigned long * an);
  504. #ifdef useWindowFilter
  505. void resetWindowFilter(void);
  506. #endif
  507. void initGuino(void);
  508. void delay2(unsigned int ms);
  509. #ifdef useSerialPortDataLogging
  510. void doOutputDataLog(void);
  511. void simpletx(char * str);
  512. #endif
  513. #ifdef useSerialPort
  514. void pushSerialCharacter(uint8_t chr);
  515. #ifdef useBufferedSerialPort
  516. void serialTransmitEnable(void);
  517. void serialTransmitDisable(void);
  518. void serialTransmitByte(uint8_t s);
  519. #endif
  520. #endif
  521. void doCursorMoveRelative(uint8_t i, uint8_t j);
  522. void doCursorMoveAbsolute(uint8_t i, uint8_t j);
  523. void doRefreshDisplay(void);
  524. void doNothing(void);
  525. void doNothing2(uint8_t s);
  526. void noSupport(void);
  527. void displayMainScreenFunction(uint8_t readingIdx, uint8_t k, uint8_t functBlink, uint8_t tripBlink);
  528. void writeCGRAMlabelChar(uint8_t cgChar, uint8_t functIdx, uint8_t tripIdx, uint8_t functBlink, uint8_t tripBlink);
  529. void doCursorUpdateMain(void);
  530. void doMainScreenDisplay(void);
  531. void doNextBright(void);
  532. void doLongGoLeft(void);
  533. void doLongGoRight(void);
  534. void doTripResetTank(void);
  535. void doTripResetCurrent(void);
  536. #ifdef useBarGraph
  537. void clearBGplot(uint8_t mode);
  538. uint8_t bgPlotConvert(uint8_t coord);
  539. void bgPlot(uint8_t idx, uint8_t lowerPoint, uint8_t upperPoint, uint8_t mode);
  540. void bgOutputPlot(uint8_t idx, uint8_t yIdx);
  541. uint8_t bgConvert(unsigned long v, unsigned long ll, unsigned long d);
  542. void formatBarGraph(uint8_t bgSize, uint8_t slotIdx, unsigned long centerVal, unsigned long topLimit);
  543. void displayBarGraphLine(uint8_t lineNum, uint8_t tripIdx, uint8_t tripCalcIdx);
  544. void displayBarGraph(uint8_t trip1idx, uint8_t trip1CalcIdx, uint8_t trip2idx, uint8_t trip2CalcIdx);
  545. #endif
  546. #ifdef useBarFuelEconVsSpeed
  547. void doCursorUpdateBarFEvS(void);
  548. void doBarFEvSdisplay(void);
  549. void doResetBarFEvS(void);
  550. #endif
  551. #ifdef useBarFuelEconVsTime
  552. void doResetBarFEvT(void);
  553. void doCursorUpdateBarFEvT(void);
  554. void doBarFEvTdisplay(void);
  555. #endif
  556. #ifdef useCPUreading
  557. void doDisplaySystemInfo(void);
  558. void displayCPUutil(void);
  559. void doShowCPU(void);
  560. #endif
  561. #ifdef useBenchMark
  562. void doBenchMark(void);
  563. #endif
  564. void doCursorUpdateSetting(void);
  565. void doSettingEditDisplay(void);
  566. void doGoSettingsEdit(void);
  567. void doReturnToMain(void);
  568. void doParamEditDisplay(void);
  569. void doParamExit(void);
  570. void doParamSave(void);
  571. void doGoParamEdit(void);
  572. void generalMenuLevelReturn(const char * s, uint8_t newMenuLevel);
  573. void printStatusMessage(const char * s);
  574. void doParamFindLeft(void);
  575. void doParamFindRight(void);
  576. void doParamStoreMax(void);
  577. void doParamStoreMin(void);
  578. void doParamRevert(void);
  579. void doParamStoreNumber(unsigned long v);
  580. void doParamReformat(void);
  581. void doParamChangeDigit(void);
  582. #ifdef useEEPROMviewer
  583. void doEEPROMviewDisplay(void);
  584. void goEEPROMview(void);
  585. #endif
  586. #ifdef useBigFE
  587. void doCursorUpdateBigFEscreen(void);
  588. void doBigFEdisplay(void);
  589. #endif
  590. #ifdef useBigDTE
  591. void doCursorUpdateBigDTEscreen(void);
  592. void doBigDTEdisplay(void);
  593. #endif
  594. #ifdef useBigTTE
  595. void doCursorUpdateBigTTEscreen(void);
  596. void doBigTTEdisplay(void);
  597. #endif
  598. #ifdef useClock // Clock support section
  599. void doCursorUpdateSystemTimeScreen(void);
  600. void doDisplaySystemTime(void);
  601. void doGoEditSystemTime(void);
  602. void doEditSystemTimeDisplay(void);
  603. void doEditSystemTimeChangeDigit(void);
  604. void doEditSystemTimeSave(void);
  605. void doEditSystemTimeCancel(void);
  606. #endif
  607. #ifdef useSavedTrips // Trip save/restore/raw data view support section
  608. void doCursorUpdateTripShow(void);
  609. void doTripSaveDisplay(void);
  610. void doTripShowDisplay(void);
  611. void doGoTripTank(void);
  612. void doGoTripCurrent(void);
  613. void goSavedTrip(uint8_t tripSlot);
  614. void doTripSelect(void);
  615. void doTripLongSelect(void);
  616. void goTripSelect(uint8_t pressFlag);
  617. void doTripSave(uint8_t tripIdx);
  618. void doTripLoad(uint8_t tripIdx);
  619. uint8_t doTripAutoAction(uint8_t taaMode);
  620. void doTripReset(uint8_t tripIdx);
  621. void doTripPrintType(uint8_t tripIdx);
  622. void doTripBumpSlot(void);
  623. void doTripShowCancel(void);
  624. #endif
  625. #ifdef useScreenEditor // Programmable main display screen edit support section
  626. void doCursorUpdateScreenEdit(void);
  627. void doScreenEditDisplay(void);
  628. void doGoScreenEdit(void);
  629. void doScreenEditReturnToMain(void);
  630. void doScreenEditRevert(void);
  631. void doScreenEditBump(void);
  632. void doSaveScreen(void);
  633. #endif
  634. uint8_t loadParams(void);
  635. uint8_t eepromWriteVal(unsigned int eePtr, unsigned long val);
  636. unsigned long eepromReadVal(unsigned int eePtr);
  637. unsigned int eepromGetAddress(unsigned int eePtr);
  638. void callFuncPointer(const uint8_t * funcIdx);
  639. unsigned long cycles2(void);
  640. unsigned long findCycleLength(unsigned long lastCycle, unsigned long thisCycle);
  641. int main(void);
  642.  
  643. const uint8_t idxDoNothing =        0;
  644. const uint8_t idxNoSupport =        idxDoNothing + 1;
  645. const uint8_t idxDoCursorUpdateMain =     idxNoSupport + 1;
  646. const uint8_t idxDoCursorUpdateSetting =    idxDoCursorUpdateMain + 1;
  647. const uint8_t idxDoMainScreenDisplay =      idxDoCursorUpdateSetting + 1;
  648. const uint8_t idxDoSettingEditDisplay =     idxDoMainScreenDisplay + 1;
  649. const uint8_t idxDoParamEditDisplay =     idxDoSettingEditDisplay + 1;
  650. const uint8_t idxDoGoSettingsEdit =       idxDoParamEditDisplay + 1;
  651. const uint8_t idxDoNextBright =       idxDoGoSettingsEdit + 1;
  652. const uint8_t idxDoTripResetCurrent =     idxDoNextBright + 1;
  653. const uint8_t idxDoLongGoRight =      idxDoTripResetCurrent + 1;
  654. const uint8_t idxDoTripResetTank =      idxDoLongGoRight + 1;
  655. const uint8_t idxDoLongGoLeft =       idxDoTripResetTank + 1;
  656. const uint8_t idxDoReturnToMain =     idxDoLongGoLeft + 1;
  657. const uint8_t idxDoGoParamEdit =      idxDoReturnToMain + 1;
  658. const uint8_t idxDoParamFindRight =     idxDoGoParamEdit + 1;
  659. const uint8_t idxDoParamExit =        idxDoParamFindRight + 1;
  660. const uint8_t idxDoParamFindLeft =      idxDoParamExit + 1;
  661. const uint8_t idxDoParamChangeDigit =     idxDoParamFindLeft + 1;
  662. const uint8_t idxDoParamSave =        idxDoParamChangeDigit + 1;
  663. const uint8_t idxDoParamStoreMin =      idxDoParamSave + 1;
  664. const uint8_t idxDoParamStoreMax =      idxDoParamStoreMin + 1;
  665. const uint8_t idxDoParamRevert =      idxDoParamStoreMax + 1;
  666. #define nextAllowedValue idxDoParamRevert
  667. #ifdef useCPUreading
  668. const uint8_t idxDoDisplaySystemInfo =      nextAllowedValue + 1;
  669. const uint8_t idxDoShowCPU =        idxDoDisplaySystemInfo + 1;
  670. #define nextAllowedValue idxDoShowCPU
  671. #endif
  672. #ifdef useBigFE
  673. const uint8_t idxDoCursorUpdateBigFEscreen =    nextAllowedValue + 1;
  674. const uint8_t idxDoBigFEdisplay =     idxDoCursorUpdateBigFEscreen + 1;
  675. #define nextAllowedValue idxDoBigFEdisplay
  676. #endif
  677. #ifdef useBigDTE
  678. const uint8_t idxDoCursorUpdateBigDTEscreen =   nextAllowedValue + 1;
  679. const uint8_t idxDoBigDTEdisplay =      idxDoCursorUpdateBigDTEscreen + 1;
  680. #define nextAllowedValue idxDoBigDTEdisplay
  681. #endif
  682. #ifdef useBigTTE
  683. const uint8_t idxDoCursorUpdateBigTTEscreen =   nextAllowedValue + 1;
  684. const uint8_t idxDoBigTTEdisplay =      idxDoCursorUpdateBigTTEscreen + 1;
  685. #define nextAllowedValue idxDoBigTTEdisplay
  686. #endif
  687. #ifdef useClock
  688. const uint8_t idxDoCursorUpdateSystemTimeScreen = nextAllowedValue + 1;
  689. const uint8_t idxDoDisplaySystemTime =      idxDoCursorUpdateSystemTimeScreen + 1;
  690. const uint8_t idxDoGoEditSystemTime =     idxDoDisplaySystemTime + 1;
  691. const uint8_t idxDoEditSystemTimeDisplay =    idxDoGoEditSystemTime + 1;
  692. const uint8_t idxDoEditSystemTimeCancel =   idxDoEditSystemTimeDisplay + 1;
  693. const uint8_t idxDoEditSystemTimeChangeDigit =    idxDoEditSystemTimeCancel + 1;
  694. const uint8_t idxDoEditSystemTimeSave =     idxDoEditSystemTimeChangeDigit + 1;
  695. #define nextAllowedValue idxDoEditSystemTimeSave
  696. #endif
  697. #ifdef useSavedTrips
  698. const uint8_t idxDoCursorUpdateTripShow =   nextAllowedValue + 1;
  699. const uint8_t idxDoTripSaveDisplay =      idxDoCursorUpdateTripShow + 1;
  700. const uint8_t idxDoTripShowDisplay =      idxDoTripSaveDisplay + 1;
  701. const uint8_t idxDoGoTripCurrent =      idxDoTripShowDisplay + 1;
  702. const uint8_t idxDoGoTripTank =       idxDoGoTripCurrent + 1;
  703. const uint8_t idxDoTripBumpSlot =     idxDoGoTripTank + 1;
  704. const uint8_t idxDoTripSelect =       idxDoTripBumpSlot + 1;
  705. const uint8_t idxDoTripLongSelect =     idxDoTripSelect + 1;
  706. const uint8_t idxDoTripShowCancel =     idxDoTripLongSelect + 1;
  707. #define nextAllowedValue idxDoTripShowCancel
  708. #endif
  709. #ifdef useScreenEditor
  710. const uint8_t idxDoScreenEditDisplay =      nextAllowedValue + 1;
  711. const uint8_t idxDoGoScreenEdit =     idxDoScreenEditDisplay + 1;
  712. const uint8_t idxDoScreenEditReturnToMain =   idxDoGoScreenEdit + 1;
  713. const uint8_t idxDoScreenEditRevert =     idxDoScreenEditReturnToMain + 1;
  714. const uint8_t idxDoSaveScreen =       idxDoScreenEditRevert + 1;
  715. const uint8_t idxDoScreenEditBump =     idxDoSaveScreen + 1;
  716. const uint8_t idxDoCursorUpdateScreenEdit =   idxDoScreenEditBump + 1;
  717. #define nextAllowedValue idxDoCursorUpdateScreenEdit
  718. #endif
  719. #ifdef useBarFuelEconVsTime
  720. const uint8_t idxDoCursorUpdateBarFEvT =    nextAllowedValue + 1;
  721. const uint8_t idxDoBarFEvTdisplay =     idxDoCursorUpdateBarFEvT + 1;
  722. #define nextAllowedValue idxDoBarFEvTdisplay
  723. #endif
  724. #ifdef useBarFuelEconVsSpeed
  725. const uint8_t idxDoCursorUpdateBarFEvS =    nextAllowedValue + 1;
  726. const uint8_t idxDoBarFEvSdisplay =     idxDoCursorUpdateBarFEvS + 1;
  727. const uint8_t idxDoResetBarFEvS =     idxDoBarFEvSdisplay + 1;
  728. #define nextAllowedValue idxDoResetBarFEvS
  729. #endif
  730. #ifdef useBenchMark
  731. const uint8_t idxDoBenchMark =        nextAllowedValue + 1;
  732. #define nextAllowedValue idxDoBenchMark
  733. #endif
  734. #ifdef useEEPROMviewer
  735. const uint8_t idxDoEEPROMviewDisplay =      nextAllowedValue + 1;
  736. const uint8_t idxGoEEPROMview =       idxDoEEPROMviewDisplay + 1;
  737. #define nextAllowedValue idxGoEEPROMview
  738. #endif
  739.  
  740. const uint8_t rvLength = 8;
  741.  
  742. const uint8_t rvVSSpulseIdx = 0;    // from the speedo
  743. const uint8_t rvInjPulseIdx = 1;    // rpm
  744. const uint8_t rvVSScycleIdx = 2;    // time that the vehicle has spent moving
  745. const uint8_t rvInjCycleIdx = 4;    // engine run time since this class was reset
  746. const uint8_t rvInjOpenCycleIdx = 6;    // time that the fuel injector has been open
  747.  
  748. const uint8_t tFuelUsed =   0;
  749. const uint8_t tFuelRate =   tFuelUsed + 1;
  750. const uint8_t tEngineRunTime =    tFuelRate + 1;
  751. const uint8_t tTimeToEmpty =    tEngineRunTime + 1;
  752. const uint8_t tDistance =   tTimeToEmpty + 1;
  753. const uint8_t tSpeed =      tDistance + 1;
  754. const uint8_t tMotionTime =   tSpeed + 1;
  755. const uint8_t tFuelEcon =   tMotionTime + 1;
  756. const uint8_t tRemainingFuel =    tFuelEcon + 1;
  757. const uint8_t tDistanceToEmpty =  tRemainingFuel + 1;
  758. const uint8_t tEngineSpeed =    tDistanceToEmpty + 1;
  759. const uint8_t tInjectorOpenTime = tEngineSpeed + 1;
  760. const uint8_t tInjectorTotalTime =  tInjectorOpenTime + 1;
  761. const uint8_t tVSStotalTime =   tInjectorTotalTime + 1;
  762. const uint8_t tInjectorPulseCount = tVSStotalTime + 1;
  763. const uint8_t tVSSpulseCount =    tInjectorPulseCount + 1;
  764. #define nextAllowedValue tVSSpulseCount
  765. #ifdef useFuelCost
  766. const uint8_t tFuelCost =   nextAllowedValue + 1;
  767. const uint8_t tFuelRateCost =   tFuelCost + 1;
  768. const uint8_t tFuelCostPerDistance =  tFuelRateCost + 1;
  769. const uint8_t tDistancePerFuelCost =  tFuelCostPerDistance + 1;
  770. const uint8_t tFuelCostRemaining =  tDistancePerFuelCost + 1;
  771. #define nextAllowedValue tFuelCostRemaining
  772. #endif
  773. const uint8_t dfMaxValCount =   nextAllowedValue + 1;
  774. #ifdef useAnalogRead
  775. #ifdef TinkerkitLCDmodule
  776. const uint8_t tAnalogChannel0 =   nextAllowedValue + 1;
  777. const uint8_t tAnalogChannel1 =   tAnalogChannel0 + 1;
  778. const uint8_t tAnalogChannel2 =   tAnalogChannel1 + 1;
  779. #define nextAllowedValue tAnalogChannel2
  780. #else
  781. const uint8_t tAnalogChannel0 =   nextAllowedValue + 1;
  782. const uint8_t tAnalogChannel1 =   tAnalogChannel0 + 1;
  783. #define nextAllowedValue tAnalogChannel1
  784. #ifdef useAnalogButtons
  785. const uint8_t tAnalogChannel2 =   nextAllowedValue + 1;
  786. const uint8_t tAnalogChannel3 =   tAnalogChannel2 + 1;
  787. const uint8_t tAnalogChannel4 =   tAnalogChannel3 + 1;
  788. #define nextAllowedValue tAnalogChannel4
  789. #endif
  790. #endif
  791. const uint8_t dfMaxValAnalogCount = nextAllowedValue + 1;
  792. #endif
  793. #ifdef useChryslerMAPCorrection
  794. const uint8_t tPressureChannel0 = nextAllowedValue + 1;
  795. const uint8_t tPressureChannel1 = tPressureChannel0 + 1;
  796. const uint8_t tPressureChannel2 = tPressureChannel1 + 1;
  797. const uint8_t tPressureChannel3 = tPressureChannel2 + 1;
  798. const uint8_t tCorrectionFactor = tPressureChannel3 + 1;
  799. #define nextAllowedValue tCorrectionFactor
  800. const uint8_t dfMaxValMAPCount = nextAllowedValue + 1;
  801. #endif
  802.  
  803. const uint8_t dfBitShift = 5;
  804. const uint8_t dfTripMask = 0xE0;
  805. const uint8_t dfValMask = 0x1F;
  806. const uint8_t dfMaxTripCount = 6;
  807.  
  808. const uint8_t calcDecimalPoints[] PROGMEM = {
  809.   2,  // fuel used
  810.   2,  // fuel rate
  811.   0,  // engine run time
  812.   0,  // time to empty
  813.   1,  // distance travelled
  814.   1,  // average speed
  815.   0,  // time in motion
  816.   1,  // fuel economy
  817.   2,  // remaining fuel
  818.   1,  // remaining distance
  819.   0,  // engine speed
  820.   0,  // fuel used, in microseconds
  821.   0,  // engine run time, in microseconds
  822.   0,  // time in motion, in microseconds
  823.   0,  // injector pulses
  824.   0,  // VSS pulses
  825. #ifdef useFuelCost
  826.   2,  // fuel cost
  827.   2,  // fuel cost rate
  828.   2,  // fuel cost per unit distance
  829.   1,  // distance per unit fuel cost
  830.   2,  // fuel cost remaining
  831. #endif
  832. #ifdef useAnalogRead
  833. #ifdef TinkerkitLCDmodule
  834.   3,  // voltage
  835.   3,  // voltage
  836.   3,  // voltage
  837. #else
  838.   3,  // voltage
  839.   3,  // voltage
  840. #ifdef useAnalogButtons
  841.   3,  // voltage
  842.   3,  // voltage
  843.   3,  // voltage
  844. #endif
  845. #endif
  846. #endif
  847. #ifdef useChryslerMAPCorrection
  848.   2,  // pressure
  849.   2,  // pressure
  850.   2,  // pressure
  851.   2,  // pressure
  852.   3,  // correction factor
  853. #endif
  854. };
  855.  
  856. const uint8_t dfMaxValDisplayCount = (sizeof(calcDecimalPoints) / sizeof(uint8_t));
  857.  
  858. #ifdef useSavedTrips
  859. const uint8_t tripSaveSlotCount = 10;
  860. const uint8_t tripListLength = rvLength;
  861. const uint8_t tripListSize = tripListLength + 2; // (uint8_t signature) plus (uint32_t timestamp)
  862. const uint8_t tripListSigPointer = tripListSize - 1;
  863. const uint8_t eepromTripListSize = tripListLength * 4 + 5; // trip list length plus (uint8_t signature) plus (uint32_t timestamp)
  864. #endif
  865.  
  866. #ifdef useBarGraph
  867. const uint8_t bgDataSize = 15;
  868. #endif
  869.  
  870. const uint8_t rawIdx =        0;
  871. const uint8_t instantIdx =      rawIdx + 1;
  872. const uint8_t currentIdx =      instantIdx + 1;
  873. const uint8_t tankIdx =       currentIdx + 1;
  874. #define nextAllowedValue tankIdx
  875. #ifdef trackIdleEOCdata
  876. const uint8_t rawIdleIdx =      nextAllowedValue + 1;
  877. const uint8_t eocIdleInstantIdx =     rawIdleIdx + 1;
  878. const uint8_t eocIdleCurrentIdx =     eocIdleInstantIdx + 1;
  879. const uint8_t eocIdleTankIdx =      eocIdleCurrentIdx + 1;
  880. #define nextAllowedValue eocIdleTankIdx
  881. #endif
  882. #ifdef useBarFuelEconVsTime
  883. const uint8_t periodIdx =       nextAllowedValue + 1;
  884. #define nextAllowedValue periodIdx
  885. #endif
  886. #ifdef useBarFuelEconVsSpeed
  887. const uint8_t FEvsSpeedIdx =      nextAllowedValue + 1;
  888. #define nextAllowedValue (FEvsSpeedIdx + bgDataSize - 1)
  889. #endif
  890. #ifdef useCoastDownCalculator
  891. const uint8_t thisCoastDownIdx =    nextAllowedValue + 1;
  892. const uint8_t lastCoastDownIdx =    thisCoastDownIdx + 1;
  893. #define nextAllowedValue lastCoastDownIdx
  894. #endif
  895. #ifdef useWindowFilter
  896. const uint8_t windowFilterSize = 4;
  897. const uint8_t windowFilterElemIdx =     nextAllowedValue + 1;
  898. const uint8_t windowFilterSumIdx =    windowFilterElemIdx + windowFilterSize;
  899. #define nextAllowedValue windowFilterSumIdx
  900. #endif
  901. const uint8_t tripSlotCount =       nextAllowedValue + 1;
  902.  
  903. const uint8_t displayPageCount = 9    // count of base number of data screens
  904. #ifdef trackIdleEOCdata
  905.   + 3                 // count of Idle/EOC tracking data screens
  906. #endif
  907. #ifdef useAnalogRead
  908.   + 1                 // count of analog voltage data screen
  909. #endif
  910. #ifdef useChryslerMAPCorrection
  911.   + 1                 // count of Chrysler MAP-specific data screen
  912. #endif
  913. ;
  914. const uint8_t displayFormatSize = displayPageCount * 4;
  915.  
  916. const uint8_t tripScreenIdxBase = 6
  917. #ifdef useChryslerMAPCorrection
  918.   + 1
  919. #endif
  920. #ifdef useAnalogRead
  921.   + 1
  922. #endif
  923. #ifdef trackIdleEOCdata
  924.   + 1
  925. #endif
  926. ;
  927.  
  928. #ifdef useLegacyLCD
  929. #ifdef useLegacyLCDinvertedBrightness
  930. const uint8_t brightness[] PROGMEM = { 255, 170, 85, 0 }; //middle button cycles through these brightness settings
  931. #else
  932. const uint8_t brightness[] PROGMEM = { 0, 30, 84, 192 }; //middle button cycles through these brightness settings
  933. #endif
  934. const char brightString[] PROGMEM = {
  935.   " OFF\0"
  936.   " LOW\0"
  937.   " MED\0"
  938.   "HIGH\0"
  939. };
  940. const uint8_t brightnessLength = (sizeof(brightness) / sizeof(uint8_t) ); // size of brightness table
  941. #endif
  942. #ifdef useParallaxLCD
  943. const uint8_t brightnessLength = 2;
  944. const char brightString[] PROGMEM = {
  945.   " OFF\0"
  946.   "  ON\0"
  947. };
  948. #endif
  949.  
  950. #ifdef TinkerkitLCDmodule
  951. const uint8_t vssBit =      (1 << PINB1);
  952. #else
  953. const uint8_t vssBit =      (1 << PINC0);
  954. #endif
  955.  
  956. #ifdef useLegacyButtons
  957. #ifdef ArduinoMega2560
  958. const uint8_t lbuttonBit =    (1 << PINK3);
  959. const uint8_t mbuttonBit =    (1 << PINK4);
  960. const uint8_t rbuttonBit =    (1 << PINK5);
  961. const uint8_t longButtonBit =     (1 << PINK6); // PINK6 isn't being used for anything right now
  962. #else
  963. const uint8_t lbuttonBit =    (1 << PINC3);
  964. const uint8_t mbuttonBit =    (1 << PINC4);
  965. const uint8_t rbuttonBit =    (1 << PINC5);
  966. const uint8_t longButtonBit =     (1 << PINC6); // PINC6 is used as the RESET pin, so this value is safe to use for long-press signalling
  967. #endif
  968.  
  969. const uint8_t buttonsUp =     rbuttonBit | mbuttonBit | lbuttonBit;
  970.  
  971. const uint8_t btnShortPressL =    rbuttonBit | mbuttonBit;
  972. const uint8_t btnShortPressC =    rbuttonBit | lbuttonBit;
  973. const uint8_t btnShortPressCL =   rbuttonBit;
  974. const uint8_t btnShortPressR =    mbuttonBit | lbuttonBit;
  975. const uint8_t btnShortPressRL =   mbuttonBit;
  976. const uint8_t btnShortPressRC =   lbuttonBit;
  977. const uint8_t btnShortPressRCL =  0;
  978. #endif
  979.  
  980. #ifdef useAnalogButtons
  981. const uint8_t longButtonBit =     0b10000000;
  982.  
  983. const uint8_t buttonsUp =     0;
  984. const uint8_t btnShortPressL =    buttonsUp + 1;
  985. const uint8_t btnShortPressC =    btnShortPressL + 1;
  986. const uint8_t btnShortPressR =    btnShortPressC + 2;
  987. const uint8_t btnShortPress1 =    btnShortPressR + 4;
  988. const uint8_t btnShortPress1L =   btnShortPress1 + 1;
  989. const uint8_t btnShortPress1C =   btnShortPress1L + 1;
  990. const uint8_t btnShortPress1CL =  btnShortPress1C + 1;
  991. const uint8_t btnShortPress1R =   btnShortPress1CL + 1;
  992. const uint8_t btnShortPress1RL =  btnShortPress1R + 1;
  993. const uint8_t btnShortPress1RC =  btnShortPress1RL + 1;
  994. const uint8_t btnShortPress1RCL =   btnShortPress1RC + 1;
  995. const uint8_t btnShortPress2 =    btnShortPress1RCL + 1;
  996. const uint8_t btnShortPress2L =   btnShortPress2 + 1;
  997. const uint8_t btnShortPress2C =   btnShortPress2L + 1;
  998. const uint8_t btnShortPress2CL =  btnShortPress2C + 1;
  999. const uint8_t btnShortPress2R =   btnShortPress2CL + 1;
  1000. const uint8_t btnShortPress2RL =  btnShortPress2R + 1;
  1001. const uint8_t btnShortPress2RC =  btnShortPress2RL + 1;
  1002. const uint8_t btnShortPress2RCL =   btnShortPress2RC + 1;
  1003. const uint8_t btnShortPress21 =   btnShortPress2RCL + 1;
  1004. const uint8_t btnShortPress21L =  btnShortPress21 + 1;
  1005. const uint8_t btnShortPress21C =  btnShortPress21L + 1;
  1006. const uint8_t btnShortPress21CL =   btnShortPress21C + 1;
  1007. const uint8_t btnShortPress21R =  btnShortPress21CL + 1;
  1008. const uint8_t btnShortPress21RL =   btnShortPress21R + 1;
  1009. const uint8_t btnShortPress21RC =   btnShortPress21RL + 1;
  1010. const uint8_t btnShortPress21RCL =  btnShortPress21RC + 1;
  1011.  
  1012. #ifdef useAnalogMuxButtons
  1013. const uint8_t btnShortPressCL =   btnShortPressC + 1;
  1014. const uint8_t btnShortPressRL =   btnShortPressR + 1;
  1015. const uint8_t btnShortPressRC =   btnShortPressRL + 1;
  1016. const uint8_t btnShortPressRCL =  btnShortPressRC + 1;
  1017. #endif
  1018.  
  1019. #ifdef useParallax5PositionSwitch
  1020. const uint8_t btnShortPressCL =   btnShortPress1L;
  1021. const uint8_t btnShortPressRL =   btnShortPress1;
  1022. const uint8_t btnShortPressRC =   btnShortPress1R;
  1023. const uint8_t btnShortPressRCL =  btnShortPress2;
  1024. #endif
  1025. #endif
  1026.  
  1027. const uint8_t btnLongPressL =     longButtonBit | btnShortPressL;
  1028. const uint8_t btnLongPressC =     longButtonBit | btnShortPressC;
  1029. const uint8_t btnLongPressCL =    longButtonBit | btnShortPressCL;
  1030. const uint8_t btnLongPressR =     longButtonBit | btnShortPressR;
  1031. const uint8_t btnLongPressRL =    longButtonBit | btnShortPressRL;
  1032. const uint8_t btnLongPressRC =    longButtonBit | btnShortPressRC;
  1033. const uint8_t btnLongPressRCL =   longButtonBit | btnShortPressRCL;
  1034.  
  1035. #ifdef useAnalogButtons
  1036. const uint8_t btnLongPress1 =     longButtonBit | btnShortPress1;
  1037. const uint8_t btnLongPress1L =    longButtonBit | btnShortPress1L;
  1038. const uint8_t btnLongPress1C =    longButtonBit | btnShortPress1C;
  1039. const uint8_t btnLongPress1CL =   longButtonBit | btnShortPress1CL;
  1040. const uint8_t btnLongPress1R =    longButtonBit | btnShortPress1R;
  1041. const uint8_t btnLongPress1RL =   longButtonBit | btnShortPress1RL;
  1042. const uint8_t btnLongPress1RC =   longButtonBit | btnShortPress1RC;
  1043. const uint8_t btnLongPress1RCL =  longButtonBit | btnShortPress1RCL;
  1044. const uint8_t btnLongPress2 =     longButtonBit | btnShortPress2;
  1045. const uint8_t btnLongPress2L =    longButtonBit | btnShortPress2L;
  1046. const uint8_t btnLongPress2C =    longButtonBit | btnShortPress2C;
  1047. const uint8_t btnLongPress2CL =   longButtonBit | btnShortPress2CL;
  1048. const uint8_t btnLongPress2R =    longButtonBit | btnShortPress2R;
  1049. const uint8_t btnLongPress2RL =   longButtonBit | btnShortPress2RL;
  1050. const uint8_t btnLongPress2RC =   longButtonBit | btnShortPress2RC;
  1051. const uint8_t btnLongPress2RCL =  longButtonBit | btnShortPress2RCL;
  1052. const uint8_t btnLongPress21 =    longButtonBit | btnShortPress21;
  1053. const uint8_t btnLongPress21L =   longButtonBit | btnShortPress21L;
  1054. const uint8_t btnLongPress21C =   longButtonBit | btnShortPress21C;
  1055. const uint8_t btnLongPress21CL =  longButtonBit | btnShortPress21CL;
  1056. const uint8_t btnLongPress21R =   longButtonBit | btnShortPress21R;
  1057. const uint8_t btnLongPress21RL =  longButtonBit | btnShortPress21RL;
  1058. const uint8_t btnLongPress21RC =  longButtonBit | btnShortPress21RC;
  1059. const uint8_t btnLongPress21RCL =   longButtonBit | btnShortPress21RCL;
  1060. #endif
  1061.  
  1062. const uint8_t dispRaw =     0b10000000;
  1063. const uint8_t dispFE =      0b01000000;
  1064. const uint8_t dispDTE =     0b00100000;
  1065.  
  1066. const uint8_t guinosig =    0b10110111;
  1067.  
  1068. const uint8_t dirtySysTick =    0b00001000;
  1069. const uint8_t dirtyInjOpenRead =  0b00000100;
  1070. const uint8_t dirtyGoodInj =    0b00000010;
  1071. const uint8_t dirtyGoodVSS =    0b00000001;
  1072.  
  1073. const uint8_t tcFallAsleep =      0b10000000;
  1074. const uint8_t tcWakeUpOnEngine =    0b01000000;
  1075. const uint8_t tcWakeUpOnButton =    0b00100000;
  1076. const uint8_t tcDisplayDelay =      0b00010000;
  1077. const uint8_t tcStartLoop =       0b00001000;
  1078. const uint8_t tcDoDelay =         0b00000100;
  1079. #ifdef useLegacyLCD
  1080. const uint8_t tcLCDdelay =        0b00000010;
  1081. #endif
  1082. #ifdef useAnalogRead
  1083. const uint8_t tcResetADC =        0b00000001;
  1084. #endif
  1085. const uint8_t tcWakeUp =        tcWakeUpOnEngine | tcWakeUpOnButton;
  1086.  
  1087. const uint8_t tsFellAsleep =      0b10000000;
  1088. const uint8_t tsAwakeOnEngine =     0b01000000;
  1089. const uint8_t tsAwakeOnButton =     0b00100000;
  1090. const uint8_t tsDisplayDelay =      0b00010000;
  1091. const uint8_t tsLoopExec =        0b00001000;
  1092. const uint8_t tsMarkLoop =        0b00000100;
  1093. const uint8_t tsButtonsUp =       0b00000010;
  1094. const uint8_t tsButtonRead =      0b00000001;
  1095. const uint8_t tsAwake =         tsAwakeOnEngine | tsAwakeOnButton;
  1096.  
  1097. #ifdef useLegacyLCD
  1098. #ifdef ArduinoMega2560
  1099. const uint8_t lcdData =     (1 << PORTA4); // on PORTA
  1100. const uint8_t lcdEnable =     (1 << PORTA5); // on PORTA
  1101. const uint8_t lcdBit3 =     (1 << PORTA0); // on PORTA
  1102. const uint8_t lcdBit2 =     (1 << PORTA1); // on PORTA
  1103. const uint8_t lcdBit1 =     (1 << PORTA2); // on PORTA
  1104. const uint8_t lcdBit0 =     (1 << PORTA3); // on PORTA
  1105. const uint8_t lcdBrightness =     (1 << DDB5); // on PORTB
  1106. const uint8_t lcdContrast =     (1 << DDB7); // on PORTB
  1107. #else
  1108. #ifdef TinkerkitLCDmodule
  1109. const uint8_t lcdDirection =    (1 << PORTF0); // on PORTF
  1110. const uint8_t lcdData =     (1 << PORTF1); // on PORTF
  1111. const uint8_t lcdEnable =     (1 << PORTE6); // on PORTE
  1112. const uint8_t lcdBit3 =     (1 << PORTB4); // on PORTB
  1113. const uint8_t lcdBit2 =     (1 << PORTD6); // on PORTD
  1114. const uint8_t lcdBit1 =     (1 << PORTD4); // on PORTD
  1115. const uint8_t lcdBit0 =     (1 << PORTF4); // on PORTF
  1116. const uint8_t lcdBrightness =     (1 << DDB6); // on PORTB
  1117. const uint8_t lcdContrast =     (1 << DDB5); // on PORTB
  1118. #else
  1119. const uint8_t lcdData =     (1 << PORTD4); // on PORTD
  1120. const uint8_t lcdEnable =     (1 << PORTD5); // on PORTD
  1121. const uint8_t lcdBit3 =     (1 << PORTB5); // on PORTB
  1122. const uint8_t lcdBit2 =     (1 << PORTB4); // on PORTB
  1123. const uint8_t lcdBit1 =     (1 << PORTB0); // on PORTB
  1124. const uint8_t lcdBit0 =     (1 << PORTD7); // on PORTD
  1125. const uint8_t lcdBrightness =     (1 << DDB1); // on PORTB
  1126. const uint8_t lcdContrast =     (1 << DDD6); // on PORTD
  1127.  
  1128. const uint8_t LEDred1 =     (1 << PORTB2);
  1129. const uint8_t LEDgrn1 =     (1 << PORTB3);
  1130.  
  1131. #endif
  1132. #endif
  1133.  
  1134. const uint8_t lcdDataByte =     0b00001000;
  1135. const uint8_t lcdCommandByte =    0b00000000;
  1136. const uint8_t lcdSendByte =     0b00000100;
  1137. const uint8_t lcdDelay0015ms =    0x03;
  1138. const uint8_t lcdDelay4100us =    0x02;
  1139. const uint8_t lcdDelay0100us =    0x01;
  1140. const uint8_t lcdDelay0080us =    0x00;
  1141. #endif
  1142.  
  1143. const uint8_t cgramBigNum = 1;
  1144.  
  1145. #define EuB0 (1 << 0)
  1146. #define EuB1 (1 << 1)
  1147. #define EuB2 (1 << 2)
  1148. #define EuB3 (1 << 3)
  1149. #define EuB4 (1 << 4)
  1150. #define EuB5 (1 << 5)
  1151. #define EuB6 (1 << 6)
  1152. #define EuB7 (1 << 7)
  1153.  
  1154. #ifdef useSavedTrips
  1155. #define EuB7 0
  1156. #ifdef trackIdleEOCdata
  1157. #define EuB6 0
  1158. #endif
  1159. #endif
  1160.  
  1161. #ifdef useScreenEditor
  1162. #define EuB5 0
  1163. #endif
  1164.  
  1165. const uint8_t EEPROMusage = EuB7 | EuB6 | EuB5 | EuB4 | EuB3 | EuB2 | EuB1 | EuB0;
  1166.  
  1167. const uint8_t eePtrSignature = 0;
  1168. const unsigned int eePtrSettingsStart = 1;
  1169.  
  1170. const uint8_t eeAdrSignature = 0;
  1171. const unsigned int eeAdrSettingsStart = 3;
  1172.  
  1173. // start of remarkably long EEPROM stored settings section
  1174.  
  1175. #define nextAllowedValue (uint8_t)(eePtrSettingsStart - 1)
  1176. #ifdef useLegacyLCD
  1177. const uint8_t pContrastIdx =      nextAllowedValue + 1;
  1178. #define nextAllowedValue pContrastIdx
  1179. #endif
  1180. const uint8_t pMetricFlagIdx =      nextAllowedValue + 1;
  1181. const uint8_t pInjEdgeTriggerIdx =    pMetricFlagIdx + 1;
  1182. #define nextAllowedValue pInjEdgeTriggerIdx
  1183. #ifdef useIsqrt
  1184. const uint8_t pSysFuelPressureIdx =   nextAllowedValue + 1;
  1185. #define nextAllowedValue pSysFuelPressureIdx
  1186. #endif
  1187. #ifdef useCalculatedFuelFactor
  1188. const uint8_t pRefFuelPressureIdx =   nextAllowedValue + 1;
  1189. const uint8_t pInjectorCountIdx =   pRefFuelPressureIdx + 1;
  1190. const uint8_t pInjectorSizeIdx =    pInjectorCountIdx + 1;
  1191. #define nextAllowedValue pInjectorSizeIdx
  1192. #endif
  1193. const uint8_t pMicroSecondsPerQuantityIdx = nextAllowedValue + 1;
  1194. const uint8_t pInjectorSettleTimeIdx =    pMicroSecondsPerQuantityIdx + 1;
  1195. const uint8_t pPulsesPerDistanceIdx =   pInjectorSettleTimeIdx + 1;
  1196. const uint8_t pVSSpauseIdx =      pPulsesPerDistanceIdx + 1;
  1197. const uint8_t pCrankRevPerInjIdx =    pVSSpauseIdx + 1;
  1198. const uint8_t pMinGoodRPMidx =      pCrankRevPerInjIdx + 1;
  1199. const uint8_t pTankSizeIdx =      pMinGoodRPMidx + 1;
  1200. #define nextAllowedValue pTankSizeIdx
  1201. #ifdef useChryslerMAPCorrection
  1202. const uint8_t pMAPsensorFloorIdx =    nextAllowedValue + 1;
  1203. const uint8_t pBaroSensorFloorIdx =   pMAPsensorFloorIdx + 1;
  1204. const uint8_t pMAPsensorCeilingIdx =    pBaroSensorFloorIdx + 1;
  1205. const uint8_t pBaroSensorCeilingIdx =   pMAPsensorCeilingIdx + 1;
  1206. const uint8_t pMAPsensorRangeIdx =    pBaroSensorCeilingIdx + 1;
  1207. const uint8_t pBaroSensorRangeIdx =   pMAPsensorRangeIdx + 1;
  1208. const uint8_t pMAPsensorOffsetIdx =   pBaroSensorRangeIdx + 1;
  1209. const uint8_t pBaroSensorOffsetIdx =    pMAPsensorOffsetIdx + 1;
  1210. #define nextAllowedValue pBaroSensorOffsetIdx
  1211. #endif
  1212. #ifdef useVehicleMass
  1213. const uint8_t pVehicleMassIdx =     nextAllowedValue + 1;
  1214. #define nextAllowedValue pVehicleMassIdx
  1215. #endif
  1216. #ifdef useCoastDownCalculator
  1217. const uint8_t pVehicleFrontalAreaIdx =    nextAllowedValue + 1;
  1218. const uint8_t pLocustDensityIdx =   pVehicleFrontalAreaIdx + 1;
  1219. const uint8_t pCoefficientDidx =    pLocustDensityIdx + 1;
  1220. const uint8_t pCoefficientVidx =    pCoefficientDidx + 1;
  1221. const uint8_t pCoefficientRRidx =   pCoefficientVidx + 1;
  1222. #define nextAllowedValue pCoefficientRRidx
  1223. #endif
  1224. const uint8_t pActivityTimeoutIdx =   nextAllowedValue + 1;
  1225. const uint8_t pWakeupResetCurrentOnEngineIdx =    pActivityTimeoutIdx + 1;
  1226. const uint8_t pWakeupResetCurrentOnButtonIdx =    pWakeupResetCurrentOnEngineIdx + 1;
  1227. #define nextAllowedValue pWakeupResetCurrentOnButtonIdx
  1228. #ifdef useSerialPortDataLogging
  1229. const uint8_t pSerialDataLoggingIdx =   nextAllowedValue + 1;
  1230. #define nextAllowedValue pSerialDataLoggingIdx
  1231. #endif
  1232. #ifdef useWindowFilter
  1233. const uint8_t pWindowFilterIdx =    nextAllowedValue + 1;
  1234. #define nextAllowedValue pWindowFilterIdx
  1235. #endif
  1236. #ifdef useBarFuelEconVsTime
  1237. const uint8_t pFEvsTimeIdx =      nextAllowedValue + 1;
  1238. #define nextAllowedValue pFEvsTimeIdx
  1239. #endif
  1240. #ifdef useSavedTrips
  1241. const uint8_t pAutoSaveActiveIdx =    nextAllowedValue + 1;
  1242. #define nextAllowedValue pAutoSaveActiveIdx
  1243. #ifdef trackIdleEOCdata
  1244. const uint8_t pAutoSaveIdleIdx =    nextAllowedValue + 1;
  1245. #define nextAllowedValue pAutoSaveIdleIdx
  1246. #endif
  1247. #endif
  1248. #ifdef useBarFuelEconVsSpeed
  1249. const uint8_t pBarLowSpeedCutoffIdx =   nextAllowedValue + 1;
  1250. const uint8_t pBarSpeedQuantumIdx =   pBarLowSpeedCutoffIdx + 1;
  1251. #define nextAllowedValue pBarSpeedQuantumIdx
  1252. #endif
  1253. #ifdef useFuelCost
  1254. const uint8_t pCostPerQuantity =    nextAllowedValue + 1;
  1255. #define nextAllowedValue pCostPerQuantity
  1256. #endif
  1257. const uint8_t pScratchpadIdx =      nextAllowedValue + 1;
  1258.  
  1259. const char parmLabels[] PROGMEM = {
  1260. #ifdef useLegacyLCD
  1261.   "Contrast\0"
  1262. #endif
  1263.   "Metric 1-Yes\0"
  1264.   "InjTrg 0-Dn 1-Up\0"
  1265. #ifdef useIsqrt
  1266.   "P(Fuel) {psi\\kPa}*1000\0"
  1267. #endif
  1268. #ifdef useCalculatedFuelFactor
  1269.   "P(Ref) {psi\\kPa}*1000\0"
  1270.   "Injector Count\0"
  1271.   "InjSize mL/min\0"
  1272. #endif
  1273.   "Microsec/{Gallon\\L}\0"
  1274.   "Inj Delay (uS)\0"
  1275.   "VSS Pulses/{Mile\\km}\0"
  1276.   "VSS Delay (ms)\0"
  1277.   "Revs/Inj Pulse\0"
  1278.   "Min Good RPM\0"
  1279.   "Tank ({Gal\\L})*1000\0"
  1280. #ifdef useChryslerMAPCorrection
  1281.   "MAPfloor (mV)\0"
  1282.   "BaroFloor (mV)\0"
  1283.   "MAPceiling (mV)\0"
  1284.   "BaroCeiling (mV)\0"
  1285.   "MAPrnge {psi\\kPa}*1000\0"
  1286.   "BaroRng {psi\\kPa}*1000\0"
  1287.   "MAPofst {psi\\kPa}*1000\0"
  1288.   "BroOfst {psi\\kPa}*1000\0"
  1289. #endif
  1290. #ifdef useVehicleMass
  1291.   "{Weight\\Mass} ({lbs\\kg})\0"
  1292. #endif
  1293. #ifdef useCoastDownCalculator
  1294.   "FrArea*1000 {ft\\m}^2\0"
  1295.   "rho*1000 {lb/yd\\kg/m}^3\0"
  1296.   "C(d) * 1000\0"
  1297.   "C(v) * 1000\0"
  1298.   "C(rr) * 1000\0"
  1299. #endif
  1300.   "Timeout (s)\0"
  1301.   "WakeEngRst CURR\0"
  1302.   "WakeBtnRst CURR\0"
  1303. #ifdef useSerialPortDataLogging
  1304.   "DLogSerial 1-Yes\0"
  1305. #endif
  1306. #ifdef useWindowFilter
  1307.   "WindowFilter 1-Y\0"
  1308. #endif
  1309. #ifdef useBarFuelEconVsTime
  1310.   "FE/Time Period s\0"
  1311. #endif
  1312. #ifdef useSavedTrips
  1313.   "AutoSaveTrip 1-Y\0"
  1314. #ifdef trackIdleEOCdata
  1315.   "AutoSaveIdle 1-Y\0"
  1316. #endif
  1317. #endif
  1318. #ifdef useBarFuelEconVsSpeed
  1319.   "bgLower*1000 {MPH\\kph}\0"
  1320.   "bgSize*1000 {MPH\\kph}\0"
  1321. #endif
  1322. #ifdef useFuelCost
  1323.   "Fuel Price*1000\0"
  1324. #endif
  1325.   "Scratchpad(odo?)\0"
  1326. };
  1327.  
  1328. #ifdef useLegacyLCD
  1329. const uint8_t pSizeContrast =       8;
  1330. #endif
  1331. const uint8_t pSizeMetricFlag =     1;
  1332. const uint8_t pSizeInjEdgeTrigger =     1;
  1333. #ifdef useIsqrt
  1334. const uint8_t pSizeSysFuelPressure =    32;
  1335. #endif
  1336. #ifdef useCalculatedFuelFactor
  1337. const uint8_t pSizeRefFuelPressure =    32;
  1338. const uint8_t pSizeInjectorCount =    8;
  1339. const uint8_t pSizeInjectorSize =     16;
  1340. #endif
  1341. const uint8_t pSizeMicroSecondsPerQuantity =  32;
  1342. const uint8_t pSizeInjectorSettleTime =   16;
  1343. const uint8_t pSizePulsesPerDistance =    16;
  1344. const uint8_t pSizeVSSpause =     8;
  1345. const uint8_t pSizeCrankRevPerInj =   8;
  1346. const uint8_t pSizeMinGoodRPM =     16;
  1347. const uint8_t pSizeTankSize =     24;
  1348. #ifdef useChryslerMAPCorrection
  1349. const uint8_t pSizeMAPsensorFloor =   16;
  1350. const uint8_t pSizeBaroSensorFloor =    16;
  1351. const uint8_t pSizeMAPsensorCeiling =   16;
  1352. const uint8_t pSizeBaroSensorCeiling =    16;
  1353. const uint8_t pSizeMAPsensorRange =   32;
  1354. const uint8_t pSizeBaroSensorRange =    32;
  1355. const uint8_t pSizeMAPsensorOffset =    32;
  1356. const uint8_t pSizeBaroSensorOffset =   32;
  1357. #endif
  1358. #ifdef useVehicleMass
  1359. const uint8_t pSizeVehicleMass =    16;
  1360. #endif
  1361. #ifdef useCoastDownCalculator
  1362. const uint8_t pSizeVehicleFrontalArea =   16;
  1363. const uint8_t pSizeLocustDensity =    16;
  1364. const uint8_t pSizeCoefficientD =   16;
  1365. const uint8_t pSizeCoefficientV =   16;
  1366. const uint8_t pSizeCoefficientRR =    16;
  1367. #endif
  1368. const uint8_t pSizeActivityTimeout =    16;
  1369. const uint8_t pSizeWakeupResetCurrentOnEngine =   1;
  1370. const uint8_t pSizeWakeupResetCurrentOnButton =   1;
  1371. #ifdef useSerialPortDataLogging
  1372. const uint8_t pSizeSerialDataLogging =    1;
  1373. #endif
  1374. #ifdef useWindowFilter
  1375. const uint8_t pSizeWindowFilter =   1;
  1376. #endif
  1377. #ifdef useBarFuelEconVsTime
  1378. const uint8_t pSizeFEvsTime =     16;
  1379. #endif
  1380. #ifdef useSavedTrips
  1381. const uint8_t pSizeAutoSaveActive =   1;
  1382. #ifdef trackIdleEOCdata
  1383. const uint8_t pSizeAutoSaveIdle =   1;
  1384. #endif
  1385. #endif
  1386. #ifdef useBarFuelEconVsSpeed
  1387. const uint8_t pSizeBarLowSpeedCutoff =    24;
  1388. const uint8_t pSizeBarSpeedQuantumIdx =   24;
  1389. #endif
  1390. #ifdef useFuelCost
  1391. const uint8_t pSizeFuelUnitCost =   16;
  1392. #endif
  1393. const uint8_t pSizeScratchpad =     32;
  1394.  
  1395. const uint8_t paramsLength[] PROGMEM = {
  1396. #ifdef useLegacyLCD
  1397.   pSizeContrast,          // LCD Contrast
  1398. #endif
  1399.   pSizeMetricFlag,        // Display Mode (0 - US Display, 1 - Metric Display)
  1400.   pSizeInjEdgeTrigger,        // Fuel Injector Edge Trigger (0 - Falling Edge, 1 - Rising Edge)
  1401. #ifdef useIsqrt
  1402.   pSizeSysFuelPressure,       // Fuel System Pressure * 1000 (psig or Pa)
  1403. #endif
  1404. #ifdef useCalculatedFuelFactor
  1405.   pSizeRefFuelPressure,       // Reference Fuel Injector Rated Pressure * 1000 (psig or Pa)
  1406.   pSizeInjectorCount,       // Fuel Injector Count
  1407.   pSizeInjectorSize,        // Fuel Injector Rated Capacity in mL/min
  1408. #endif
  1409.   pSizeMicroSecondsPerQuantity,     // Microseconds per (gal or L)
  1410.   pSizeInjectorSettleTime,      // Fuel Injector Response Delay Time (us)
  1411.   pSizePulsesPerDistance,       // VSS Pulses (per mile or per km)
  1412.   pSizeVSSpause,          // VSS Pause Debounce Count (ms)
  1413.   pSizeCrankRevPerInj,        // Crankshaft Revolutions per Fuel Injector Event
  1414.   pSizeMinGoodRPM,        // Minimum Engine Speed For Engine On (RPM)
  1415.   pSizeTankSize,          // Tank Capacity * 1000 (gal or L)
  1416. #ifdef useChryslerMAPCorrection
  1417.   pSizeMAPsensorFloor,        // MAP Sensor Floor * 1000 (mV)
  1418.   pSizeBaroSensorFloor,       // Barometric Sensor Floor * 1000 (mV)
  1419.   pSizeMAPsensorCeiling,        // MAP Sensor Ceiling * 1000 (mV)
  1420.   pSizeBaroSensorCeiling,       // Barometric Sensor Ceiling * 1000 (mV)
  1421.   pSizeMAPsensorRange,        // MAP Sensor Range * 1000 (psig or kPa)
  1422.   pSizeBaroSensorRange,       // Barometric Sensor Range * 1000 (psig or kPa)
  1423.   pSizeMAPsensorOffset,       // MAP Sensor Offset * 1000 (psig or kPa)
  1424.   pSizeBaroSensorOffset,        // Barometric Sensor Offset * 1000 (psig or kPa)
  1425. #endif
  1426. #ifdef useVehicleMass
  1427.   pSizeVehicleMass,       // Vehicle Weight/Mass (lbs or kg)
  1428. #endif
  1429. #ifdef useCoastDownCalculator
  1430.   pSizeVehicleFrontalArea,      // Vehicle Frontal Area * 1000 (ft^2 or m^2)
  1431.   pSizeLocustDensity,       // Air density (lb/yd^3 or kg/m^3)
  1432.   pSizeCoefficientD,        // Vehicle C(d) * 1000
  1433.   pSizeCoefficientV,        // Vehicle C(v) * 1000
  1434.   pSizeCoefficientRR,       // Vehicle C(rr) * 1000
  1435. #endif
  1436.   pSizeActivityTimeout,       // Activity Timeout (s)
  1437.   pSizeWakeupResetCurrentOnEngine,        // Enable current trip reset upon wakeup due to engine running
  1438.   pSizeWakeupResetCurrentOnButton,        // Enable current trip reset upon wakeup due to button press
  1439. #ifdef useSerialPortDataLogging
  1440.   pSizeSerialDataLogging,       // Serial Data Logging Enable
  1441. #endif
  1442. #ifdef useWindowFilter
  1443.   pSizeWindowFilter,        // Window Filter Enable
  1444. #endif
  1445. #ifdef useBarFuelEconVsTime
  1446.   pSizeFEvsTime,          // Period Of FE over Time BarGraph Bar (s)
  1447. #endif
  1448. #ifdef useSavedTrips
  1449.   pSizeAutoSaveActive,        // Autosave Active Trip Data Enable
  1450. #ifdef trackIdleEOCdata
  1451.   pSizeAutoSaveIdle,        // Autosave Idle Trip Data Enable
  1452. #endif
  1453. #endif
  1454. #ifdef useBarFuelEconVsSpeed
  1455.   pSizeBarLowSpeedCutoff,       // FE vs Speed Bargraph lower speed
  1456.   pSizeBarSpeedQuantumIdx,      // FE vs Speed Bargraph speed bar size
  1457. #endif
  1458. #ifdef useFuelCost
  1459.   pSizeFuelUnitCost,        // Price per unit volume of fuel
  1460. #endif
  1461.   pSizeScratchpad,        // Scratchpad Memory
  1462. };
  1463.  
  1464. #define byteSize(bitLength) ((((bitLength & 0x07) != 0)? 1 : 0) + (bitLength / 8))
  1465.  
  1466. #define nextAllowedValue 0
  1467. #ifdef useLegacyLCD
  1468. const uint8_t pOffsetContrast =     nextAllowedValue;
  1469. #define nextAllowedValue pOffsetContrast + byteSize(pSizeContrast)
  1470. #endif
  1471. const uint8_t pOffsetMetricFlag =     nextAllowedValue;
  1472. const uint8_t pOffsetInjEdgeTrigger =     pOffsetMetricFlag + byteSize(pSizeMetricFlag);
  1473. #define nextAllowedValue pOffsetInjEdgeTrigger + byteSize(pSizeInjEdgeTrigger)
  1474. #ifdef useIsqrt
  1475. const uint8_t pOffsetSysFuelPressure =    nextAllowedValue;
  1476. #define nextAllowedValue pOffsetSysFuelPressure + byteSize(pSizeSysFuelPressure)
  1477. #endif
  1478. #ifdef useCalculatedFuelFactor
  1479. const uint8_t pOffsetRefFuelPressure =    nextAllowedValue;
  1480. const uint8_t pOffsetInjectorCount =    pOffsetRefFuelPressure + byteSize(pSizeRefFuelPressure);
  1481. const uint8_t pOffsetInjectorSize =     pOffsetInjectorCount + byteSize(pSizeInjectorCount);
  1482. #define nextAllowedValue pOffsetInjectorSize + byteSize(pSizeInjectorSize)
  1483. #endif
  1484. const uint8_t pOffsetMicroSecondsPerQuantity =  nextAllowedValue;
  1485. const uint8_t pOffsetInjectorSettleTime = pOffsetMicroSecondsPerQuantity + byteSize(pSizeMicroSecondsPerQuantity);
  1486. const uint8_t pOffsetPulsesPerDistance =  pOffsetInjectorSettleTime + byteSize(pSizeInjectorSettleTime);
  1487. const uint8_t pOffsetVSSpause =     pOffsetPulsesPerDistance + byteSize(pSizePulsesPerDistance);
  1488. const uint8_t pOffsetCrankRevPerInj =   pOffsetVSSpause + byteSize(pSizeVSSpause);
  1489. const uint8_t pOffsetMinGoodRPM =   pOffsetCrankRevPerInj + byteSize(pSizeCrankRevPerInj);
  1490. const uint8_t pOffsetTankSize =     pOffsetMinGoodRPM + byteSize(pSizeMinGoodRPM);
  1491. #define nextAllowedValue pOffsetTankSize + byteSize(pSizeTankSize)
  1492. #ifdef useChryslerMAPCorrection
  1493. const uint8_t pOffsetMAPsensorFloor =   nextAllowedValue;
  1494. const uint8_t pOffsetBaroSensorFloor =    pOffsetMAPsensorFloor + byteSize(pSizeMAPsensorFloor);
  1495. const uint8_t pOffsetMAPsensorCeiling =   pOffsetBaroSensorFloor + byteSize(pSizeBaroSensorFloor);
  1496. const uint8_t pOffsetBaroSensorCeiling =  pOffsetMAPsensorCeiling + byteSize(pSizeMAPsensorCeiling);
  1497. const uint8_t pOffsetMAPsensorRange =   pOffsetBaroSensorCeiling + byteSize(pSizeBaroSensorCeiling);
  1498. const uint8_t pOffsetBaroSensorRange =    pOffsetMAPsensorRange + byteSize(pSizeMAPsensorRange);
  1499. const uint8_t pOffsetMAPsensorOffset =    pOffsetBaroSensorRange + byteSize(pSizeBaroSensorRange);
  1500. const uint8_t pOffsetBaroSensorOffset =   pOffsetMAPsensorOffset + byteSize(pSizeMAPsensorOffset);
  1501. #define nextAllowedValue pOffsetBaroSensorOffset + byteSize(pSizeBaroSensorOffset)
  1502. #endif
  1503. #ifdef useVehicleMass
  1504. const uint8_t pOffsetVehicleMass =    nextAllowedValue;
  1505. #define nextAllowedValue pOffsetVehicleMass + byteSize(pSizeVehicleMass)
  1506. #endif
  1507. #ifdef useCoastDownCalculator
  1508. const uint8_t pOffsetVehicleFrontalArea = nextAllowedValue;
  1509. const uint8_t pOffsetLocustDensity =    pOffsetVehicleFrontalArea + byteSize(pSizeVehicleFrontalArea);
  1510. const uint8_t pOffsetCoefficientD =   pOffsetLocustDensity + byteSize(pSizeLocustDensity);
  1511. const uint8_t pOffsetCoefficientV =   pOffsetCoefficientD + byteSize(pSizeCoefficientD);
  1512. const uint8_t pOffsetCoefficientRR =    pOffsetCoefficientV + byteSize(pSizeCoefficientV);
  1513. #define nextAllowedValue pOffsetCoefficientRR + byteSize(pSizeCoefficientRR)
  1514. #endif
  1515. const uint8_t pOffsetActivityTimeout =    nextAllowedValue;
  1516. const uint8_t pOffsetWakeupResetCurrentOnEngine = pOffsetActivityTimeout + byteSize(pSizeActivityTimeout);
  1517. const uint8_t pOffsetWakeupResetCurrentOnButton = pOffsetWakeupResetCurrentOnEngine + byteSize(pSizeWakeupResetCurrentOnEngine);
  1518. #define nextAllowedValue pOffsetWakeupResetCurrentOnButton + byteSize(pSizeWakeupResetCurrentOnButton)
  1519. #ifdef useSerialPortDataLogging
  1520. const uint8_t pOffsetSerialDataLogging =  nextAllowedValue;
  1521. #define nextAllowedValue pOffsetSerialDataLogging + byteSize(pSizeSerialDataLogging)
  1522. #endif
  1523. #ifdef useWindowFilter
  1524. const uint8_t pOffsetWindowFilter =   nextAllowedValue;
  1525. #define nextAllowedValue pOffsetWindowFilter + byteSize(pSizeWindowFilter)
  1526. #endif
  1527. #ifdef useBarFuelEconVsTime
  1528. const uint8_t pOffsetFEvsTime =     nextAllowedValue;
  1529. #define nextAllowedValue pOffsetFEvsTime + byteSize(pSizeFEvsTime)
  1530. #endif
  1531. #ifdef useSavedTrips
  1532. const uint8_t pOffsetAutoSaveActive =   nextAllowedValue;
  1533. #define nextAllowedValue pOffsetAutoSaveActive + byteSize(pSizeAutoSaveActive)
  1534. #ifdef trackIdleEOCdata
  1535. const uint8_t pOffsetAutoSaveIdle =   nextAllowedValue;
  1536. #define nextAllowedValue pOffsetAutoSaveIdle + byteSize(pSizeAutoSaveIdle)
  1537. #endif
  1538. #endif
  1539. #ifdef useBarFuelEconVsSpeed
  1540. const uint8_t pOffsetBarLowSpeedCutoff =  nextAllowedValue;
  1541. const uint8_t pOffsetBarSpeedQuantumIdx = pOffsetBarLowSpeedCutoff + byteSize(pSizeBarLowSpeedCutoff);
  1542. #define nextAllowedValue pOffsetBarSpeedQuantumIdx + byteSize(pSizeBarSpeedQuantumIdx)
  1543. #endif
  1544. #ifdef useFuelCost
  1545. const uint8_t pOffsetFuelUnitCost =   nextAllowedValue;
  1546. #define nextAllowedValue pOffsetFuelUnitCost + byteSize(pSizeFuelUnitCost)
  1547. #endif
  1548. const uint8_t pOffsetScratchpad =   nextAllowedValue;
  1549. const uint8_t pOffsetZZ =     pOffsetScratchpad + byteSize(pSizeScratchpad);
  1550.  
  1551. const uint8_t paramAddrs[] PROGMEM = {
  1552. #ifdef useLegacyLCD
  1553.   (uint8_t)(eeAdrSettingsStart) + pOffsetContrast,      // LCD Contrast
  1554. #endif
  1555.   (uint8_t)(eeAdrSettingsStart) + pOffsetMetricFlag,      // Display Mode (0 - US Display, 1 - Metric Display)
  1556.   (uint8_t)(eeAdrSettingsStart) + pOffsetInjEdgeTrigger,    // Fuel Injector Edge Trigger (0 - Falling Edge, 1 - Rising Edge)
  1557. #ifdef useIsqrt
  1558.   (uint8_t)(eeAdrSettingsStart) + pOffsetSysFuelPressure,   // Fuel System Pressure * 1000 (psig or Pa)
  1559. #endif
  1560. #ifdef useCalculatedFuelFactor
  1561.   (uint8_t)(eeAdrSettingsStart) + pOffsetRefFuelPressure,   // Reference Fuel Injector Rated Pressure * 1000 (psig or Pa)
  1562.   (uint8_t)(eeAdrSettingsStart) + pOffsetInjectorCount,   // Fuel Injector Count
  1563.   (uint8_t)(eeAdrSettingsStart) + pOffsetInjectorSize,    // Fuel Injector Rated Capacity in mL/min
  1564. #endif
  1565.   (uint8_t)(eeAdrSettingsStart) + pOffsetMicroSecondsPerQuantity, // Microseconds per (gal or L)
  1566.   (uint8_t)(eeAdrSettingsStart) + pOffsetInjectorSettleTime,    // Fuel Injector Response Delay Time (us)
  1567.   (uint8_t)(eeAdrSettingsStart) + pOffsetPulsesPerDistance,   // VSS Pulses (per mile or per km)
  1568.   (uint8_t)(eeAdrSettingsStart) + pOffsetVSSpause,      // VSS Pause Debounce Count (ms)
  1569.   (uint8_t)(eeAdrSettingsStart) + pOffsetCrankRevPerInj,    // Crankshaft Revolutions per Fuel Injector Event
  1570.   (uint8_t)(eeAdrSettingsStart) + pOffsetMinGoodRPM,      // Minimum Engine Speed For Engine On (RPM)
  1571.   (uint8_t)(eeAdrSettingsStart) + pOffsetTankSize,      // Tank Capacity * 1000 (gal or L)
  1572. #ifdef useChryslerMAPCorrection
  1573.   (uint8_t)(eeAdrSettingsStart) + pOffsetMAPsensorFloor,    // MAP Sensor Floor * 1000 (mV)
  1574.   (uint8_t)(eeAdrSettingsStart) + pOffsetBaroSensorFloor,   // Barometric Sensor Floor * 1000 (mV)
  1575.   (uint8_t)(eeAdrSettingsStart) + pOffsetMAPsensorCeiling,    // MAP Sensor Ceiling * 1000 (mV)
  1576.   (uint8_t)(eeAdrSettingsStart) + pOffsetBaroSensorCeiling,   // Barometric Sensor Ceiling * 1000 (mV)
  1577.   (uint8_t)(eeAdrSettingsStart) + pOffsetMAPsensorRange,    // MAP Sensor Range * 1000 (psig or kPa)
  1578.   (uint8_t)(eeAdrSettingsStart) + pOffsetBaroSensorRange,   // Barometric Sensor Range * 1000 (psig or kPa)
  1579.   (uint8_t)(eeAdrSettingsStart) + pOffsetMAPsensorOffset,   // MAP Sensor Offset * 1000 (psig or kPa)
  1580.   (uint8_t)(eeAdrSettingsStart) + pOffsetBaroSensorOffset,    // Barometric Sensor Offset * 1000 (psig or kPa)
  1581. #endif
  1582. #ifdef useVehicleMass
  1583.   (uint8_t)(eeAdrSettingsStart) + pOffsetVehicleMass,   // Vehicle Weight/Mass (lbs or kg)
  1584. #endif
  1585. #ifdef useCoastDownCalculator
  1586.   (uint8_t)(eeAdrSettingsStart) + pOffsetVehicleFrontalArea,    // Vehicle Frontal Area * 1000 (ft^2 or m^2)
  1587.   (uint8_t)(eeAdrSettingsStart) + pOffsetLocustDensity,   // Air density (lb/yd^3 or kg/m^3)
  1588.   (uint8_t)(eeAdrSettingsStart) + pOffsetCoefficientD,    // Vehicle C(d) * 1000
  1589.   (uint8_t)(eeAdrSettingsStart) + pOffsetCoefficientV,    // Vehicle C(v) * 1000
  1590.   (uint8_t)(eeAdrSettingsStart) + pOffsetCoefficientRR,   // Vehicle C(rr) * 1000
  1591. #endif
  1592.   (uint8_t)(eeAdrSettingsStart) + pOffsetActivityTimeout,   // Activity Timeout (s)
  1593.   (uint8_t)(eeAdrSettingsStart) + pOffsetWakeupResetCurrentOnEngine,    // Enable current trip reset upon wakeup due to engine running
  1594.   (uint8_t)(eeAdrSettingsStart) + pOffsetWakeupResetCurrentOnButton,    // Enable current trip reset upon wakeup due to button press
  1595. #ifdef useSerialPortDataLogging
  1596.   (uint8_t)(eeAdrSettingsStart) + pOffsetSerialDataLogging,   // Serial Data Logging Enable
  1597. #endif
  1598. #ifdef useWindowFilter
  1599.   (uint8_t)(eeAdrSettingsStart) + pOffsetWindowFilter,    // Window Filter Enable
  1600. #endif
  1601. #ifdef useBarFuelEconVsTime
  1602.   (uint8_t)(eeAdrSettingsStart) + pOffsetFEvsTime,      // Period Of FE over Time Bar Graph Bar (s)
  1603. #endif
  1604. #ifdef useSavedTrips
  1605.   (uint8_t)(eeAdrSettingsStart) + pOffsetAutoSaveActive,    // Autosave Active Trip Data Enable
  1606. #ifdef trackIdleEOCdata
  1607.   (uint8_t)(eeAdrSettingsStart) + pOffsetAutoSaveIdle,    // Autosave Idle Trip Data Enable
  1608. #endif
  1609. #endif
  1610. #ifdef useBarFuelEconVsSpeed
  1611.   (uint8_t)(eeAdrSettingsStart) + pOffsetBarLowSpeedCutoff,   // FE vs Speed Bargraph lower speed
  1612.   (uint8_t)(eeAdrSettingsStart) + pOffsetBarSpeedQuantumIdx,    // FE vs Speed Bargraph speed bar size
  1613. #endif
  1614. #ifdef useFuelCost
  1615.   (uint8_t)(eeAdrSettingsStart) + pOffsetFuelUnitCost,    // Price per unit volume of fuel
  1616. #endif
  1617.   (uint8_t)(eeAdrSettingsStart) + pOffsetScratchpad,      // Scratchpad Memory
  1618.   (uint8_t)(eeAdrSettingsStart) + pOffsetZZ,        // Start address of next EEPROM logical block
  1619. };
  1620.  
  1621. const uint32_t params[] PROGMEM = {
  1622. #ifdef useLegacyLCD
  1623.   120,             // LCD Contrast
  1624. #endif
  1625.   0,              // Display Mode (0 - US Display, 1 - Metric Display)
  1626.   0,              // Fuel Injector Edge Trigger (0 - Falling Edge, 1 - Rising Edge)
  1627. #ifdef useIsqrt
  1628.   36005,              // Fuel System Pressure * 1000 (psig or Pa)
  1629. #endif
  1630. #ifdef useCalculatedFuelFactor
  1631.   36005,              // Reference Fuel Injector Rated Pressure * 1000 (psig or Pa)
  1632.   4,              // Fuel Injector Count
  1633.   615,              // Fuel Injector Rated Capacity in mL/min
  1634. #endif
  1635.   133262651,            // Microseconds per (gal or L)
  1636.   550,              // Fuel Injector Response Delay Time (us)
  1637.   20000,              // VSS Pulses (per mile or per km)
  1638.   2,              // VSS Pause Debounce Count (ms)
  1639.   1,              // Crankshaft Revolutions per Fuel Injector Event
  1640.   100,              // Minimum Engine Speed For Engine On (RPM)
  1641.   10000,              // Tank Capacity * 1000 (gal or L)
  1642. #ifdef useChryslerMAPCorrection
  1643.   0,              // MAP Sensor Floor * 1000 (mV)
  1644.   0,              // Barometric Sensor Floor * 1000 (mV)
  1645.   4500,             // MAP Sensor Ceiling * 1000 (mV)
  1646.   4500,             // Barometric Sensor Ceiling * 1000 (mV)
  1647.   14270,              // MAP Sensor Range * 1000 (psig or kPa)
  1648.   0,              // Barometric Sensor Range * 1000 (psig or kPa)
  1649.   551,              // MAP Sensor Offset * 1000 (psig or kPa)
  1650.   14696,              // Barometric Sensor Offset * 1000 (psig or kPa)
  1651. #endif
  1652. #ifdef useVehicleMass
  1653.   2000,             // Vehicle Weight/Mass (lbs or kg)
  1654. #endif
  1655. #ifdef useCoastDownCalculator
  1656.   25400,              // Vehicle Frontal Area (ft^2 or m^2)
  1657.   2065,             // Air density (lb/yd^3 or kg/m^3)
  1658.   346,              // C(d)
  1659.   1,              // C(v)
  1660.   8,              // C(rr)
  1661. #endif
  1662.   90,              // Activity Timeout (s)
  1663.   1,              // Enable current trip reset upon wakeup due to engine running
  1664.   0,              // Enable current trip reset upon wakeup due to button press
  1665. #ifdef useSerialPortDataLogging
  1666.   1,              // Serial Data Logging Enable
  1667. #endif
  1668. #ifdef useWindowFilter
  1669.   1,              // Window Filter Enable
  1670. #endif
  1671. #ifdef useBarFuelEconVsTime
  1672.   5,              // Length Of BarGraph Bar (s)
  1673. #endif
  1674. #ifdef useSavedTrips
  1675.   1,              // Autosave Active Trip Data Enable
  1676. #ifdef trackIdleEOCdata
  1677.   1,              // Autosave Idle Trip Data Enable
  1678. #endif
  1679. #endif
  1680. #ifdef useBarFuelEconVsSpeed
  1681.   25000,              // FE vs Speed Bargraph lower speed
  1682.   5000,             // FE vs Speed Bargraph speed bar size
  1683. #endif
  1684. #ifdef useFuelCost
  1685.   3799,             // Price per unit volume of fuel
  1686. #endif
  1687.   0,              // Scratchpad Memory
  1688. };
  1689.  
  1690. const uint8_t settingsSize = (sizeof(params) / sizeof(uint32_t));
  1691.  
  1692. const unsigned int eePtrSettingsEnd = eePtrSettingsStart + (unsigned int)(settingsSize);
  1693. const unsigned int eeAdrSettingsEnd = eeAdrSettingsStart + (unsigned int)(pOffsetZZ);
  1694.  
  1695. // end of remarkably long EEPROM stored settings section
  1696.  
  1697. const unsigned long newEEPROMsignature = ((unsigned long)(guinosig) << 16) + ((unsigned long)(settingsSize) << 8) + (unsigned long)(EEPROMusage);
  1698.  
  1699. #define nextAllowedValue eePtrSettingsEnd
  1700. #define nextAllowedValue2 eeAdrSettingsEnd
  1701. #ifdef useScreenEditor
  1702. const unsigned int eePtrScreensStart = nextAllowedValue;
  1703. const unsigned int eeAdrScreensStart = nextAllowedValue2;
  1704. const unsigned int eePtrScreensEnd = eePtrScreensStart + (unsigned int)(displayFormatSize);
  1705. const unsigned int eeAdrScreensEnd = eeAdrScreensStart + (unsigned int)(displayFormatSize);
  1706. #define nextAllowedValue eePtrScreensEnd
  1707. #define nextAllowedValue2 eeAdrScreensEnd
  1708. #endif
  1709. #ifdef useSavedTrips
  1710. const unsigned int eePtrSavedTripsStart = nextAllowedValue;
  1711. const unsigned int eeAdrSavedTripsStart = nextAllowedValue2;
  1712. const unsigned int eeAdrSavedTripsTemp1 = (unsigned int)(E2END) - eeAdrSavedTripsStart + 1;
  1713. const uint8_t eeAdrSavedTripsTemp2 = (uint8_t)(eeAdrSavedTripsTemp1 / (unsigned int)(eepromTripListSize));
  1714. const uint8_t eeAdrSavedTripsTemp3 = ((tripSaveSlotCount > eeAdrSavedTripsTemp2) ? eeAdrSavedTripsTemp2 : tripSaveSlotCount);
  1715. const unsigned int eePtrSavedTripsEnd = eePtrSavedTripsStart + (unsigned int)(tripListSize) * (unsigned int)(eeAdrSavedTripsTemp3);
  1716. const unsigned int eeAdrSavedTripsEnd = eeAdrSavedTripsStart + (unsigned int)(eepromTripListSize) * (unsigned int)(eeAdrSavedTripsTemp3);
  1717. #define nextAllowedValue eePtrSavedTripsEnd
  1718. #define nextAllowedValue2 eeAdrSavedTripsEnd
  1719. #endif
  1720. const uint8_t eePtrEnd = nextAllowedValue;
  1721.  
  1722. #ifdef useSavedTrips
  1723. const uint8_t tripSelectList[] PROGMEM = {
  1724.   tankIdx,
  1725.   currentIdx,
  1726. #ifdef trackIdleEOCdata
  1727.   eocIdleTankIdx,
  1728.   eocIdleCurrentIdx,
  1729. #endif
  1730. };
  1731.  
  1732. const uint8_t tslSize = (sizeof(tripSelectList) / sizeof(uint8_t));
  1733. const uint8_t tslSubSize = 4;
  1734. const uint8_t tslCount = tslSize * tslSubSize;
  1735. const uint8_t tripMenuSize = tslCount + 1; // size of trip menu
  1736. const uint8_t tripValueLabelSize = 7;
  1737. const uint8_t tripValueSize = tripValueLabelSize * 2 - 4;
  1738.  
  1739. const char ertvNames[] PROGMEM = {
  1740.   "Ident\0"
  1741.   "Timestamp\0"
  1742.   "Inj Pulse\0"
  1743.   "VSS Pulse\0"
  1744.   "Inj Cyc\0"
  1745.   "Inj OpenCyc\0"
  1746.   "VSS Cyc\0"
  1747. };
  1748.  
  1749. const char tripNames[] PROGMEM = {
  1750.   "View Active \0"
  1751.   "Save \0"
  1752.   "Load \0"
  1753.   "Reset \0"
  1754.   "View Saved\0"
  1755. };
  1756.  
  1757. #endif
  1758.  
  1759. const char overFlowStr[] PROGMEM = " ---- ";
  1760.  
  1761. const char bigFEDispChars[] PROGMEM = {
  1762.   "RAW \0"
  1763.   "INST\0"
  1764.   "CURR\0"
  1765.   "TANK\0"
  1766. #ifdef trackIdleEOCdata
  1767.   "rC/I\0"
  1768.   "iC/I\0"
  1769.   "cC/I\0"
  1770.   "tC/I\0"
  1771. #endif
  1772. #ifdef useBarFuelEconVsTime
  1773.   "FE/T\0"
  1774. #endif
  1775. };
  1776.  
  1777. const char paramButtonChars[] PROGMEM = {
  1778.   " OK\0"
  1779.   " XX\0"
  1780. };
  1781.  
  1782. #ifdef useBigNumberDisplay
  1783. #ifdef useSpiffyBigChars
  1784. #ifdef useParallaxLCD
  1785. const uint8_t decimalPtChar = 46;
  1786. #define allTurnedOn 0x0C
  1787. #else
  1788. const uint8_t decimalPtChar = 0x0C;
  1789. #define allTurnedOn 255
  1790. #endif
  1791. const char bigNumChars1[] PROGMEM = {
  1792.   0x0E, 0x08, 0x0F, 0,
  1793.   0x08, allTurnedOn, 32, 0,
  1794.   0x0A, 0x0A, 0x0F, 0,
  1795.   0x08, 0x0A, 0x0F, 0,
  1796.   allTurnedOn, 0x09, allTurnedOn, 0,
  1797.   allTurnedOn, 0x0A, 0x0A, 0,
  1798.   0x0E, 0x0A, 0x0A, 0,
  1799.   0x08, 0x08, 0x0D, 0,
  1800.   0x0E, 0x0A, 0x0F, 0,
  1801.   0x0E, 0x0A, 0x0F, 0,
  1802.   32, 32, 32, 0,
  1803.   0x09, 0x09, 0x09, 0,
  1804. };
  1805.  
  1806. const char bigNumChars2[] PROGMEM = {
  1807.   0x0B, 0x09, 0x0D, 0,
  1808.   32, allTurnedOn, 32, 0,
  1809.   allTurnedOn, 0x09, 0x09, 0,
  1810.   0x09, 0x09, 0x0D, 0,
  1811.   32, 32, allTurnedOn, 0,
  1812.   0x09, 0x09, 0x0D, 0,
  1813.   0x0B, 0x09, 0x0D, 0,
  1814.   32, 0x0E, 32, 0,
  1815.   0x0B, 0x09, 0x0D, 0,
  1816.   0x09, 0x09, 0x0D, 0,
  1817.   32, 32, 32, 0,
  1818.   32, 32, 32, 0,
  1819. };
  1820.  
  1821. const char bigNumFont[] PROGMEM = {
  1822.   cgramBigNum, // font code
  1823.   8, // number of characters in font
  1824.  
  1825.   0b00011111, // char 0x08
  1826.   0b00011111,
  1827.   0b00000000,
  1828.   0b00000000,
  1829.   0b00000000,
  1830.   0b00000000,
  1831.   0b00000000,
  1832.   0b00000000,
  1833.  
  1834.   0b00000000, // char 0x09
  1835.   0b00000000,
  1836.   0b00000000,
  1837.   0b00000000,
  1838.   0b00000000,
  1839.   0b00000000,
  1840.   0b00011111,
  1841.   0b00011111,
  1842.  
  1843.   0b00011111, // char 0x0A
  1844.   0b00011111,
  1845.   0b00000000,
  1846.   0b00000000,
  1847.   0b00000000,
  1848.   0b00000000,
  1849.   0b00011111,
  1850.   0b00011111,
  1851.  
  1852.   0b00011111, // char 0x0B
  1853.   0b00011111,
  1854.   0b00011111,
  1855.   0b00011111,
  1856.   0b00011111,
  1857.   0b00011111,
  1858.   0b00001111,
  1859.   0b00000111,
  1860.  
  1861. #ifdef useParallaxLCD
  1862.   0b00011111, // char 0x0C
  1863.   0b00011111,
  1864.   0b00011111,
  1865.   0b00011111,
  1866.   0b00011111,
  1867.   0b00011111,
  1868.   0b00011111,
  1869.   0b00011111,
  1870. #else
  1871.   0b00000000, // char 0x0C
  1872.   0b00000000,
  1873.   0b00000000,
  1874.   0b00000000,
  1875.   0b00000000,
  1876.   0b00001110,
  1877.   0b00001110,
  1878.   0b00001110,
  1879. #endif
  1880.  
  1881.   0b00011111, // char 0x0D
  1882.   0b00011111,
  1883.   0b00011111,
  1884.   0b00011111,
  1885.   0b00011111,
  1886.   0b00011111,
  1887.   0b00011110,
  1888.   0b00011100,
  1889.  
  1890.   0b00000111, // char 0x0E
  1891.   0b00001111,
  1892.   0b00011111,
  1893.   0b00011111,
  1894.   0b00011111,
  1895.   0b00011111,
  1896.   0b00011111,
  1897.   0b00011111,
  1898.  
  1899.   0b00011100, // char 0x0F
  1900.   0b00011110,
  1901.   0b00011111,
  1902.   0b00011111,
  1903.   0b00011111,
  1904.   0b00011111,
  1905.   0b00011111,
  1906.   0b00011111,
  1907. };
  1908. #else
  1909. const uint8_t decimalPtChar = 0x0C;
  1910. const char bigNumChars1[] PROGMEM = {
  1911.   0x0B, 0x08, 0x0B, 0,
  1912.   0x08, 0x0B, 32, 0,
  1913.   0x0A, 0x0A, 0x0B, 0,
  1914.   0x08, 0x0A, 0x0B, 0,
  1915.   0x0B, 0x09, 0x0B, 0,
  1916.   0x0B, 0x0A, 0x0A, 0,
  1917.   0x0B, 0x0A, 0x0A, 0,
  1918.   0x08, 0x08, 0x0B, 0,
  1919.   0x0B, 0x0A, 0x0B, 0,
  1920.   0x0B, 0x0A, 0x0B, 0,
  1921.   32, 32, 32, 0,
  1922.   0x09, 0x09, 0x09, 0,
  1923. };
  1924.  
  1925. const char bigNumChars2[] PROGMEM = {
  1926.   0x0B, 0x09, 0x0B, 0,
  1927.   0x09, 0x0B, 0x09, 0,
  1928.   0x0B, 0x09, 0x09, 0,
  1929.   0x09, 0x09, 0x0B, 0,
  1930.   32, 32, 0x0B, 0,
  1931.   0x09, 0x09, 0x0B, 0,
  1932.   0x0B, 0x09, 0x0B, 0,
  1933.   32, 0x0B, 32, 0,
  1934.   0x0B, 0x09, 0x0B, 0,
  1935.   0x09, 0x09, 0x0B, 0,
  1936.   32, 32, 32, 0,
  1937.   32, 32, 32, 0,
  1938. };
  1939.  
  1940. const char bigNumFont[] PROGMEM = {
  1941.   cgramBigNum, // font code
  1942.   5, // number of characters in font
  1943.  
  1944.   0b00011111, // char 0x08
  1945.   0b00011111,
  1946.   0b00000000,
  1947.   0b00000000,
  1948.   0b00000000,
  1949.   0b00000000,
  1950.   0b00000000,
  1951.   0b00000000,
  1952.  
  1953.   0b00000000, // char 0x09
  1954.   0b00000000,
  1955.   0b00000000,
  1956.   0b00000000,
  1957.   0b00000000,
  1958.   0b00000000,
  1959.   0b00011111,
  1960.   0b00011111,
  1961.  
  1962.   0b00011111, // char 0x0A
  1963.   0b00011111,
  1964.   0b00000000,
  1965.   0b00000000,
  1966.   0b00000000,
  1967.   0b00000000,
  1968.   0b00011111,
  1969.   0b00011111,
  1970.  
  1971.   0b00011111, // char 0x0B
  1972.   0b00011111,
  1973.   0b00011111,
  1974.   0b00011111,
  1975.   0b00011111,
  1976.   0b00011111,
  1977.   0b00011111,
  1978.   0b00011111,
  1979.  
  1980.   0b00000000, // char 0x0C
  1981.   0b00000000,
  1982.   0b00000000,
  1983.   0b00000000,
  1984.   0b00000000,
  1985.   0b00001110,
  1986.   0b00001110,
  1987.   0b00001110
  1988. };
  1989. #endif
  1990. #endif
  1991.  
  1992. const uint8_t tripUpdateSrcList[] PROGMEM = {
  1993.   rawIdx | 0x80,            // transfer raw trip data to instant (disable interrupts)
  1994.   instantIdx,           // update tank trip with instant - this must be here, or 'remaining' calculations will be off
  1995.   instantIdx,           // update current trip with instant
  1996. #ifdef trackIdleEOCdata
  1997.   rawIdleIdx | 0x80,          // transfer raw idle/EOC trip data to idle/EOC instant (disable interrupts)
  1998.   eocIdleInstantIdx,          // update idle tank trip with idle instant
  1999.   eocIdleInstantIdx,          // update idle current trip with idle instant
  2000. #endif
  2001. #ifdef useBarFuelEconVsTime
  2002.   instantIdx,           // update bargraph periodic trip with instant
  2003. #endif
  2004. #ifdef useCoastDownCalculator
  2005.   thisCoastDownIdx,         // transfer last loop's coastdown trip data to last coastdown trip
  2006.   instantIdx,           // update this loop's coastdown trip with instant
  2007. #endif
  2008. };
  2009.  
  2010. const uint8_t tripUpdateDestList[] PROGMEM = {
  2011.   instantIdx | 0x80,          // transfer raw trip data to instant
  2012.   tankIdx,            // update tank trip with instant - this must be here, or 'remaining' calculations will be off
  2013.   currentIdx,             // update current trip with instant
  2014. #ifdef trackIdleEOCdata
  2015.   eocIdleInstantIdx | 0x80,       // transfer raw idle/EOC trip data to idle/EOC instant
  2016.   eocIdleTankIdx,           // update idle tank trip with idle instant
  2017.   eocIdleCurrentIdx,          // update idle current trip with idle instant
  2018. #endif
  2019. #ifdef useBarFuelEconVsTime
  2020.   periodIdx,            // update bargraph periodic trip with instant
  2021. #endif
  2022. #ifdef useCoastDownCalculator
  2023.   lastCoastDownIdx | 0x80,        // transfer last loop's coastdown trip data to last coastdown trip
  2024.   thisCoastDownIdx,         // update this loop's coastdown trip with instant
  2025. #endif
  2026. #ifdef useBarFuelEconVsSpeed
  2027.   FEvsSpeedIdx,           // ensure this matches the value in bgDataSize
  2028.   FEvsSpeedIdx + 1,
  2029.   FEvsSpeedIdx + 2,
  2030.   FEvsSpeedIdx + 3,
  2031.   FEvsSpeedIdx + 4,
  2032.   FEvsSpeedIdx + 5,
  2033.   FEvsSpeedIdx + 6,
  2034.   FEvsSpeedIdx + 7,
  2035.   FEvsSpeedIdx + 8,
  2036.   FEvsSpeedIdx + 9,
  2037.   FEvsSpeedIdx + 10,
  2038.   FEvsSpeedIdx + 11,
  2039.   FEvsSpeedIdx + 12,
  2040.   FEvsSpeedIdx + 13,
  2041.   FEvsSpeedIdx + 14,
  2042. #endif
  2043. };
  2044.  
  2045. const uint8_t tUScount = (sizeof(tripUpdateSrcList) / sizeof(uint8_t));
  2046. const uint8_t tUDcount = (sizeof(tripUpdateDestList) / sizeof(uint8_t));
  2047.  
  2048. const uint8_t convIdx[] PROGMEM = {
  2049.   pPulsesPerDistanceIdx,
  2050.   pMicroSecondsPerQuantityIdx,
  2051.   pTankSizeIdx,
  2052. #ifdef useVehicleMass
  2053.   pVehicleMassIdx,
  2054. #endif
  2055. #ifdef useCoastDownCalculator
  2056.   pVehicleFrontalAreaIdx,
  2057.   pLocustDensityIdx,
  2058. #endif
  2059. #ifdef useCalculatedFuelFactor
  2060.   pSysFuelPressureIdx,
  2061.   pRefFuelPressureIdx,
  2062. #endif
  2063. #ifdef useChryslerMAPCorrection
  2064.   pMAPsensorRangeIdx,
  2065.   pMAPsensorOffsetIdx,
  2066.   pBaroSensorRangeIdx,
  2067.   pBaroSensorOffsetIdx,
  2068. #endif
  2069. #ifdef useBarFuelEconVsSpeed
  2070.   pBarLowSpeedCutoffIdx,
  2071.   pBarSpeedQuantumIdx,
  2072. #endif
  2073. #ifdef useFuelCost
  2074.   pCostPerQuantity,
  2075. #endif
  2076. };
  2077.  
  2078. const uint8_t convSize = (sizeof(convIdx) / sizeof(uint8_t));
  2079.  
  2080. const uint8_t idxNumerDistance = 0;
  2081. const uint8_t idxDenomDistance = idxNumerDistance + 1;
  2082. const uint8_t idxNumerVolume = idxDenomDistance + 1;
  2083. const uint8_t idxDenomVolume = idxNumerVolume + 1;
  2084. const uint8_t idxCyclesPerSecond = idxDenomVolume + 1;
  2085. const uint8_t idxMicroSecondsPerSecond = idxCyclesPerSecond + 1;
  2086. const uint8_t idxDecimalPoint = idxMicroSecondsPerSecond + 1;
  2087. const uint8_t idxMetricFE = idxDecimalPoint + 1;
  2088. const uint8_t idxSecondsPerHour = idxMetricFE + 1;
  2089. const uint8_t idxBiggestNumber = idxSecondsPerHour + 1;
  2090. const uint8_t idxNumber7nines = idxBiggestNumber + 1;
  2091. const uint8_t idxNumber6nines = idxNumber7nines + 1;
  2092. const uint8_t idxNumber5nines = idxNumber6nines + 1;
  2093. const uint8_t idxNumber500 = idxNumber5nines + 1;
  2094. const uint8_t idxNumber50 = idxNumber500 + 1;
  2095. const uint8_t idxNumber5 = idxNumber50 + 1;
  2096. #define nextAllowedValue idxNumber5
  2097. #ifdef useCPUreading
  2098. const uint8_t idxNumerCPUutil = nextAllowedValue + 1;
  2099. const uint8_t idxDenomCPUutil = idxNumerCPUutil + 1;
  2100. #define nextAllowedValue idxDenomCPUutil
  2101. #endif
  2102. #ifdef useClock
  2103. const uint8_t idxSecondsPerDay = nextAllowedValue + 1;
  2104. #define nextAllowedValue idxSecondsPerDay
  2105. #endif
  2106. #ifdef useIsqrt
  2107. const uint8_t idxNumerPressure = nextAllowedValue + 1;
  2108. const uint8_t idxDenomPressure = idxNumerPressure + 1;
  2109. const uint8_t idxCorrFactor = idxDenomPressure + 1;
  2110. #define nextAllowedValue idxCorrFactor
  2111. #endif
  2112. #ifdef useAnalogRead
  2113. const uint8_t idxNumerVoltage = nextAllowedValue + 1;
  2114. const uint8_t idxDenomVoltage = idxNumerVoltage + 1;
  2115. #define nextAllowedValue idxDenomVoltage
  2116. #endif
  2117. #ifdef useVehicleMass
  2118. const uint8_t idxNumerMass = nextAllowedValue + 1;
  2119. const uint8_t idxDenomMass = idxNumerMass + 1;
  2120. #define nextAllowedValue idxDenomMass
  2121. #endif
  2122. #ifdef useCoastDownCalculator
  2123. const uint8_t idxNumerArea = nextAllowedValue + 1;
  2124. const uint8_t idxDenomArea = idxNumerArea + 1;
  2125. const uint8_t idxNumerDensity = idxDenomArea + 1;
  2126. const uint8_t idxDenomDensity = idxNumerDensity + 1;
  2127. #define nextAllowedValue idxDenomDensity
  2128. #endif
  2129.  
  2130. const uint32_t convNumbers[] PROGMEM = {
  2131.   1000000ul,
  2132.   1609344ul,
  2133.   1000000000ul,
  2134.   3785411784ul,
  2135.   t2CyclesPerSecond,
  2136.   1000000ul,
  2137.   1000ul,
  2138.   100000ul,
  2139.   3600,
  2140.   0xFFFFFFFE,
  2141.   10000000,
  2142.   1000000,
  2143.   100000,
  2144.   500,
  2145.   50,
  2146.   5,
  2147. #ifdef useCPUreading
  2148.   10000ul,
  2149.   loopSystemLength,
  2150. #endif
  2151. #ifdef useClock
  2152.   86400,
  2153. #endif
  2154. #ifdef useIsqrt
  2155.   68947573ul,
  2156.   10000000ul,
  2157.   4096,
  2158. #endif
  2159. #ifdef useAnalogRead
  2160.   1024ul,
  2161.   5000ul,
  2162. #endif
  2163. #ifdef useVehicleMass
  2164.   1000000000ul,
  2165.   2204622621ul,
  2166. #endif
  2167. #ifdef useCoastDownCalculator
  2168.   9290304,
  2169.   100000000,
  2170.   100000,
  2171.   168555,
  2172. #endif
  2173. };
  2174.  
  2175. const uint8_t DNUISinstrDone =        0;
  2176. const uint8_t DNUISinstrTraceOn =       DNUISinstrDone + 1;
  2177. const uint8_t DNUISinstrTraceOff =      DNUISinstrTraceOn + 1;
  2178. const uint8_t DNUISinstrSkipIfMetricMode =    DNUISinstrTraceOff + 1;
  2179. const uint8_t DNUISinstrSkipIfZero =      DNUISinstrSkipIfMetricMode + 1;
  2180. const uint8_t DNUISinstrSkipIfLTorE =       DNUISinstrSkipIfZero + 1;
  2181. const uint8_t DNUISinstrSkipIfLSBset =      DNUISinstrSkipIfLTorE + 1;
  2182. const uint8_t DNUISinstrSkipIfMSBset =      DNUISinstrSkipIfLSBset + 1;
  2183. const uint8_t DNUISinstrSkipIfIndexBelow =    DNUISinstrSkipIfMSBset + 1;
  2184. const uint8_t DNUISinstrSkip =        DNUISinstrSkipIfIndexBelow + 1;
  2185. const uint8_t DNUISinstrLd =        DNUISinstrSkip + 1;
  2186. const uint8_t DNUISinstrLdByte =      DNUISinstrLd + 1;
  2187. const uint8_t DNUISinstrLdByteFromYindexed =    DNUISinstrLdByte + 1;
  2188. const uint8_t DNUISinstrLdTripVar =       DNUISinstrLdByteFromYindexed + 1;
  2189. const uint8_t DNUISinstrLdTtlFuelUsed =     DNUISinstrLdTripVar + 1;
  2190. const uint8_t DNUISinstrLdConst =       DNUISinstrLdTtlFuelUsed + 1;
  2191. const uint8_t DNUISinstrLdEEPROM =      DNUISinstrLdConst + 1;
  2192. const uint8_t DNUISinstrStByteToYindexed =    DNUISinstrLdEEPROM + 1;
  2193. const uint8_t DNUISinstrStEEPROM =      DNUISinstrStByteToYindexed + 1;
  2194. const uint8_t DNUISinstrLdEEPROMindexed =     DNUISinstrStEEPROM + 1;
  2195. const uint8_t DNUISinstrLdEEPROMindirect =    DNUISinstrLdEEPROMindexed + 1;
  2196. const uint8_t DNUISinstrStEEPROMindirect =    DNUISinstrLdEEPROMindirect + 1;
  2197. const uint8_t DNUISinstrLdIndex =       DNUISinstrStEEPROMindirect + 1;
  2198. const uint8_t DNUISinstrLdNumer =       DNUISinstrLdIndex + 1;
  2199. const uint8_t DNUISinstrLdDenom =       DNUISinstrLdNumer + 1;
  2200. const uint8_t DNUISinstrCall =        DNUISinstrLdDenom + 1;
  2201. const uint8_t DNUISinstrJump =        DNUISinstrCall + 1;
  2202. const uint8_t DNUISinstrSwap =        DNUISinstrJump + 1;
  2203. const uint8_t DNUISinstrSubYfromX =       DNUISinstrSwap + 1;
  2204. const uint8_t DNUISinstrAddYtoX =       DNUISinstrSubYfromX + 1;
  2205. #define nextAllowedValue DNUISinstrAddYtoX
  2206. #ifndef useSWEET64multDiv
  2207. const uint8_t DNUISinstrMulXbyY =       DNUISinstrAddYtoX + 1;
  2208. const uint8_t DNUISinstrDivXbyY =       DNUISinstrMulXbyY + 1;
  2209. #define nextAllowedValue DNUISinstrDivXbyY
  2210. #endif
  2211. const uint8_t DNUISinstrShiftLeft =       nextAllowedValue + 1;
  2212. const uint8_t DNUISinstrShiftRight =      DNUISinstrShiftLeft + 1;
  2213. const uint8_t DNUISinstrAddToIndex =      DNUISinstrShiftRight + 1;
  2214. #define nextAllowedValue DNUISinstrAddToIndex
  2215. #ifdef useIsqrt
  2216. const uint8_t DNUISinstrIsqrt =       nextAllowedValue + 1;
  2217. #define nextAllowedValue DNUISinstrIsqrt
  2218. #endif
  2219. #ifdef useAnalogRead
  2220. const uint8_t DNUISinstrLdVoltage =       nextAllowedValue + 1;
  2221. #define nextAllowedValue DNUISinstrLdVoltage
  2222. #endif
  2223. #ifdef useChryslerMAPCorrection
  2224. const uint8_t DNUISinstrLdPressure =      nextAllowedValue + 1;
  2225. #define nextAllowedValue DNUISinstrLdPressure
  2226. #endif
  2227.  
  2228. #define instrDone     DNUISinstrDone
  2229. #define instrTraceOn      DNUISinstrTraceOn
  2230. #define instrTraceOff     DNUISinstrTraceOff
  2231. #define instrSkipIfMetricMode   (DNUISinstrSkipIfMetricMode | 0x80)
  2232. #define instrSkipIfZero     (DNUISinstrSkipIfZero | 0x80 | 0x40)
  2233. #define instrSkipIfLTorE    (DNUISinstrSkipIfLTorE | 0x80 | 0x40)
  2234. #define instrSkipIfLSBset   (DNUISinstrSkipIfLSBset | 0x80 | 0x40)
  2235. #define instrSkipIfMSBset   (DNUISinstrSkipIfMSBset | 0x80 | 0x40)
  2236. #define instrSkipIfIndexBelow   (DNUISinstrSkipIfIndexBelow | 0x80)
  2237. #define instrSkip     (DNUISinstrSkip | 0x80)
  2238. #define instrLd       (DNUISinstrLd | 0x40)
  2239. #define instrLdByte     (DNUISinstrLdByte | 0x80 | 0x40)
  2240. #define instrLdByteFromYindexed   (DNUISinstrLdByteFromYindexed | 0x40)
  2241. #define instrLdTripVar      (DNUISinstrLdTripVar | 0x80 | 0x40)
  2242. #define instrLdTtlFuelUsed    (DNUISinstrLdTtlFuelUsed | 0x40)
  2243. #define instrLdConst      (DNUISinstrLdConst | 0x80 | 0x40)
  2244. #define instrLdEEPROM     (DNUISinstrLdEEPROM | 0x80 | 0x40)
  2245. #define instrStByteToYindexed   (DNUISinstrStByteToYindexed | 0x40)
  2246. #define instrStEEPROM     (DNUISinstrStEEPROM | 0x80 | 0x40)
  2247. #define instrLdEEPROMindexed    (DNUISinstrLdEEPROMindexed | 0x80 | 0x40)
  2248. #define instrLdEEPROMindirect   (DNUISinstrLdEEPROMindirect | 0x40)
  2249. #define instrStEEPROMindirect   (DNUISinstrStEEPROMindirect | 0x40)
  2250. #define instrLdIndex      (DNUISinstrLdIndex | 0x80)
  2251. #define instrLdNumer      (DNUISinstrLdNumer | 0x40)
  2252. #define instrLdDenom      (DNUISinstrLdDenom | 0x40)
  2253. #define instrCall     (DNUISinstrCall | 0x80)
  2254. #define instrJump     (DNUISinstrJump | 0x80)
  2255. #define instrSwap     (DNUISinstrSwap | 0x40)
  2256. #define instrSubYfromX      (DNUISinstrSubYfromX | 0x40)
  2257. #define instrAddYtoX      (DNUISinstrAddYtoX | 0x40)
  2258. #ifndef useSWEET64multDiv
  2259. #define instrMulXbyY      (DNUISinstrMulXbyY | 0x40)
  2260. #define instrDivXbyY      (DNUISinstrDivXbyY | 0x40)
  2261. #endif
  2262. #define instrShiftLeft      (DNUISinstrShiftLeft | 0x40)
  2263. #define instrShiftRight     (DNUISinstrShiftRight | 0x40)
  2264. #define instrAddToIndex     (DNUISinstrAddToIndex | 0x80)
  2265. #ifdef useAnalogRead
  2266. #define instrLdVoltage      (DNUISinstrLdVoltage | 0x40)
  2267. #endif
  2268. #ifdef useChryslerMAPCorrection
  2269. #define instrLdPressure     (DNUISinstrLdPressure | 0x40)
  2270. #endif
  2271. #ifdef useIsqrt
  2272. #define instrIsqrt      (DNUISinstrIsqrt | 0x40)
  2273. #endif
  2274.  
  2275. const uint8_t idxS64findRemainingFuel = dfMaxValDisplayCount;
  2276. const uint8_t idxS64doMultiply = idxS64findRemainingFuel + 1;
  2277. const uint8_t idxS64doDivide = idxS64doMultiply + 1;
  2278. const uint8_t idxS64findCyclesPerQuantity = idxS64doDivide + 1;
  2279. const uint8_t idxS64doConvertToMicroSeconds = idxS64findCyclesPerQuantity + 1;
  2280. const uint8_t idxS64doAdjust = idxS64doConvertToMicroSeconds + 1;
  2281. const uint8_t idxS64doNumber = idxS64doAdjust + 1;
  2282.  
  2283. const uint8_t prgmEngineSpeed[] PROGMEM = {
  2284.   instrLdTripVar, 0x02, rvInjPulseIdx,
  2285.   instrLdConst, 0x01, idxCyclesPerSecond,
  2286.   instrCall, idxS64doMultiply,
  2287.   instrLdByte, 0x01, 60,          // load seconds per minute into register 1
  2288.   instrCall, idxS64doMultiply,
  2289.   instrLdConst, 0x01, idxDecimalPoint,
  2290.   instrCall, idxS64doMultiply,
  2291.   instrLdEEPROM, 0x01, pCrankRevPerInjIdx,
  2292.   instrCall, idxS64doMultiply,
  2293.   instrLdTripVar, 0x01, rvInjCycleIdx,
  2294.   instrJump, idxS64doDivide,
  2295. };
  2296.  
  2297. const uint8_t prgmMotionTime[] PROGMEM = {
  2298.   instrLdTripVar, 0x02, rvVSScycleIdx,
  2299.   instrLdConst, 0x01, idxCyclesPerSecond,
  2300.   instrJump, idxS64doDivide,
  2301. };
  2302.  
  2303. const uint8_t prgmDistance[] PROGMEM = {
  2304.   instrLdTripVar, 0x02, rvVSSpulseIdx,
  2305.   instrLdConst, 0x01, idxDecimalPoint,
  2306.   instrCall, idxS64doMultiply,
  2307.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,
  2308.   instrJump, idxS64doDivide,
  2309. };
  2310.  
  2311. const uint8_t prgmSpeed[] PROGMEM = {
  2312.   instrLdTripVar, 0x02, rvVSScycleIdx,
  2313.   instrSkipIfZero, 0x02, 29,
  2314.  
  2315.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,
  2316.   instrCall, idxS64doMultiply,
  2317.   instrSwap, 0x23,
  2318.   instrLdTripVar, 0x02, rvVSSpulseIdx,
  2319.   instrLdConst, 0x01, idxDecimalPoint,
  2320.   instrCall, idxS64doMultiply,
  2321.   instrLdConst, 0x01, idxCyclesPerSecond,
  2322.   instrCall, idxS64doMultiply,
  2323.   instrLdConst, 0x01, idxSecondsPerHour,
  2324.   instrCall, idxS64doMultiply,
  2325.   instrSwap, 0x13,
  2326.   instrJump, idxS64doDivide,
  2327.  
  2328.   instrDone
  2329. };
  2330.  
  2331. #ifdef useBarFuelEconVsSpeed
  2332. const uint8_t prgmFEvsSpeed[] PROGMEM = {
  2333.   instrLdEEPROM, 0x01, pBarLowSpeedCutoffIdx,   // convert stored distance per hour to pulses per hour
  2334.   instrLdEEPROM, 0x02, pPulsesPerDistanceIdx,
  2335.   instrCall, idxS64doMultiply,
  2336.   instrLdConst, 0x01, idxDecimalPoint,
  2337.   instrCall, idxS64doDivide,
  2338.   instrSwap, 0x23,
  2339.  
  2340.   instrLdTripVar, 0x02, rvVSSpulseIdx,      // generate speed in pulses per hour
  2341.   instrLdConst, 0x01, idxCyclesPerSecond,
  2342.   instrCall, idxS64doMultiply,
  2343.   instrLdConst, 0x01, idxSecondsPerHour,
  2344.   instrCall, idxS64doMultiply,
  2345.   instrLdTripVar, 0x01, rvVSScycleIdx,
  2346.   instrCall, idxS64doDivide,
  2347.  
  2348.   instrSkipIfLTorE, 0x32, 4,        // if (converted value <= generated value), skip to next section
  2349.   instrLdByte, 0x02, 0xFF,        // load a 255 into register 2
  2350.   instrDone,            // exit to caller
  2351.  
  2352.   instrSubYfromX, 0x23,         // subtract converted value from generated value
  2353.   instrSwap, 0x23,
  2354.  
  2355.   instrLdEEPROM, 0x01, pBarSpeedQuantumIdx,   // convert stored distance per hour to pulses per hour
  2356.   instrLdEEPROM, 0x02, pPulsesPerDistanceIdx,
  2357.   instrCall, idxS64doMultiply,
  2358.   instrLdConst, 0x01, idxDecimalPoint,
  2359.   instrCall, idxS64doDivide,
  2360.   instrSkipIfZero, 0x02, 232,       // if (bargraph size == 0), load an 0xFF into register 2 and exit to caller
  2361.   instrSwap, 0x21,          // move to denominator position
  2362.  
  2363.   instrSwap, 0x23,          // get numerator (generated - converted value)
  2364.   instrCall, idxS64doDivide,        // perform division
  2365.  
  2366.   instrLdByte, 0x01, bgDataSize,        // compare to bargraph data size
  2367.   instrSkipIfLTorE, 0x12, 220,        // if (bargraph size <= calculated value), load an 0xFF into register 2 and exit to caller
  2368.   instrLdByte, 0x01, FEvsSpeedIdx,      // convert calculated value into a trip index
  2369.   instrAddYtoX, 0x21,
  2370.   instrDone
  2371. };
  2372. #endif
  2373.  
  2374. const uint8_t prgmFuelUsed[] PROGMEM = {
  2375.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,
  2376.   instrSkipIfZero, 0x02, 9,
  2377.  
  2378.   instrLdConst, 0x01, idxDecimalPoint,
  2379.   instrCall, idxS64doMultiply,
  2380.   instrCall, idxS64findCyclesPerQuantity,
  2381.   instrJump, idxS64doDivide,
  2382.  
  2383.   instrDone,
  2384. };
  2385.  
  2386. #ifdef useFuelCost
  2387. const uint8_t prgmFuelCost[] PROGMEM = {
  2388.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,
  2389.   instrSkipIfZero, 0x02, 9,
  2390.  
  2391.   instrLdEEPROM, 0x01, pCostPerQuantity,
  2392.   instrCall, idxS64doMultiply,
  2393.   instrCall, idxS64findCyclesPerQuantity,
  2394.   instrJump, idxS64doDivide,
  2395.  
  2396.   instrDone,
  2397. };
  2398.  
  2399. const uint8_t prgmFuelRateCost[] PROGMEM = {
  2400.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,
  2401.   instrSkipIfZero, 0x02, 25,
  2402.  
  2403.   instrLdEEPROM, 0x01, pCostPerQuantity,
  2404.   instrCall, idxS64doMultiply,
  2405.   instrLdTripVar, 0x01, rvInjCycleIdx,
  2406.   instrCall, idxS64doDivide,
  2407.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2408.   instrCall, idxS64doMultiply,
  2409.   instrLdConst, 0x01, idxSecondsPerHour,
  2410.   instrCall, idxS64doMultiply,
  2411.   instrLdEEPROM, 0x01, pMicroSecondsPerQuantityIdx,
  2412.   instrJump, idxS64doDivide,
  2413.  
  2414.   instrDone
  2415. };
  2416.  
  2417. const uint8_t prgmFuelCostPerDistance[] PROGMEM = {
  2418.   instrLdTripVar, 0x02, rvVSSpulseIdx,      // fetch the accumulated number of VSS pulses counted
  2419.   instrCall, idxS64findCyclesPerQuantity,     // calculate the cycles per unit fuel quantity factor
  2420.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the denominator for fuel cost per distance
  2421.   instrSwap, 0x23,          // save it for later
  2422.  
  2423.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,    // fetch the accumulated fuel injector open cycle measurement
  2424.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,   // fetch the pulses per unit distance factor
  2425.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the numerator for fuel cost per distance
  2426.   instrLdEEPROM, 0x01, pCostPerQuantity,      // load fuel cost per unit quantity into register 1
  2427.   instrCall, idxS64doMultiply,        // multiply the numerator by the formatting term
  2428.  
  2429.   instrSwap, 0x13,          // move the denominator term into position
  2430.   instrJump, idxS64doDivide,        // divide the numerator by the denominator, then exit to caller
  2431. };
  2432.  
  2433. const uint8_t prgmDistancePerFuelCost[] PROGMEM = {
  2434.   instrLdTripVar, 0x02, rvVSSpulseIdx,      // fetch the accumulated number of VSS pulses counted
  2435.   instrCall, idxS64findCyclesPerQuantity,     // calculate the cycles per unit fuel quantity factor
  2436.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the numerator for distance per fuel cost
  2437.   instrLdConst, 0x01, idxDecimalPoint,      // load the decimal point constant used for output formatting
  2438.   instrCall, idxS64doMultiply,        // multiply the numerator by the formatting term
  2439.   instrLdConst, 0x01, idxDecimalPoint,      // load the decimal point constant used for output formatting
  2440.   instrCall, idxS64doMultiply,        // multiply the numerator by the formatting term
  2441.   instrSwap, 0x23,          // save it for later
  2442.  
  2443.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,    // fetch the accumulated fuel injector open cycle measurement
  2444.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,   // fetch the pulses per unit distance factor
  2445.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the denominator for distance per fuel cost
  2446.   instrLdEEPROM, 0x01, pCostPerQuantity,      // load fuel cost per unit quantity into register 1
  2447.   instrCall, idxS64doMultiply,        // multiply the numerator by the formatting term
  2448.   instrSwap, 0x23,          // swap the numerator and denominator terms around
  2449.  
  2450.   instrSwap, 0x13,          // move the denominator term into position
  2451.   instrJump, idxS64doDivide,        // divide the numerator by the denominator, then exit to caller
  2452. };
  2453.  
  2454. const uint8_t prgmRemainingFuelCost[] PROGMEM = {
  2455.   instrCall, idxS64findRemainingFuel,
  2456.   instrSkipIfZero, 0x02, 20,
  2457.  
  2458.   instrLdEEPROM, 0x01, pCostPerQuantity,
  2459.   instrCall, idxS64doMultiply,
  2460.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2461.   instrCall, idxS64doMultiply,
  2462.   instrLdConst, 0x01, idxCyclesPerSecond,
  2463.   instrCall, idxS64doDivide,
  2464.   instrLdEEPROM, 0x01, pMicroSecondsPerQuantityIdx,
  2465.   instrJump, idxS64doDivide,
  2466.  
  2467.   instrDone
  2468. };
  2469. #endif
  2470.  
  2471. const uint8_t prgmEngineRunTime[] PROGMEM = {
  2472.   instrLdTripVar, 0x02, rvInjCycleIdx,
  2473.   instrLdConst, 0x01, idxCyclesPerSecond,
  2474.   instrJump, idxS64doDivide,
  2475. };
  2476.  
  2477. const uint8_t prgmFuelRate[] PROGMEM = {
  2478.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,
  2479.   instrSkipIfZero, 0x02, 25,
  2480.  
  2481.   instrLdConst, 0x01, idxDecimalPoint,
  2482.   instrCall, idxS64doMultiply,
  2483.   instrLdTripVar, 0x01, rvInjCycleIdx,
  2484.   instrCall, idxS64doDivide,
  2485.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2486.   instrCall, idxS64doMultiply,
  2487.   instrLdConst, 0x01, idxSecondsPerHour,
  2488.   instrCall, idxS64doMultiply,
  2489.   instrLdEEPROM, 0x01, pMicroSecondsPerQuantityIdx,
  2490.   instrJump, idxS64doDivide,
  2491.  
  2492.   instrDone
  2493. };
  2494.  
  2495. const uint8_t prgmFuelEcon[] PROGMEM = {
  2496.   instrLdTripVar, 0x02, rvVSSpulseIdx,      // fetch the accumulated number of VSS pulses counted
  2497.   instrCall, idxS64findCyclesPerQuantity,     // calculate the cycles per unit fuel quantity factor
  2498.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the denominator for fuel economy
  2499.   instrSwap, 0x23,          // save it for later
  2500.  
  2501.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,    // fetch the accumulated fuel injector open cycle measurement
  2502.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,   // fetch the pulses per unit distance factor
  2503.   instrCall, idxS64doMultiply,        // multiply the two numbers to get the numerator for fuel economy
  2504.  
  2505.   instrSkipIfMetricMode, 7,       // if metric mode set, skip ahead
  2506.   instrSwap, 0x23,          // swap the numerator and denominator terms around
  2507.   instrLdConst, 0x01, idxDecimalPoint,      // load the decimal point constant used for output formatting
  2508.   instrSkip, 3,           // go skip ahead
  2509.  
  2510.   instrLdConst, 0x01, idxMetricFE,      // load the output formatting decimal point constant, multiplied by 100 (for 100km/L)
  2511.  
  2512.   instrSkipIfZero, 0x02, 6,       // if the numerator term is zero, go exit
  2513.  
  2514.   instrCall, idxS64doMultiply,        // multiply the numerator by the formatting term
  2515.   instrSwap, 0x13,          // move the denominator term into position
  2516.   instrJump, idxS64doDivide,        // divide the numerator by the denominator, then exit to caller
  2517.  
  2518.   instrDone           // exit to caller
  2519. };
  2520.  
  2521. const uint8_t prgmFindRemainingFuel[] PROGMEM = {
  2522.   instrLdEEPROM, 0x02, pTankSizeIdx,
  2523.   instrLdEEPROM, 0x01, pMicroSecondsPerQuantityIdx,
  2524.   instrCall, idxS64doMultiply,
  2525.   instrLdConst, 0x01, idxCyclesPerSecond,
  2526.   instrCall, idxS64doMultiply,
  2527.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2528.   instrCall, idxS64doDivide,
  2529.   instrLdConst, 0x01, idxDecimalPoint,
  2530.   instrCall, idxS64doDivide,
  2531.   instrLdTtlFuelUsed, 0x01,
  2532.  
  2533.   instrSkipIfLTorE, 0x12, 4,
  2534.  
  2535.   instrLdByte, 0x02, 0,
  2536.   instrDone,
  2537.  
  2538.   instrSubYfromX, 0x21,
  2539.   instrDone
  2540. };
  2541.  
  2542. const uint8_t prgmRemainingFuel[] PROGMEM = {
  2543.   instrCall, idxS64findRemainingFuel,
  2544.   instrSkipIfZero, 0x02, 20,
  2545.  
  2546.   instrLdConst, 0x01, idxDecimalPoint,
  2547.   instrCall, idxS64doMultiply,
  2548.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2549.   instrCall, idxS64doMultiply,
  2550.   instrLdConst, 0x01, idxCyclesPerSecond,
  2551.   instrCall, idxS64doDivide,
  2552.   instrLdEEPROM, 0x01, pMicroSecondsPerQuantityIdx,
  2553.   instrJump, idxS64doDivide,
  2554.  
  2555.   instrDone
  2556. };
  2557.  
  2558. const uint8_t prgmDistanceToEmpty[] PROGMEM = {
  2559.   instrCall, idxS64findRemainingFuel,
  2560.   instrSkipIfZero, 0x02, 22,
  2561.  
  2562.   instrLdConst, 0x01, idxDecimalPoint,
  2563.   instrCall, idxS64doMultiply,
  2564.   instrLdTripVar, 0x01, rvInjOpenCycleIdx,
  2565.   instrCall, idxS64doDivide,
  2566.   instrLdTripVar, 0x01, rvVSSpulseIdx,
  2567.   instrCall, idxS64doMultiply,
  2568.   instrLdEEPROM, 0x01, pPulsesPerDistanceIdx,
  2569.   instrCall, idxS64doDivide,
  2570.   instrJump, idxS64doAdjust,
  2571.  
  2572.   instrDone
  2573. };
  2574.  
  2575. const uint8_t prgmTimeToEmpty[] PROGMEM = {
  2576.   instrLdConst, 0x01, idxCyclesPerSecond,
  2577.   instrLdConst, 0x02, idxMicroSecondsPerSecond,
  2578.   instrCall, idxS64doMultiply,
  2579.   instrSwap, 0x23,
  2580.  
  2581.   instrCall, idxS64findRemainingFuel,
  2582.   instrSkipIfZero, 0x02, 19,
  2583.  
  2584.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2585.   instrCall, idxS64doMultiply,
  2586.   instrLdTripVar, 0x01, rvInjOpenCycleIdx,
  2587.   instrCall, idxS64doDivide,
  2588.   instrLdTripVar, 0x01, rvInjCycleIdx,
  2589.   instrCall, idxS64doMultiply,
  2590.   instrSwap, 0x13,
  2591.   instrJump, idxS64doDivide,
  2592.  
  2593.   instrDone
  2594. };
  2595.  
  2596. const uint8_t prgmInjectorOpenTime[] PROGMEM = {
  2597.   instrLdTripVar, 0x02, rvInjOpenCycleIdx,
  2598.   instrJump, idxS64doConvertToMicroSeconds,
  2599. };
  2600.  
  2601. const uint8_t prgmInjectorTotalTime[] PROGMEM = {
  2602.   instrLdTripVar, 0x02, rvInjCycleIdx,
  2603.   instrJump, idxS64doConvertToMicroSeconds,
  2604. };
  2605.  
  2606. const uint8_t prgmVSStotalTime[] PROGMEM = {
  2607.   instrLdTripVar, 0x02, rvVSScycleIdx,
  2608.   instrJump, idxS64doConvertToMicroSeconds,
  2609. };
  2610.  
  2611. const uint8_t prgmVSSpulseCount[] PROGMEM = {
  2612.   instrLdTripVar, 0x02, rvVSSpulseIdx,
  2613.   instrDone
  2614. };
  2615.  
  2616. const uint8_t prgmInjectorPulseCount[] PROGMEM = {
  2617.   instrLdTripVar, 0x02, rvInjPulseIdx,
  2618.   instrDone
  2619. };
  2620. #ifdef useAnalogRead
  2621.  
  2622. const uint8_t prgmVoltage[] PROGMEM = {
  2623.   instrLdConst, 0x02, idxDenomVoltage,
  2624.   instrLdVoltage, 0x01,
  2625.   instrCall, idxS64doMultiply,
  2626.   instrLdConst, 0x01, idxNumerVoltage,
  2627.   instrJump, idxS64doDivide,
  2628. };
  2629. #endif
  2630. #ifdef useChryslerMAPCorrection
  2631.  
  2632. const uint8_t prgmPressure[] PROGMEM = {
  2633.   instrLdPressure, 0x02,
  2634.   instrDone
  2635. };
  2636.  
  2637. const uint8_t prgmCorrF[] PROGMEM = {
  2638.   instrLdConst, 0x02, idxDecimalPoint,
  2639.   instrLdPressure, 0x01,
  2640.   instrCall, idxS64doMultiply,
  2641.   instrLdConst, 0x01, idxCorrFactor,
  2642.   instrJump, idxS64doDivide,
  2643. };
  2644. #endif
  2645.  
  2646. const uint8_t prgmConvertToMicroSeconds[] PROGMEM = {
  2647.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2648.   instrCall, idxS64doMultiply,
  2649.   instrLdConst, 0x01, idxCyclesPerSecond,
  2650.   instrJump, idxS64doDivide,
  2651. };
  2652.  
  2653. const uint8_t prgmDoMultiply[] PROGMEM = {
  2654. #ifdef useSWEET64multDiv
  2655.   instrLd, 0x41,            // load multiplier into register 4
  2656.   instrLd, 0x52,            // load multiplicand into register 5
  2657.   instrLdByte, 0x02, 0,         // zero out result (register 2)
  2658.  
  2659.   instrSkipIfZero, 0x04, 13,        // if multiplier is zero, exit
  2660.   instrSkipIfLSBset, 0x04, 2,       // if the low bit of multiplier is zet, skip ahead
  2661.  
  2662.   instrSkip, 2,           // jump to multiplicand/multiplier adjust
  2663.  
  2664.   instrAddYtoX, 0x25,         // add multiplicand to result
  2665.  
  2666.   instrShiftLeft, 0x05,         // shift multiplicand left by one bit
  2667.   instrShiftRight, 0x04,          // shift multiplier right by one bit
  2668.   instrSkip, 240,           // jump back to multiplier tests
  2669. #else
  2670.   instrMulXbyY, 0x21,
  2671. #endif
  2672.   instrDone           // exit to caller
  2673. };
  2674.  
  2675. const uint8_t prgmDoDivide[] PROGMEM = {
  2676. #ifdef useSWEET64multDiv
  2677.   instrSkipIfZero, 0x02, 13,        // exit if dividend is zero
  2678.   instrSkipIfZero, 0x01, 2,       // skip if divisor is zero
  2679.   instrSkip, 11,            // skip ahead
  2680.   instrLdByte, 0x02, 0,         // zero out result (register 2)
  2681.   instrLdByte, 0x05, 1,         // load 1 into register 5
  2682.   instrSubYfromX, 0x25,         // set overflow value in result
  2683.   instrLd, 0x12,            // set overflow (or zero numerator) value in remainder
  2684.   instrDone,            // exit to caller
  2685.  
  2686.   instrLd, 0x41,            // load register 4 with divisor
  2687.   instrLd, 0x12,            // load register 1 with dividend
  2688.   instrLdByte, 0x05, 1,         // load register 5 with quotient bitmask
  2689.   instrLdByte, 0x02, 0,         // load result (register 2) with initialized quotient
  2690.  
  2691.   instrSkipIfMSBset, 0x04, 6,       // if divisor has been leftshifted to MSB, skip ahead
  2692.   instrShiftLeft, 0x04,         // shift divisor left one bit
  2693.   instrShiftLeft, 0x05,         // shift quotient bitmask left one bit
  2694.   instrSkip, 247,           // skip back to divisor test
  2695.  
  2696.   instrSkipIfZero, 0x05, 233,       // if quotient bitmask is zero, exit
  2697.   instrSkipIfLTorE, 0x41, 2,        // if divisor is less than or equal to dividend, skip ahead
  2698.   instrSkip, 4,           // skip to divisor/quotient bitmask adjustment routine
  2699.   instrSubYfromX, 0x14,         // subtract divisor from dividend
  2700.   instrAddYtoX, 0x25,               // add quotient bitmask to quotient
  2701.   instrShiftRight, 0x04,          // shift divisor right by one bit
  2702.   instrShiftRight, 0x05,          // shift quotient bitmask right by one bit
  2703.   instrSkip, 238,           // go back to quotient bitmask test
  2704. #else
  2705.   instrDivXbyY, 0x21,
  2706.   instrDone           // exit to caller
  2707. #endif
  2708. };
  2709.  
  2710. const uint8_t prgmDoAdjust[] PROGMEM = {
  2711.   instrSkipIfLTorE, 0x14, 1,        // if (divisor / 2 <= dividend), skip to next section
  2712.   instrDone,
  2713.  
  2714.   instrLdByte, 0x05, 1,         // load a 1 into the old quotient bitmask register
  2715.   instrAddYtoX, 0x25,         // bump up quotient by one
  2716.   instrDone           // exit to caller
  2717. };
  2718.  
  2719. const uint8_t prgmRoundOffNumber[] PROGMEM = {
  2720.   instrLdConst, 0x01, idxNumber7nines,      // if number is greater than 9999, round off to nearest 1
  2721.   instrSkipIfLTorE, 0x12, 25,
  2722.   instrLdConst, 0x01, idxNumber6nines,      // if number is greater than 999, round off to nearest 1/10th
  2723.   instrSkipIfLTorE, 0x12, 24,
  2724.   instrLdConst, 0x01, idxNumber5nines,      // if number is greater than 99, round off to nearest 1/100th
  2725.   instrSkipIfLTorE, 0x12, 23,
  2726.  
  2727.   instrAddToIndex, 253,         // determine whether a number of right-hand digits were specified
  2728.   instrSkipIfIndexBelow, 23, 253,       // skip if there were no specified number of of right-hand digits
  2729.   instrSkipIfIndexBelow, 5, 254,        // skip if 0 right-hand digits were specified
  2730.   instrSkipIfIndexBelow, 7, 255,        // skip if 1 right-hand digit was specified
  2731.   instrSkip, 10,            // skip if 2 right-hand digits were specified
  2732.  
  2733.   instrLdConst, 0x01, idxNumber500,
  2734.   instrSkip, 8,
  2735.   instrLdConst, 0x01, idxNumber50,
  2736.   instrSkip, 3,
  2737.   instrLdConst, 0x01, idxNumber5,
  2738.  
  2739.   instrAddYtoX, 0x21,
  2740.  
  2741.   instrLdConst, 0x01, idxBiggestNumber,     // if number is less than biggest number, go perform round-off
  2742.   instrSkipIfLTorE, 0x21, 8,
  2743.  
  2744.   instrLdIndex, 6,
  2745.   instrLdByte, 0x01, 255,         // signal overflow by loading 255 into length byte
  2746.   instrStByteToYindexed, 0x13,        // store total length into byte 6 of register 3
  2747.   instrDone,
  2748.  
  2749.   instrJump, idxS64doNumber,
  2750. };
  2751.  
  2752. const uint8_t prgmFormatToNumber[] PROGMEM = {
  2753.   instrLdIndex, 4,          // load 5 into index
  2754.   instrLdByte, 0x01, 100,         // load 100 into register 1
  2755.   instrCall, idxS64doDivide,        // perform division - quotient remains in register 2, and remainder goes into register 1
  2756.   instrStByteToYindexed, 0x13,        // store remainder into indexed byte of register 3
  2757.   instrAddToIndex, 255,         // update index
  2758.   instrSkipIfIndexBelow, 244, 255,      // continue if index is greater than or equal to 0
  2759.  
  2760.   instrLdIndex, 7,
  2761.   instrLdByte, 0x01, 32,          // load leading zero character into register 1
  2762.   instrStByteToYindexed, 0x13,        // store leading zero character into byte 7 of register 3
  2763.   instrLdIndex, 6,
  2764.   instrLdByte, 0x01, 5,         // load total length into register 1
  2765.   instrStByteToYindexed, 0x13,        // store total length into byte 6 of register 3
  2766.   instrDone,
  2767. };
  2768.  
  2769. const uint8_t prgmFindCyclesPerQuantity[] PROGMEM = {
  2770.   instrSwap, 0x23,
  2771.   instrLdConst, 0x01, idxCyclesPerSecond,
  2772.   instrLdEEPROM, 0x02, pMicroSecondsPerQuantityIdx,
  2773.   instrCall, idxS64doMultiply,
  2774.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  2775.   instrCall, idxS64doDivide,
  2776.   instrLd, 0x12,
  2777.   instrSwap, 0x23,
  2778.   instrDone
  2779. };
  2780.  
  2781. const uint8_t prgmFormatToTime[] PROGMEM = {
  2782.   instrLdIndex, 2,
  2783.   instrLdByte, 0x01, 60,          // load seconds per minute into register 1
  2784.   instrCall, idxS64doDivide,
  2785.   instrStByteToYindexed, 0x13,
  2786.   instrLdIndex, 1,
  2787.   instrLdByte, 0x01, 60,          // load minutes per hour into register 1
  2788.   instrCall, idxS64doDivide,
  2789.   instrStByteToYindexed, 0x13,
  2790.   instrLdIndex, 0,
  2791.   instrLdByte, 0x01, 24,          // load hours per day into register 1
  2792.   instrCall, idxS64doDivide,
  2793.   instrStByteToYindexed, 0x13,
  2794.   instrLdIndex, 7,
  2795.   instrLdByte, 0x01, 48,          // load leading zero character into register 1
  2796.   instrStByteToYindexed, 0x13,        // store leading zero character into byte 7 of register 3
  2797.   instrLdIndex, 6,
  2798.   instrLdByte, 0x01, 3,         // load total length into register 1
  2799.   instrStByteToYindexed, 0x13,        // store total length into byte 6 of register 3
  2800.   instrDone
  2801. };
  2802.  
  2803. const uint8_t convNumerIdx[] PROGMEM = {
  2804.   idxNumerDistance,
  2805.   idxNumerVolume,
  2806.   idxDenomVolume,
  2807. #ifdef useVehicleMass
  2808.   idxNumerMass,
  2809. #endif
  2810. #ifdef useCoastDownCalculator
  2811.   idxNumerArea,
  2812.   idxNumerDensity,
  2813. #endif
  2814. #ifdef useCalculatedFuelFactor
  2815.   idxNumerPressure,
  2816.   idxNumerPressure,
  2817. #endif
  2818. #ifdef useChryslerMAPCorrection
  2819.   idxNumerPressure,
  2820.   idxNumerPressure,
  2821.   idxNumerPressure,
  2822.   idxNumerPressure,
  2823. #endif
  2824. #ifdef useBarFuelEconVsSpeed
  2825.   idxNumerDistance,
  2826.   idxNumerDistance,
  2827. #endif
  2828. #ifdef useFuelCost
  2829.   idxNumerVolume,
  2830. #endif
  2831. };
  2832.  
  2833. #ifdef useScreenEditor
  2834. uint8_t displayFormats[(unsigned int)(displayFormatSize)] = {
  2835. #else
  2836. const uint8_t displayFormats[(unsigned int)(displayFormatSize)] PROGMEM = {
  2837. #endif
  2838.   (instantIdx << dfBitShift) | tSpeed,      (instantIdx << dfBitShift) | tEngineSpeed,    (instantIdx << dfBitShift) | tFuelRate,     (instantIdx << dfBitShift) | tFuelEcon,
  2839.   (instantIdx << dfBitShift) | tFuelEcon,     (instantIdx << dfBitShift) | tSpeed,      (instantIdx << dfBitShift) | tFuelRate,     (currentIdx << dfBitShift) | tFuelEcon,
  2840. #ifdef useChryslerMAPCorrection
  2841.   (instantIdx << dfBitShift) | tPressureChannel0,   (instantIdx << dfBitShift) | tPressureChannel1,   (instantIdx << dfBitShift) | tPressureChannel3,   (instantIdx << dfBitShift) | tCorrectionFactor,
  2842. #endif
  2843. #ifdef useAnalogRead
  2844.   (instantIdx << dfBitShift) | tAnalogChannel0,   (instantIdx << dfBitShift) | tAnalogChannel1,   (instantIdx << dfBitShift) | tAnalogChannel0,   (instantIdx << dfBitShift) | tAnalogChannel1,
  2845. #endif
  2846.   (instantIdx << dfBitShift) | tFuelEcon,     (instantIdx << dfBitShift) | tSpeed,      (currentIdx << dfBitShift) | tFuelEcon,     (currentIdx << dfBitShift) | tDistance,
  2847.   (instantIdx << dfBitShift) | tFuelEcon,     (instantIdx << dfBitShift) | tSpeed,      (tankIdx << dfBitShift) | tFuelEcon,      (tankIdx << dfBitShift) | tDistance,
  2848.   (currentIdx << dfBitShift) | tSpeed,      (currentIdx << dfBitShift) | tFuelEcon,     (currentIdx << dfBitShift) | tDistance,     (currentIdx << dfBitShift) | tFuelUsed,
  2849.   (tankIdx << dfBitShift) | tSpeed,     (tankIdx << dfBitShift) | tFuelEcon,      (tankIdx << dfBitShift) | tDistance,      (tankIdx << dfBitShift) | tFuelUsed,
  2850. #ifdef trackIdleEOCdata
  2851.   (eocIdleCurrentIdx << dfBitShift) | tDistance,    (eocIdleCurrentIdx << dfBitShift) | tFuelUsed,    (eocIdleTankIdx << dfBitShift) | tDistance,   (eocIdleTankIdx << dfBitShift) | tFuelUsed,
  2852. #endif
  2853.   (tankIdx << dfBitShift) | tEngineRunTime,   (tankIdx << dfBitShift) | tFuelUsed,      (tankIdx << dfBitShift) | tMotionTime,      (tankIdx << dfBitShift) | tDistance,
  2854.   (currentIdx << dfBitShift) | tEngineRunTime,    (currentIdx << dfBitShift) | tFuelUsed,     (currentIdx << dfBitShift) | tMotionTime,   (currentIdx << dfBitShift) | tDistance,
  2855. #ifdef trackIdleEOCdata
  2856.   (eocIdleTankIdx << dfBitShift) | tEngineRunTime,  (eocIdleTankIdx << dfBitShift) | tFuelUsed,   (eocIdleTankIdx << dfBitShift) | tMotionTime,   (eocIdleTankIdx << dfBitShift) | tDistance,
  2857.   (eocIdleCurrentIdx << dfBitShift) | tEngineRunTime, (eocIdleCurrentIdx << dfBitShift) | tFuelUsed,    (eocIdleCurrentIdx << dfBitShift) | tMotionTime,  (eocIdleCurrentIdx << dfBitShift) | tDistance,
  2858. #endif
  2859.   (tankIdx << dfBitShift) | tFuelUsed,      (tankIdx << dfBitShift) | tRemainingFuel,   (tankIdx << dfBitShift) | tTimeToEmpty,     (tankIdx << dfBitShift) | tDistanceToEmpty
  2860. };
  2861.  
  2862. const uint16_t funcPointers[] PROGMEM = {
  2863.   (uint16_t)doNothing,
  2864.   (uint16_t)noSupport,
  2865.   (uint16_t)doCursorUpdateMain,
  2866.   (uint16_t)doCursorUpdateSetting,
  2867.   (uint16_t)doMainScreenDisplay,
  2868.   (uint16_t)doSettingEditDisplay,
  2869.   (uint16_t)doParamEditDisplay,
  2870.   (uint16_t)doGoSettingsEdit,
  2871.   (uint16_t)doNextBright,
  2872.   (uint16_t)doTripResetCurrent,
  2873.   (uint16_t)doLongGoRight,
  2874.   (uint16_t)doTripResetTank,
  2875.   (uint16_t)doLongGoLeft,
  2876.   (uint16_t)doReturnToMain,
  2877.   (uint16_t)doGoParamEdit,
  2878.   (uint16_t)doParamFindRight,
  2879.   (uint16_t)doParamExit,
  2880.   (uint16_t)doParamFindLeft,
  2881.   (uint16_t)doParamChangeDigit,
  2882.   (uint16_t)doParamSave,
  2883.   (uint16_t)doParamStoreMin,
  2884.   (uint16_t)doParamStoreMax,
  2885.   (uint16_t)doParamRevert,
  2886. #ifdef useCPUreading
  2887.   (uint16_t)doDisplaySystemInfo,
  2888.   (uint16_t)doShowCPU,
  2889. #endif
  2890. #ifdef useBigFE
  2891.   (uint16_t)doCursorUpdateBigFEscreen,
  2892.   (uint16_t)doBigFEdisplay,
  2893. #endif
  2894. #ifdef useBigDTE
  2895.   (uint16_t)doCursorUpdateBigDTEscreen,
  2896.   (uint16_t)doBigDTEdisplay,
  2897. #endif
  2898. #ifdef useBigTTE
  2899.   (uint16_t)doCursorUpdateBigTTEscreen,
  2900.   (uint16_t)doBigTTEdisplay,
  2901. #endif
  2902. #ifdef useClock
  2903.   (uint16_t)doCursorUpdateSystemTimeScreen,
  2904.   (uint16_t)doDisplaySystemTime,
  2905.   (uint16_t)doGoEditSystemTime,
  2906.   (uint16_t)doEditSystemTimeDisplay,
  2907.   (uint16_t)doEditSystemTimeCancel,
  2908.   (uint16_t)doEditSystemTimeChangeDigit,
  2909.   (uint16_t)doEditSystemTimeSave,
  2910. #endif
  2911. #ifdef useSavedTrips
  2912.   (uint16_t)doCursorUpdateTripShow,
  2913.   (uint16_t)doTripSaveDisplay,
  2914.   (uint16_t)doTripShowDisplay,
  2915.   (uint16_t)doGoTripCurrent,
  2916.   (uint16_t)doGoTripTank,
  2917.   (uint16_t)doTripBumpSlot,
  2918.   (uint16_t)doTripSelect,
  2919.   (uint16_t)doTripLongSelect,
  2920.   (uint16_t)doTripShowCancel,
  2921. #endif
  2922. #ifdef useScreenEditor
  2923.   (uint16_t)doScreenEditDisplay,
  2924.   (uint16_t)doGoScreenEdit,
  2925.   (uint16_t)doScreenEditReturnToMain,
  2926.   (uint16_t)doScreenEditRevert,
  2927.   (uint16_t)doSaveScreen,
  2928.   (uint16_t)doScreenEditBump,
  2929.   (uint16_t)doCursorUpdateScreenEdit,
  2930. #endif
  2931. #ifdef useBarFuelEconVsTime
  2932.   (uint16_t)doCursorUpdateBarFEvT,
  2933.   (uint16_t)doBarFEvTdisplay,
  2934. #endif
  2935. #ifdef useBarFuelEconVsSpeed
  2936.   (uint16_t)doCursorUpdateBarFEvS,
  2937.   (uint16_t)doBarFEvSdisplay,
  2938.   (uint16_t)doResetBarFEvS,
  2939. #endif
  2940. #ifdef useBenchMark
  2941.   (uint16_t)doBenchMark,
  2942. #endif
  2943. #ifdef useEEPROMviewer
  2944.   (uint16_t)doEEPROMviewDisplay,
  2945.   (uint16_t)goEEPROMview,
  2946. #endif
  2947. };
  2948.  
  2949. // Button Press variable section
  2950.  
  2951. const uint8_t bpListMain[] PROGMEM = {
  2952.   btnShortPressRL, idxDoGoSettingsEdit,
  2953.   btnShortPressC, idxDoNextBright,
  2954.   btnLongPressRC, idxDoTripResetCurrent,
  2955.   btnLongPressCL, idxDoTripResetTank,
  2956.   btnLongPressR, idxDoLongGoRight,
  2957.   btnLongPressL, idxDoLongGoLeft,
  2958. #ifdef useCPUreading
  2959.   btnLongPressC, idxDoShowCPU,
  2960. #endif
  2961. #ifdef useSavedTrips
  2962.   btnShortPressRC, idxDoGoTripCurrent,
  2963.   btnShortPressCL, idxDoGoTripTank,
  2964. #endif
  2965. #ifdef useScreenEditor
  2966.   btnLongPressRL, idxDoGoScreenEdit,
  2967. #endif
  2968. #ifdef useEEPROMviewer
  2969.   btnShortPressRCL, idxGoEEPROMview,
  2970. #endif
  2971.   buttonsUp, idxNoSupport,
  2972. };
  2973.  
  2974. const uint8_t bpListSetting[] PROGMEM = {
  2975.   btnShortPressRL, idxDoReturnToMain,
  2976.   btnShortPressC, idxDoGoParamEdit,
  2977.   btnLongPressRL, idxDoReturnToMain,
  2978. #ifdef useCPUreading
  2979.   btnLongPressC, idxDoShowCPU,
  2980. #endif
  2981.   buttonsUp, idxDoNothing,
  2982. };
  2983.  
  2984. const uint8_t bpListParam[] PROGMEM = {
  2985.   btnShortPressRC, idxDoParamFindRight,
  2986.   btnShortPressRL, idxDoParamExit,
  2987.   btnShortPressCL, idxDoParamFindLeft,
  2988.   btnShortPressC, idxDoParamChangeDigit,
  2989.   btnLongPressRC, idxDoParamStoreMin,
  2990.   btnLongPressRL, idxDoParamRevert,
  2991.   btnLongPressCL, idxDoParamStoreMax,
  2992.   btnLongPressC, idxDoParamSave,
  2993.   buttonsUp, idxDoNothing,
  2994. };
  2995.  
  2996. #ifdef useCPUreading
  2997. const uint8_t bpListCPUmonitor[] PROGMEM = {
  2998.   btnShortPressRL, idxDoGoSettingsEdit,
  2999.   btnShortPressC, idxDoNextBright,
  3000.   btnLongPressRC, idxDoTripResetCurrent,
  3001.   btnLongPressCL, idxDoTripResetTank,
  3002.   btnLongPressR, idxDoLongGoRight,
  3003.   btnLongPressL, idxDoLongGoLeft,
  3004.   btnLongPressC, idxDoShowCPU,
  3005. #ifdef useSavedTrips
  3006.   btnShortPressRC, idxDoGoTripCurrent,
  3007.   btnShortPressCL, idxDoGoTripTank,
  3008. #endif
  3009. #ifdef useBenchMark
  3010.   btnLongPressRCL, idxDoBenchMark,
  3011. #endif
  3012.   buttonsUp, idxDoNothing,
  3013. };
  3014.  
  3015. #endif
  3016. #ifdef useBigNumberDisplay
  3017. const uint8_t bpListBigNum[] PROGMEM = {
  3018.   btnShortPressRL, idxDoGoSettingsEdit,
  3019.   btnShortPressC, idxDoNextBright,
  3020.   btnLongPressRC, idxDoTripResetCurrent,
  3021.   btnLongPressCL, idxDoTripResetTank,
  3022.   btnLongPressR, idxDoLongGoRight,
  3023.   btnLongPressL, idxDoLongGoLeft,
  3024. #ifdef useCPUreading
  3025.   btnLongPressC, idxDoShowCPU,
  3026. #endif
  3027. #ifdef useSavedTrips
  3028.   btnShortPressRC, idxDoGoTripCurrent,
  3029.   btnShortPressCL, idxDoGoTripTank,
  3030. #endif
  3031.   buttonsUp, idxDoNothing,
  3032. };
  3033. #endif
  3034.  
  3035. #ifdef useBarFuelEconVsTime
  3036. const uint8_t bpListBFET[] PROGMEM = {
  3037.   btnShortPressRL, idxDoGoSettingsEdit,
  3038.   btnShortPressC, idxDoNextBright,
  3039.   btnLongPressRC, idxDoTripResetCurrent,
  3040.   btnLongPressCL, idxDoTripResetTank,
  3041.   btnLongPressR, idxDoLongGoRight,
  3042.   btnLongPressL, idxDoLongGoLeft,
  3043. #ifdef useCPUreading
  3044.   btnLongPressC, idxDoShowCPU,
  3045. #endif
  3046. #ifdef useSavedTrips
  3047.   btnShortPressRC, idxDoGoTripCurrent,
  3048.   btnShortPressCL, idxDoGoTripTank,
  3049. #endif
  3050.   buttonsUp, idxDoNothing,
  3051. };
  3052. #endif
  3053.  
  3054. #ifdef useBarFuelEconVsSpeed
  3055. const uint8_t bpListBFES[] PROGMEM = {
  3056.   btnShortPressRL, idxDoGoSettingsEdit,
  3057.   btnShortPressC, idxDoNextBright,
  3058.   btnLongPressRC, idxDoTripResetCurrent,
  3059.   btnLongPressCL, idxDoTripResetTank,
  3060.   btnLongPressR, idxDoLongGoRight,
  3061.   btnLongPressL, idxDoLongGoLeft,
  3062. #ifdef useCPUreading
  3063.   btnLongPressC, idxDoShowCPU,
  3064. #endif
  3065.   btnLongPressRCL, idxDoResetBarFEvS,
  3066. #ifdef useSavedTrips
  3067.   btnShortPressRC, idxDoGoTripCurrent,
  3068.   btnShortPressCL, idxDoGoTripTank,
  3069. #endif
  3070.   buttonsUp, idxDoNothing,
  3071. };
  3072. #endif
  3073.  
  3074. #ifdef useClock
  3075. const uint8_t bpListTime[] PROGMEM = {
  3076.   btnShortPressRL, idxDoGoEditSystemTime,
  3077.   btnShortPressC, idxDoNextBright,
  3078.   btnLongPressRC, idxDoTripResetCurrent,
  3079.   btnLongPressCL, idxDoTripResetTank,
  3080.   btnLongPressR, idxDoLongGoRight,
  3081.   btnLongPressL, idxDoLongGoLeft,
  3082. #ifdef useCPUreading
  3083.   btnLongPressC, idxDoShowCPU,
  3084. #endif
  3085. #ifdef useSavedTrips
  3086.   btnShortPressRC, idxDoGoTripCurrent,
  3087.   btnShortPressCL, idxDoGoTripTank,
  3088. #endif
  3089.   buttonsUp, idxDoNothing,
  3090. };
  3091.  
  3092. const uint8_t bpListClockEdit[] PROGMEM = {
  3093.   btnShortPressRL, idxDoEditSystemTimeCancel,
  3094.   btnShortPressC, idxDoEditSystemTimeChangeDigit,
  3095.   btnLongPressRL, idxDoEditSystemTimeCancel,
  3096.   btnLongPressC, idxDoEditSystemTimeSave,
  3097.   buttonsUp, idxDoNothing,
  3098. };
  3099. #endif
  3100.  
  3101. #ifdef useSavedTrips
  3102. const uint8_t bpListTripSave[] PROGMEM = {
  3103.   btnShortPressRL, idxDoReturnToMain,
  3104.   btnShortPressC, idxDoTripSelect,
  3105.   btnLongPressRC, idxDoTripResetCurrent,
  3106.   btnLongPressRL, idxDoReturnToMain,
  3107.   btnLongPressCL, idxDoTripResetTank,
  3108.   btnLongPressC, idxDoTripLongSelect,
  3109.   buttonsUp, idxDoNothing,
  3110. };
  3111.  
  3112. const uint8_t bpListTripView[] PROGMEM = {
  3113.   btnShortPressRL, idxDoTripShowCancel,
  3114.   btnShortPressC, idxDoTripBumpSlot,
  3115.   btnLongPressRL, idxDoReturnToMain,
  3116.   buttonsUp, idxDoNothing,
  3117. };
  3118. #endif
  3119.  
  3120. #ifdef useScreenEditor
  3121. const uint8_t bpListScreenEdit[] PROGMEM = {
  3122.   btnShortPressRL, idxDoScreenEditReturnToMain,
  3123.   btnShortPressC, idxDoScreenEditBump,
  3124.   btnLongPressRL, idxDoScreenEditRevert,
  3125.   btnLongPressC, idxDoSaveScreen,
  3126.   buttonsUp, idxDoNothing,
  3127. };
  3128. #endif
  3129.  
  3130. #ifdef useEEPROMviewer
  3131. const uint8_t bpListEEPROMview[] PROGMEM = {
  3132.   btnShortPressRL, idxDoReturnToMain,
  3133.   btnLongPressRL, idxDoReturnToMain,
  3134.   buttonsUp, idxDoNothing,
  3135. };
  3136. #endif
  3137.  
  3138. const uint8_t bpIdxMain = 0;
  3139. const uint8_t bpIdxSetting =  bpIdxMain + 1;
  3140. const uint8_t bpIdxParam =  bpIdxSetting + 1;
  3141. #define nextAllowedValue bpIdxParam
  3142. #ifdef useCPUreading
  3143. const uint8_t bpIdxCPUmonitor = nextAllowedValue + 1;
  3144. #define nextAllowedValue bpIdxCPUmonitor
  3145. #endif
  3146. #ifdef useBigNumberDisplay
  3147. const uint8_t bpIdxBigNum = nextAllowedValue + 1;
  3148. #define nextAllowedValue bpIdxBigNum
  3149. #endif
  3150. #ifdef useBarFuelEconVsTime
  3151. const uint8_t bpIdxBFET = nextAllowedValue + 1;
  3152. #define nextAllowedValue bpIdxBFET
  3153. #endif
  3154. #ifdef useBarFuelEconVsSpeed
  3155. const uint8_t bpIdxBFES = nextAllowedValue + 1;
  3156. #define nextAllowedValue bpIdxBFES
  3157. #endif
  3158. #ifdef useClock
  3159. const uint8_t bpIdxTime = nextAllowedValue + 1;
  3160. const uint8_t bpIdxClockEdit =  bpIdxTime + 1;
  3161. #define nextAllowedValue bpIdxClockEdit
  3162. #endif
  3163. #ifdef useSavedTrips
  3164. const uint8_t bpIdxTripSave = nextAllowedValue + 1;
  3165. const uint8_t bpIdxTripView = bpIdxTripSave + 1;
  3166. #define nextAllowedValue bpIdxTripView
  3167. #endif
  3168. #ifdef useScreenEditor
  3169. const uint8_t bpIdxScreenEdit = nextAllowedValue + 1;
  3170. #define nextAllowedValue bpIdxScreenEdit
  3171. #endif
  3172. #ifdef useEEPROMviewer
  3173. const uint8_t bpIdxEEPROMview = nextAllowedValue + 1;
  3174. #define nextAllowedValue bpIdxEEPROMview
  3175. #endif
  3176. const uint8_t bpIdxSize = nextAllowedValue + 1;
  3177.  
  3178. const uint8_t * const buttonPressAdrList[(unsigned int)(bpIdxSize)] PROGMEM = {
  3179.   bpListMain,
  3180.   bpListSetting,
  3181.   bpListParam,
  3182. #ifdef useCPUreading
  3183.   bpListCPUmonitor,
  3184. #endif
  3185. #ifdef useBigNumberDisplay
  3186.   bpListBigNum,
  3187. #endif
  3188. #ifdef useBarFuelEconVsTime
  3189.   bpListBFET,
  3190. #endif
  3191. #ifdef useBarFuelEconVsSpeed
  3192.   bpListBFES,
  3193. #endif
  3194. #ifdef useClock
  3195.   bpListTime,
  3196.   bpListClockEdit,
  3197. #endif
  3198. #ifdef useSavedTrips
  3199.   bpListTripSave,
  3200.   bpListTripView,
  3201. #endif
  3202. #ifdef useScreenEditor
  3203.   bpListScreenEdit,
  3204. #endif
  3205. #ifdef useEEPROMviewer
  3206.   bpListEEPROMview,
  3207. #endif
  3208. };
  3209.  
  3210. // Display screen variable section
  3211.  
  3212. const uint8_t mainScreenSize = 1
  3213. #ifdef useCPUreading
  3214.   + 1
  3215. #endif
  3216. #ifdef useBarFuelEconVsTime
  3217.   + 1
  3218. #endif
  3219. #ifdef useBarFuelEconVsSpeed
  3220.   + 1
  3221. #endif
  3222. #ifdef useBigFE
  3223.   + 1
  3224. #endif
  3225. #ifdef useBigDTE
  3226.   + 1
  3227. #endif
  3228. #ifdef useBigTTE
  3229.   + 1
  3230. #endif
  3231. #ifdef useClock
  3232.   + 1
  3233. #endif
  3234. ;
  3235.  
  3236. const uint8_t screenSize = mainScreenSize + 2
  3237. #ifdef useClock
  3238.   + 1
  3239. #endif
  3240. #ifdef useSavedTrips
  3241.   + 2
  3242. #endif
  3243. #ifdef useScreenEditor
  3244.   + 1
  3245. #endif
  3246. #ifdef useEEPROMviewer
  3247.   + 1
  3248. #endif
  3249. ;
  3250.  
  3251. const uint8_t mainScreenIdx =     0;
  3252. #define nextAllowedValue mainScreenIdx
  3253. #ifdef useBigFE
  3254. const uint8_t bigFEscreenIdx =      nextAllowedValue + 1;
  3255. #define nextAllowedValue bigFEscreenIdx
  3256. #endif
  3257. #ifdef useCPUreading
  3258. const uint8_t CPUmonScreenIdx =     nextAllowedValue + 1;
  3259. #define nextAllowedValue CPUmonScreenIdx
  3260. #endif
  3261. #ifdef useBarFuelEconVsTime
  3262. const uint8_t barFEvTscreenIdx =    nextAllowedValue + 1;
  3263. #define nextAllowedValue barFEvTscreenIdx
  3264. #endif
  3265. #ifdef useBarFuelEconVsSpeed
  3266. const uint8_t barFEvSscreenIdx =    nextAllowedValue + 1;
  3267. #define nextAllowedValue barFEvSscreenIdx
  3268. #endif
  3269. #ifdef useBigDTE
  3270. const uint8_t bigDTEscreenIdx =     nextAllowedValue + 1;
  3271. #define nextAllowedValue bigDTEscreenIdx
  3272. #endif
  3273. #ifdef useBigTTE
  3274. const uint8_t bigTTEscreenIdx =     nextAllowedValue + 1;
  3275. #define nextAllowedValue bigTTEscreenIdx
  3276. #endif
  3277. #ifdef useClock
  3278. const uint8_t systemTimeDisplayScreenIdx =  nextAllowedValue + 1;
  3279. #define nextAllowedValue systemTimeDisplayScreenIdx
  3280. #endif
  3281. const uint8_t settingScreenIdx =    nextAllowedValue + 1;
  3282. const uint8_t paramScreenIdx =      settingScreenIdx + 1;
  3283. #define nextAllowedValue paramScreenIdx
  3284. #ifdef useClock
  3285. const uint8_t systemTimeEditScreenIdx =   nextAllowedValue + 1;
  3286. #define nextAllowedValue systemTimeEditScreenIdx
  3287. #endif
  3288. #ifdef useSavedTrips
  3289. const uint8_t tripSaveScreenIdx =   nextAllowedValue + 1;
  3290. const uint8_t tripShowScreenIdx =   tripSaveScreenIdx + 1;
  3291. #define nextAllowedValue tripShowScreenIdx
  3292. #endif
  3293. #ifdef useScreenEditor
  3294. const uint8_t screenEditIdx =     nextAllowedValue + 1;
  3295. #define nextAllowedValue screenEditIdx
  3296. #endif
  3297. #ifdef useEEPROMviewer
  3298. const uint8_t eepromViewIdx =     nextAllowedValue + 1;
  3299. #define nextAllowedValue eepromViewIdx
  3300. #endif
  3301.  
  3302. const uint8_t screenParameters[(unsigned int)(screenSize)][6] PROGMEM = {
  3303.   mainScreenIdx,      mainScreenSize,   displayPageCount,   idxDoMainScreenDisplay,   idxDoCursorUpdateMain,      bpIdxMain,
  3304. #ifdef useBigFE
  3305.   mainScreenIdx,      mainScreenSize,   3,        idxDoBigFEdisplay,    idxDoCursorUpdateBigFEscreen,   bpIdxBigNum,
  3306. #endif
  3307. #ifdef useCPUreading
  3308.   mainScreenIdx,      mainScreenSize,   1,        idxDoDisplaySystemInfo,   idxDoNothing,       bpIdxCPUmonitor,
  3309. #endif
  3310. #ifdef useBarFuelEconVsTime
  3311.   mainScreenIdx,      mainScreenSize,   2,        idxDoBarFEvTdisplay,    idxDoCursorUpdateBarFEvT,   bpIdxBFET,
  3312. #endif
  3313. #ifdef useBarFuelEconVsSpeed
  3314.   mainScreenIdx,      mainScreenSize,   4,        idxDoBarFEvSdisplay,    idxDoCursorUpdateBarFEvS,   bpIdxBFES,
  3315. #endif
  3316. #ifdef useBigDTE
  3317.   mainScreenIdx,      mainScreenSize,   3,        idxDoBigDTEdisplay,   idxDoCursorUpdateBigDTEscreen,    bpIdxBigNum,
  3318. #endif
  3319. #ifdef useBigTTE
  3320.   mainScreenIdx,      mainScreenSize,   3,        idxDoBigTTEdisplay,   idxDoCursorUpdateBigTTEscreen,    bpIdxBigNum,
  3321. #endif
  3322. #ifdef useClock
  3323.   mainScreenIdx,      mainScreenSize,   1,        idxDoDisplaySystemTime,   idxDoCursorUpdateSystemTimeScreen,  bpIdxTime,
  3324. #endif
  3325.   settingScreenIdx,   1,      settingsSize,     idxDoSettingEditDisplay,  idxDoCursorUpdateSetting,   bpIdxSetting,
  3326.   paramScreenIdx,     1,      12,       idxDoParamEditDisplay,    idxDoNothing,       bpIdxParam,
  3327. #ifdef useClock
  3328.   systemTimeEditScreenIdx,  1,      4,        idxDoEditSystemTimeDisplay, idxDoNothing,       bpIdxClockEdit,
  3329. #endif
  3330. #ifdef useSavedTrips
  3331.   tripSaveScreenIdx,    1,      tripMenuSize,     idxDoTripSaveDisplay,   idxDoNothing,       bpIdxTripSave,
  3332.   tripShowScreenIdx,    1,      tripValueSize,      idxDoTripShowDisplay,   idxDoCursorUpdateTripShow,    bpIdxTripView,
  3333. #endif
  3334. #ifdef useScreenEditor
  3335.   screenEditIdx,      1,      displayFormatSize * 2,    idxDoScreenEditDisplay,   idxDoCursorUpdateScreenEdit,    bpIdxScreenEdit,
  3336. #endif
  3337. #ifdef useEEPROMviewer
  3338.   eepromViewIdx,      1,      eePtrEnd,     idxDoEEPROMviewDisplay,   idxDoNothing,       bpIdxEEPROMview,
  3339. #endif
  3340. };
  3341.  
  3342. uint8_t screenCursor[(unsigned int)(screenSize)] = {
  3343.   0,
  3344.   0,
  3345.   0,
  3346. #ifdef useCPUreading
  3347.   0,
  3348. #endif
  3349. #ifdef useBigFE
  3350.   0,
  3351. #endif
  3352. #ifdef useBigDTE
  3353.   0,
  3354. #endif
  3355. #ifdef useBigTTE
  3356.   0,
  3357. #endif
  3358. #ifdef useBarFuelEconVsTime
  3359.   0,
  3360. #endif
  3361. #ifdef useBarFuelEconVsSpeed
  3362.   0,
  3363. #endif
  3364. #ifdef useClock
  3365.   0,
  3366.   0,
  3367. #endif
  3368. #ifdef useSavedTrips
  3369.   0,
  3370.   0,
  3371. #endif
  3372. #ifdef useScreenEditor
  3373.   0,
  3374. #endif
  3375. #ifdef useEEPROMviewer
  3376.   0
  3377. #endif
  3378. };
  3379.  
  3380. #ifdef useCoastDownCalculator
  3381. long long matrix_x[3][3];
  3382. long long matrix_r[3][3];
  3383. long long matrix_y[3];
  3384. long long matrix_z[3];
  3385. #endif
  3386.  
  3387. #ifdef useBarFuelEconVsTime
  3388. const char barFEvTfuncNames[] PROGMEM = {
  3389.   "DiffFE / Time\0"
  3390.   "FE / Time\0"
  3391. };
  3392. #endif
  3393.  
  3394. #ifdef useBarFuelEconVsSpeed
  3395. const uint8_t barFEvSdisplayFuncs[] PROGMEM = {
  3396.   tFuelEcon,
  3397.   tFuelUsed,
  3398.   tMotionTime,
  3399.   tDistance,
  3400. };
  3401.  
  3402. const char barFEvSfuncNames[] PROGMEM = {
  3403.   "FE / Speed\0"
  3404.   "Fuel Used/Speed\0"
  3405.   "RunTime / Speed\0"
  3406.   "Distance / Speed\0"
  3407. };
  3408. #endif
  3409.  
  3410. #ifdef useBuffering
  3411. const uint8_t bufferSize = 32;
  3412. const uint8_t bufferIsFull =  0b10000000;
  3413. const uint8_t bufferIsEmpty =   0b01000000;
  3414.  
  3415. class Buffer // Buffer prototype
  3416. {
  3417.  
  3418. public:
  3419.   volatile uint8_t storage[(unsigned int)(bufferSize)];
  3420.   volatile uint8_t bufferStart;
  3421.   volatile uint8_t bufferEnd;
  3422.   volatile uint8_t bufferStatus;
  3423.  
  3424.   pFunc onEmpty;
  3425.   pFunc onNoLongerEmpty;
  3426.   pFunc onNoLongerFull;
  3427.   pFunc onFull;
  3428.  
  3429.   qFunc process;
  3430.  
  3431.   void init(void);
  3432.   void push(uint8_t value);
  3433.   void pull(void);
  3434.   uint8_t updatePointer(volatile uint8_t * pointer, uint8_t clearFlag, uint8_t setFlag);
  3435. };
  3436.  
  3437. #endif
  3438. class Trip // Trip prototype
  3439. {
  3440.  
  3441. public:
  3442.   unsigned long collectedData[rvLength];
  3443.  
  3444.   void reset(void); // reset Trip instance
  3445.   void transfer(Trip t);
  3446.   void update(Trip t); // update with results of another Trip instance
  3447.   void add64s(uint8_t calcIdx, unsigned long v);
  3448.   void add32(uint8_t calcIdx, unsigned long v);
  3449. #ifdef useWindowFilter
  3450.   void subtract(Trip t);
  3451.   void sub32(uint8_t calcIdx, unsigned long v);
  3452. #endif
  3453. #ifdef useSavedTrips
  3454.   uint8_t load(uint8_t tripSlotIdx);
  3455.   uint8_t save(uint8_t tripSlotIdx);
  3456. #endif
  3457.  
  3458. };
  3459.  
  3460. namespace LCD // LCD prototype
  3461. {
  3462.  
  3463.   void init(void);
  3464.   void gotoXY(uint8_t x, uint8_t y);
  3465.   void loadCGRAMcharacter(uint8_t chr, const char * chrData, uint8_t mode);
  3466.   void setBright(uint8_t idx);
  3467.   void writeData(uint8_t value);
  3468. #ifdef useLegacyLCD
  3469.   void setContrast(uint8_t idx);
  3470.   void writeCommand(uint8_t value);
  3471.   uint8_t writeNybble(uint8_t value, uint8_t flags);
  3472.   void outputNybble(uint8_t s);
  3473.   void startOutput(void);
  3474. #endif
  3475. };
  3476.  
  3477. #ifdef useLegacyLCD
  3478. volatile uint8_t lcdDelayCount;
  3479. #ifdef useLegacyLCDbuffered
  3480. Buffer lcdBuffer;
  3481. #endif
  3482. #endif
  3483.  
  3484. #ifdef useBufferedSerialPort
  3485. Buffer serialBuffer;
  3486. #endif
  3487.  
  3488. #ifdef useChryslerMAPCorrection
  3489. const uint8_t pressureSize = 5;
  3490. const uint8_t MAPpressureIdx = 0;
  3491. const uint8_t baroPressureIdx = 1;
  3492. const uint8_t fuelPressureIdx = 2;
  3493. const uint8_t injPressureIdx = 3;
  3494. const uint8_t injCorrectionIdx = 4;
  3495.  
  3496. unsigned long pressure[(unsigned int)(pressureSize)] = { 0, 0, 0, 0, 0 };
  3497. unsigned long analogFloor[2];
  3498. unsigned long analogSlope[2];
  3499. unsigned long analogOffset[2];
  3500. volatile unsigned int sampleCount = 0;
  3501. #endif
  3502.  
  3503. #ifdef useAnalogRead
  3504. const uint8_t ADCfilterBitSize = 4;
  3505. const uint8_t ADCfilterSize = (1 << ADCfilterBitSize);
  3506. const uint8_t ADCfilterMask = (0xFF >> (8 - ADCfilterBitSize));
  3507. const uint8_t ADCchannelCount = 2
  3508. #ifdef useAnalogButtons
  3509.   + 3
  3510. #endif
  3511. ;
  3512.  
  3513. volatile unsigned int analogValue[(unsigned int)(ADCchannelCount)];
  3514. volatile uint8_t analogChannelValue[(unsigned int)(ADCchannelCount)] = { // points to the next channel to be read
  3515. #ifdef TinkerkitLCDmodule
  3516.   (1 << REFS0)| (1 << MUX2)|      (1 << MUX0),  // analog channel 1
  3517.   (1 << REFS0)| (1 << MUX2)|  (1 << MUX1),      // analog channel 2
  3518.   (1 << REFS0)| (1 << MUX2)|  (1 << MUX1)|  (1 << MUX0),  // analog channel 3
  3519. #else
  3520.   (1 << REFS0)|         (1 << MUX0),  // analog channel 1
  3521.   (1 << REFS0)|     (1 << MUX1),      // analog channel 2
  3522. #ifdef useAnalogButtons
  3523.   (1 << REFS0)|     (1 << MUX1)|  (1 << MUX0),  // analog channel 3
  3524.   (1 << REFS0)| (1 << MUX2),          // analog channel 4
  3525.   (1 << REFS0)| (1 << MUX2)|      (1 << MUX0),  // analog channel 5
  3526. #endif
  3527. #endif
  3528. };
  3529. volatile uint8_t analogChannelIdx = 0;
  3530. #endif
  3531.  
  3532. volatile unsigned long sleepTicks;
  3533. volatile unsigned long timer2_overflow_count;
  3534. volatile unsigned long systemCycles[2] = { 0, 0 };
  3535. #ifdef useClock
  3536. volatile unsigned long clockCycles[2] = { 0, 0 };
  3537. #endif
  3538. volatile unsigned long injSettleCycles;
  3539. volatile unsigned long minGoodRPMcycles;
  3540. volatile unsigned long maxGoodInjCycles;
  3541.  
  3542. volatile unsigned int injResetCount;
  3543. volatile unsigned int vssResetCount;
  3544. volatile unsigned int buttonCount;
  3545. volatile unsigned int timerDelayCount;
  3546. volatile unsigned int injResetDelay;
  3547.  
  3548. volatile uint8_t vssPause;
  3549. volatile uint8_t buttonState;
  3550. volatile uint8_t VSSCount;
  3551. volatile uint8_t dirty = 0;
  3552. volatile uint8_t timerStatus = 0;
  3553. volatile uint8_t timerHeartBeat = 0;
  3554. volatile uint8_t timerCommand = 0;
  3555. volatile uint8_t holdDisplay = 0;
  3556.  
  3557. #ifdef ArduinoMega2560
  3558. volatile uint8_t lastPINKstate;
  3559. #else
  3560. #ifdef TinkerkitLCDmodule
  3561. volatile uint8_t lastPINBstate;
  3562. #else
  3563. volatile uint8_t lastPINCstate;
  3564. #endif
  3565. #endif
  3566.  
  3567. extern int __bss_end;
  3568. extern int *__brkval;
  3569.  
  3570. Trip tripArray[tripSlotCount]; // main objects we will be working with
  3571.  
  3572. #ifdef useBarFuelEconVsTime
  3573. unsigned long barFEvsTimeData[bgDataSize];
  3574. #endif
  3575.  
  3576. #ifdef useClock
  3577. unsigned long outputCycles[2];
  3578. #endif
  3579.  
  3580. unsigned long paramMaxValue;
  3581. unsigned long timerLoopStart;
  3582. unsigned long timerLoopLength;
  3583.  
  3584. #ifdef useBarFuelEconVsTime
  3585. unsigned int bFEvTperiod;
  3586. unsigned int bFEvTcount;
  3587.  
  3588. uint8_t bFEvTstartIDx;
  3589. uint8_t bFEvTsize;
  3590. #endif
  3591.  
  3592. #ifdef useSavedTrips
  3593. uint8_t tripShowSlot;
  3594. #endif
  3595.  
  3596. uint8_t menuLevel = 0;
  3597. uint8_t prevMenuLevel = 0;
  3598. uint8_t brightnessIdx = 1;
  3599. uint8_t metricFlag;
  3600. uint8_t paramLength = 0;
  3601. uint8_t paramPtr = 0;
  3602. uint8_t hPos;
  3603. uint8_t vPos;
  3604. uint8_t ignoreChar;
  3605. uint8_t printChar;
  3606. uint8_t cgramMode = 0;
  3607.  
  3608. #ifdef useAnalogButtons
  3609. volatile uint8_t thisAnalogKeyPressed = buttonsUp;
  3610. #endif
  3611.  
  3612. char mBuff1[17]; // used by format(), doFormat()
  3613. char mBuff2[17]; // used by editParm(), bar graph routines
  3614. char pBuff[12]; // used by editParm(), editClock()
  3615.  
  3616. // this ISR gets called every time timer 2 overflows.
  3617. // timer 2 prescaler is set at 64, and it's an 8 bit counter
  3618. // so this ISR gets called every 256 * 64 / (system clock) seconds (for 20 MHz clock, that is every 0.8192 ms)
  3619.  
  3620. #ifdef TinkerkitLCDmodule
  3621. ISR( TIMER0_OVF_vect ) // system timer interrupt handler
  3622. #else
  3623. ISR( TIMER2_OVF_vect ) // system timer interrupt handler
  3624. #endif
  3625. {
  3626.  
  3627.   static uint8_t lastKeyPressed = 0;
  3628.   static uint8_t thisKeyPressed;
  3629.   static unsigned long lastTime;
  3630.   static unsigned long timerSleep = 0;
  3631.   static unsigned long wp;
  3632.   static unsigned int timerLoopCount = 0;
  3633.  
  3634.   unsigned long thisTime;
  3635.   unsigned long cycleLength;
  3636.  
  3637.   timer2_overflow_count += 256; // update TOV count
  3638. #ifdef TinkerkitLCDmodule
  3639.   thisTime = timer2_overflow_count | TCNT0; // calculate current cycle count
  3640. #else
  3641.   thisTime = timer2_overflow_count | TCNT2; // calculate current cycle count
  3642. #endif
  3643.  
  3644.   if (dirty & dirtySysTick)
  3645.   {
  3646.  
  3647.     cycleLength = findCycleLength(lastTime, thisTime);
  3648.  
  3649.     systemCycles[0] += cycleLength;
  3650.     if (systemCycles[0] < cycleLength) systemCycles[1]++;
  3651.  
  3652. #ifdef useClock
  3653.     clockCycles[0] += cycleLength;
  3654.     if (clockCycles[0] < cycleLength) clockCycles[1]++;
  3655. #endif
  3656.  
  3657.   }
  3658.  
  3659.   if (injResetCount)
  3660.   {
  3661.  
  3662.     injResetCount--;
  3663.      // if timeout is complete, cancel any pending injector pulse read and signal that no injector pulse has been read in a while
  3664.     if (injResetCount == 0) dirty &= ~(dirtyGoodInj | dirtyInjOpenRead);
  3665.  
  3666.   }
  3667.  
  3668.   if (vssResetCount)
  3669.   {
  3670.  
  3671.     vssResetCount--;
  3672.     if (vssResetCount == 0) dirty &= ~dirtyGoodVSS;
  3673.  
  3674.   }
  3675.  
  3676.   if (VSSCount) // if there is a VSS debounce countdown in progress
  3677.   {
  3678.  
  3679.     VSSCount--; // bump down the VSS count
  3680.     if (VSSCount == 0) updateVSS(thisTime); // if count has reached zero,
  3681.  
  3682.   }
  3683.  
  3684.   if (buttonCount) // if there is a button press debounce countdown in progress
  3685.   {
  3686.  
  3687.     buttonCount--; // bump down the button press count by one
  3688.  
  3689.     if (buttonCount == 0) lastKeyPressed |= longButtonBit; // signal that a "long" keypress has been detected
  3690.  
  3691.     if (buttonCount == keyShortDelay) // if button debounce countdown reaches this point
  3692.     {
  3693.  
  3694.       // figure out what buttons are being pressed
  3695. #ifdef useLegacyButtons
  3696. #ifdef ArduinoMega2560
  3697.       thisKeyPressed = buttonsUp & lastPINKstate;
  3698. #else
  3699.       thisKeyPressed = buttonsUp & lastPINCstate;
  3700. #endif
  3701. #endif
  3702.  
  3703. #ifdef useAnalogButtons
  3704.       thisKeyPressed = thisAnalogKeyPressed;
  3705. #endif
  3706.  
  3707.       if (thisKeyPressed != buttonsUp) // if any buttons are pressed
  3708.       {
  3709.  
  3710.         lastKeyPressed = thisKeyPressed; // remember the button press status for later
  3711.         timerStatus |= tsButtonRead; // signal that a button has been read in
  3712.  
  3713.       }
  3714.       else buttonCount = 0; // reset button press debounce countdown to zero
  3715.  
  3716.     }
  3717.  
  3718.     if (buttonCount == 0) // if a button has been read, go pass it on to the main program
  3719.     {
  3720.  
  3721.       timerCommand |= tcWakeUpOnButton; // tell system timer to wake up the main program
  3722.  
  3723.       // if a valid button press was read in, and main program is not asleep
  3724.       if ((timerStatus & tsButtonRead) && !(timerStatus & tsFellAsleep))
  3725.       {
  3726.  
  3727.         // pass off the remembered button press status to the main program
  3728.         buttonState = lastKeyPressed;
  3729.         // signal main program that a key press was detected
  3730.         timerStatus &= ~(tsButtonsUp | tsButtonRead);
  3731.         if (buttonState != buttonsUp) timerStatus &= ~tsDisplayDelay;
  3732.  
  3733.       }
  3734.  
  3735.     }
  3736.  
  3737.   }
  3738.  
  3739. #ifdef useChryslerMAPCorrection
  3740.   if (sampleCount) sampleCount--;
  3741.   else readMAP();
  3742. #endif
  3743.  
  3744.   if (timerStatus & tsLoopExec) // if a loop execution is in progress
  3745.   {
  3746.  
  3747.     if (timerLoopCount) timerLoopCount--; // if the loop countdown is in progress, bump loop count up by one tick
  3748.     else
  3749.     {
  3750.  
  3751.       timerStatus &= ~tsLoopExec; // stop the loop timer and signal loop finished to main program
  3752.       if (timerStatus & tsButtonsUp) // if no keypress,
  3753.       {
  3754.  
  3755.         timerHeartBeat <<= 1; // cycle the heartbeat bit
  3756.         if (timerHeartBeat == 0) timerHeartBeat = 1;
  3757.  
  3758.       }
  3759.  
  3760.     }
  3761.  
  3762.   }
  3763.  
  3764.   if (timerSleep) timerSleep--;
  3765.   else if (timerStatus & tsAwake) timerCommand |= tcFallAsleep;
  3766.  
  3767.   if (timerCommand & tcDoDelay) // if main program has requested a delay
  3768.   {
  3769.  
  3770.     if (timerDelayCount) timerDelayCount--; // bump timer delay value down by one tick
  3771.     else timerCommand &= ~tcDoDelay; // signal to main program that delay timer has completed main program request
  3772.  
  3773.   }
  3774.  
  3775.   if (timerCommand & tcDisplayDelay) // if main program has requested to delay status line (top line)
  3776.   {
  3777.  
  3778.     timerCommand &= ~tcDisplayDelay; // signal to main program that status line delay request is acknowledged
  3779.     timerStatus |= tsDisplayDelay; // signal that status line delay request is active
  3780.     holdDisplay = holdDelay; // start hold delay countdown
  3781.  
  3782.   }
  3783.  
  3784.   if (timerCommand & tcStartLoop) // if main program has requested to start cycle
  3785.   {
  3786.  
  3787.     timerCommand &= ~tcStartLoop; // signal to main program that loop timer has acknowledged main program request
  3788.     timerStatus |= (tsLoopExec | tsMarkLoop); // signal to main program that loop timer is in progress
  3789.     timerLoopCount = loopTickLength; // initialize loop count
  3790.     if (timerStatus & tsDisplayDelay)
  3791.     {
  3792.  
  3793.       if (holdDisplay) holdDisplay--;
  3794.       else timerStatus &= ~tsDisplayDelay;
  3795.  
  3796.     }
  3797.  
  3798.   }
  3799.  
  3800.   if (timerCommand & tcWakeUp)
  3801.   {
  3802.  
  3803.     if (timerCommand & tcWakeUpOnEngine) timerStatus |= tsAwakeOnEngine; // set awake status on engine running
  3804.     if (timerCommand & tcWakeUpOnButton) timerStatus |= tsAwakeOnButton; // set awake status on button pressed
  3805.  
  3806.     // clear wakeup command and any pending sleep command
  3807.     timerCommand &= ~(tcWakeUp | tcFallAsleep);
  3808.     timerSleep = sleepTicks; // reset sleep counter
  3809.  
  3810.   }
  3811.  
  3812.   if (timerCommand & tcFallAsleep)
  3813.   {
  3814.  
  3815.     timerCommand &= ~tcFallAsleep; // clear sleep command
  3816.     timerStatus &= ~tsAwake; // clear awake status
  3817.  
  3818.   }
  3819.  
  3820.   dirty |= dirtySysTick;
  3821.  
  3822.   lastTime = thisTime; // save cycle count
  3823.  
  3824. }
  3825.  
  3826. volatile unsigned long lastInjOpenStart;
  3827. volatile unsigned long thisInjOpenStart;
  3828. volatile unsigned long totalInjCycleLength;
  3829. volatile unsigned long maximumInjOpenCycleLength;
  3830.  
  3831. #ifdef ArduinoMega2560
  3832. ISR( INT4_vect ) // injector opening event handler
  3833. #else
  3834. ISR( INT0_vect ) // injector opening event handler
  3835. #endif
  3836. {
  3837.  
  3838.   lastInjOpenStart = thisInjOpenStart;
  3839.   thisInjOpenStart = cycles2();
  3840.  
  3841.   if (dirty & dirtyGoodInj)
  3842.   {
  3843.  
  3844.     // calculate fuel injector length between pulse starts
  3845.     totalInjCycleLength = findCycleLength(lastInjOpenStart, thisInjOpenStart);
  3846.  
  3847.     if (totalInjCycleLength < minGoodRPMcycles)
  3848.     {
  3849.  
  3850.       maximumInjOpenCycleLength = 819 * totalInjCycleLength; // to determine instantaneous maximum injector on-time
  3851.       maximumInjOpenCycleLength >>= 10; // and multiply it by 0.8 (or something reasonably close) for injector duty cycle
  3852.       timerCommand |= tcWakeUpOnEngine; // tell timer to wake up main program
  3853.  
  3854.     }
  3855.     else
  3856.     {
  3857.  
  3858.       totalInjCycleLength = 0;
  3859.       dirty &= ~dirtyGoodInj; // signal that no injector pulse has been read for a while
  3860.  
  3861.     }
  3862.  
  3863.   }
  3864.  
  3865.   if (!(dirty & dirtyGoodInj)) maximumInjOpenCycleLength = maxGoodInjCycles; // seed working maxGoodInjCycles with default value
  3866.  
  3867.   dirty |= dirtyInjOpenRead; // signal that injector pulse read is in progress
  3868.   injResetCount = injResetDelay; // reset injector validity monitor
  3869.  
  3870. }
  3871.  
  3872. #ifdef ArduinoMega2560
  3873. ISR( INT5_vect ) // injector closing event handler
  3874. #else
  3875. ISR( INT1_vect ) // injector closing event handler
  3876. #endif
  3877. {
  3878.  
  3879.   unsigned long thisTime = cycles2();
  3880.   unsigned long injOpenCycleLength = 0;
  3881.   uint8_t i = rawIdx;
  3882. #ifdef trackIdleEOCdata
  3883.   uint8_t x = 1;
  3884.  
  3885.   if (!(dirty & dirtyGoodVSS)) x++; // if no valid VSS pulse has been read, then vehicle is idling
  3886. #endif
  3887.  
  3888.   if (dirty & dirtyInjOpenRead)
  3889.   {
  3890.  
  3891.     // calculate fuel injector pulse length
  3892.     injOpenCycleLength = findCycleLength(thisInjOpenStart, thisTime) - injSettleCycles;
  3893.  
  3894.     if (injOpenCycleLength < maximumInjOpenCycleLength) // perform rationality test on injector open cycle pulse length
  3895.     {
  3896.  
  3897. #ifdef useChryslerMAPCorrection
  3898.       readMAP(); // calculate correction factor for differential pressure across the fuel injector
  3899.       injOpenCycleLength *= pressure[(unsigned int)(injCorrectionIdx)]; // multiply by correction factor
  3900.       injOpenCycleLength >>= 12; // divide by denominator factor
  3901. #endif
  3902.  
  3903.       dirty |= dirtyGoodInj; // signal that a valid fuel injector pulse has just been read
  3904.       timerCommand |= tcWakeUpOnEngine; // tell timer to wake up main program
  3905.  
  3906.     }
  3907.     else
  3908.     {
  3909.  
  3910.       injOpenCycleLength = 0;
  3911.       dirty &= ~dirtyGoodInj; // signal that no injector pulse has been read
  3912.       injResetCount = 0; // stop injector validity monitor
  3913.  
  3914.     }
  3915.  
  3916.     dirty &= ~dirtyInjOpenRead; // signal that the injector pulse has been read
  3917.  
  3918.   }
  3919.  
  3920. #ifdef trackIdleEOCdata
  3921.   for (uint8_t y = 0; y < x; y++)
  3922.   {
  3923. #endif
  3924.  
  3925.     if (injOpenCycleLength)
  3926.     {
  3927.  
  3928.       tripArray[(unsigned int)(i)].collectedData[(unsigned int)(rvInjPulseIdx)]++; // update the injector pulse count
  3929.       tripArray[(unsigned int)(i)].add64s(rvInjOpenCycleIdx, injOpenCycleLength); // add to fuel injector open cycle accumulator
  3930.  
  3931.     }
  3932.  
  3933.     tripArray[(unsigned int)(i)].add64s(rvInjCycleIdx, totalInjCycleLength); // add to fuel injector total cycle accumulator
  3934.  
  3935. #ifdef trackIdleEOCdata
  3936.     i ^= (rawIdx ^ rawIdleIdx);
  3937.  
  3938.   }
  3939. #endif
  3940.  
  3941.   totalInjCycleLength = 0;
  3942.  
  3943. }
  3944.  
  3945. #ifdef ArduinoMega2560
  3946. ISR( PCINT2_vect )
  3947. #else
  3948. #ifdef TinkerkitLCDmodule
  3949. ISR( PCINT0_vect )
  3950. #else
  3951. ISR( PCINT1_vect )
  3952. #endif
  3953. #endif
  3954. {
  3955.  
  3956.   unsigned long cycleLength;
  3957.  
  3958. #ifdef TinkerkitLCDmodule
  3959.   cycleLength = timer2_overflow_count + TCNT0; // read current TCNT0
  3960.   if (TIFR0 & (1 << TOV0)) cycleLength = timer2_overflow_count + 256 + TCNT0; // if overflow occurred, re-read TCNT0 and adjust for overflow
  3961. #else
  3962.   cycleLength = timer2_overflow_count + TCNT2; // read current TCNT2
  3963.   if (TIFR2 & (1 << TOV2)) cycleLength = timer2_overflow_count + 256 + TCNT2; // if overflow occurred, re-read TCNT2 and adjust for overflow
  3964. #endif
  3965.  
  3966.   static uint8_t p;
  3967.   static uint8_t q;
  3968.  
  3969. #ifdef ArduinoMega2560
  3970.   p = PINK; // read current pin K state
  3971.   q = p ^ lastPINKstate; // detect any changes from the last time this ISR is called
  3972. #else
  3973. #ifdef TinkerkitLCDmodule
  3974.   p = PINB; // read current pin B state
  3975.   q = p ^ lastPINBstate; // detect any changes from the last time this ISR is called
  3976. #else
  3977.   p = PINC; // read current pin C state
  3978.   q = p ^ lastPINCstate; // detect any changes from the last time this ISR is called
  3979. #endif
  3980. #endif
  3981.  
  3982.   if (q & vssBit) // if a VSS pulse is received
  3983.   {
  3984.  
  3985.     if (vssPause == 0) updateVSS(cycleLength); // if there is no VSS pulse delay defined
  3986.     else VSSCount = vssPause; // otherwise, set VSS debounce count and let system timer handle the debouncing
  3987.  
  3988.   }
  3989.  
  3990. #ifdef useLegacyButtons
  3991.   if (q & buttonsUp) buttonCount = keyDelay; // set keypress debounce count, and let system timer handle the debouncing
  3992. #endif
  3993.  
  3994. #ifdef ArduinoMega2560
  3995.   lastPINKstate = p; // remember the current pin K state for the next time this ISR gets called
  3996. #else
  3997. #ifdef TinkerkitLCDmodule
  3998.   lastPINBstate = p; // remember the current pin B state for the next time this ISR gets called
  3999. #else
  4000.   lastPINCstate = p; // remember the current pin C state for the next time this ISR gets called
  4001. #endif
  4002. #endif
  4003.  
  4004. }
  4005.  
  4006. #ifdef useParallax5PositionSwitch
  4007. const unsigned int analogButtonThreshold[] PROGMEM = {
  4008.   0,
  4009.   559,
  4010.   580,
  4011.   586,
  4012.   618,
  4013.   651,
  4014.   664,
  4015.   693,
  4016.   717,
  4017.   728,
  4018.   748,
  4019.   766,
  4020.   786,
  4021.   814,
  4022.   834,
  4023.   858,
  4024.   897,
  4025.   927,
  4026.   980,
  4027. };
  4028.  
  4029. const uint8_t analogButtonCount = (sizeof(analogButtonThreshold) / sizeof(unsigned int));
  4030.  
  4031. const uint8_t analogTranslate[(unsigned int)(analogButtonCount)] PROGMEM = {
  4032.   buttonsUp,
  4033.   btnShortPress1CL,
  4034.   btnShortPress2CL,
  4035.   btnShortPressCL,
  4036.   btnShortPress1L,
  4037.   btnShortPress2L,
  4038.   btnShortPressL,
  4039.   btnShortPress1RC,
  4040.   btnShortPress2RC,
  4041.   btnShortPressRC,
  4042.   btnShortPress1C,
  4043.   btnShortPress2C,
  4044.   btnShortPressC,
  4045.   btnShortPress1R,
  4046.   btnShortPress2R,
  4047.   btnShortPressR,
  4048.   btnShortPress1,
  4049.   btnShortPress2,
  4050.   buttonsUp,
  4051. };
  4052. #endif
  4053.  
  4054. #ifdef useAnalogMuxButtons
  4055. const unsigned int analogButtonThreshold[] PROGMEM = {
  4056.   0,    // 00
  4057.   556,  // 01
  4058.   560,  // 02
  4059.   567,  // 03
  4060.   574,  // 04
  4061.   583,  // 05
  4062.   593,  // 06
  4063.   601,  // 07
  4064.   609,  // 08
  4065.   621,  // 09
  4066.   634,  // 0A
  4067.   644,  // 0B
  4068.   653,  // 0C
  4069.   665,  // 0D
  4070.   677,  // 0E
  4071.   687,  // 0F
  4072.   698,  // 10
  4073.   722,  // 11
  4074.   747,  // 12
  4075.   759,  // 13
  4076.   772,  // 14
  4077.   789,  // 15
  4078.   806,  // 16
  4079.   820,  // 17
  4080.   835,  // 18
  4081.   859,  // 19
  4082.   884,  // 1A
  4083.   902,  // 1B
  4084.   921,  // 1C
  4085.   944,  // 1D
  4086.   968,  // 1E
  4087.   989,  // 1F
  4088.   1012, // 20
  4089. };
  4090.  
  4091. const uint8_t analogButtonCount = (sizeof(analogButtonThreshold) / sizeof(unsigned int));
  4092.  
  4093. const uint8_t analogTranslate[(unsigned int)(analogButtonCount)] PROGMEM = {
  4094.   buttonsUp,
  4095.   btnShortPress21RCL,
  4096.   btnShortPress1RCL,
  4097.   btnShortPress2RCL,
  4098.   btnShortPressRCL,
  4099.   btnShortPress21CL,
  4100.   btnShortPress1CL,
  4101.   btnShortPress2CL,
  4102.   btnShortPressCL,
  4103.   btnShortPress21RL,
  4104.   btnShortPress1RL,
  4105.   btnShortPress2RL,
  4106.   btnShortPressRL,
  4107.   btnShortPress21L,
  4108.   btnShortPress1L,
  4109.   btnShortPress2L,
  4110.   btnShortPressL,
  4111.   btnShortPress21RC,
  4112.   btnShortPress1RC,
  4113.   btnShortPress2RC,
  4114.   btnShortPressRC,
  4115.   btnShortPress21C,
  4116.   btnShortPress1C,
  4117.   btnShortPress2C,
  4118.   btnShortPressC,
  4119.   btnShortPress21R,
  4120.   btnShortPress1R,
  4121.   btnShortPress2R,
  4122.   btnShortPressR,
  4123.   btnShortPress21,
  4124.   btnShortPress1,
  4125.   btnShortPress2,
  4126.   buttonsUp,
  4127. };
  4128. #endif
  4129.  
  4130. #ifdef useAnalogInterrupt
  4131. ISR( ADC_vect )
  4132. {
  4133.  
  4134. #ifdef useAnalogButtons
  4135.   static uint8_t lastAnalogKeyPressed = buttonsUp;
  4136. #endif
  4137. #ifdef useAnalogRead
  4138.   static unsigned int rawRead;
  4139.   union union_16 * rawValue = (union union_16 *) &rawRead;
  4140.   static uint8_t ADCstate = 1;
  4141.  
  4142.   rawValue->u8[0] = ADCL; // (locks ADC sample result register from AtMega hardware)
  4143.   rawValue->u8[1] = ADCH; // (releases ADC sample result register to AtMega hardware)
  4144.  
  4145.   if (ADCstate)
  4146.   {
  4147.  
  4148.     ADCstate--;
  4149.     ADMUX = analogChannelValue[(unsigned int)(analogChannelIdx)]; // select next analog channel to read (this has to be done quickly!)
  4150.  
  4151.   }
  4152.   else
  4153.   {
  4154.  
  4155. #ifdef TinkerkitLCDmodule
  4156.     ADMUX = (1 << REFS0) | (1 << MUX4) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // ground ADC sample/hold capacitor to reset it
  4157. #else
  4158.     ADMUX = (1 << REFS0) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // ground ADC sample/hold capacitor to reset it
  4159. #endif
  4160.  
  4161.     analogValue[(unsigned int)(analogChannelIdx)] = rawRead;
  4162.  
  4163.     analogChannelIdx++;
  4164.     if (analogChannelIdx == ADCchannelCount) analogChannelIdx = 0;
  4165.  
  4166.     ADCstate = 3;
  4167.  
  4168. #ifdef useAnalogButtons
  4169.     if (analogChannelIdx == 2)
  4170.     {
  4171.  
  4172.       for (uint8_t x = analogButtonCount - 1; x < analogButtonCount; x--)
  4173.       {
  4174.  
  4175.         if (analogValue[(unsigned int)(analogChannelIdx)] >= pgm_read_word(&analogButtonThreshold[(unsigned int)(x)]))
  4176.         {
  4177.  
  4178.           thisAnalogKeyPressed = pgm_read_byte(&analogTranslate[(unsigned int)(x)]);
  4179.           break;
  4180.  
  4181.         }
  4182.  
  4183.       }
  4184.  
  4185.       if (thisAnalogKeyPressed != lastAnalogKeyPressed) buttonCount = keyDelay;
  4186.  
  4187.       lastAnalogKeyPressed = thisAnalogKeyPressed;
  4188.  
  4189.     }
  4190. #endif
  4191.  
  4192.   }
  4193.  
  4194. #endif
  4195.  
  4196. #ifdef useLegacyLCD
  4197.   if (timerCommand & tcLCDdelay) // if main program has requested a delay
  4198.   {
  4199.  
  4200.     if (lcdDelayCount == 0)
  4201.     {
  4202.  
  4203. #ifdef useLegacyLCDbuffered
  4204.       lcdBuffer.pull(); // pull a buffered LCD byte and output it
  4205. #else
  4206.       timerCommand &= ~tcLCDdelay; // signal to main program that delay timer has completed main program request
  4207. #endif
  4208.  
  4209.     }
  4210.     else lcdDelayCount--; // bump timer delay value down by one tick
  4211.  
  4212.   }
  4213. #endif
  4214.  
  4215. }
  4216. #endif
  4217.  
  4218. #ifdef useBufferedSerialPort
  4219. #ifdef ArduinoMega2560
  4220. ISR( USART0_UDRE_vect )
  4221. #else
  4222. ISR( USART_UDRE_vect )
  4223. #endif
  4224. {
  4225.  
  4226.   serialBuffer.pull(); // send a buffered character to the serial hardware
  4227.  
  4228. }
  4229. #endif
  4230.  
  4231. #ifdef useChryslerMAPCorrection
  4232. void readMAP(void)
  4233. {
  4234.  
  4235.   static unsigned int sample[2] = { 0, 0 };
  4236.   unsigned long wp;
  4237.   uint8_t analogToggle = 1;
  4238.  
  4239.   sampleCount = sampleTickLength - 1; // reset sample timer counter
  4240.  
  4241.   for (uint8_t x = 0; x < 2; x++)
  4242.   {
  4243.  
  4244.     // perform 2nd stage IIR filter operation
  4245.     sample[(unsigned int)(x)] = sample[(unsigned int)(x)] + 7 * analogValue[(unsigned int)(analogToggle)]; // first order IIR filter - filt = filt + 7/8 * (reading - filt)
  4246.     sample[(unsigned int)(x)] >>= 3;
  4247.  
  4248.     // calculate MAP and barometric pressures from readings
  4249.     wp = (unsigned long)sample[(unsigned int)(x)];
  4250.     if (wp < analogFloor[(unsigned int)(x)]) wp = 0;
  4251.     else wp -= analogFloor[(unsigned int)(x)];
  4252.     wp *= analogSlope[(unsigned int)(x)];
  4253.     wp >>= 10;
  4254.     pressure[(unsigned int)(MAPpressureIdx + x)] = wp + analogOffset[(unsigned int)(x)];
  4255.  
  4256.     analogToggle ^= 1;
  4257.  
  4258.   }
  4259.  
  4260.   // calculate differential pressure seen across the fuel injector
  4261.   wp = pressure[(unsigned int)(fuelPressureIdx)] + pressure[(unsigned int)baroPressureIdx] - pressure[(unsigned int)MAPpressureIdx];
  4262.   pressure[(unsigned int)(injPressureIdx)] = wp;
  4263.  
  4264.   // to get fuel pressure ratio, multiply differential pressure by denominator factor (1 << 12), then divide by fuel system pressure
  4265.   wp <<= 12;
  4266.   wp /= pressure[(unsigned int)(fuelPressureIdx)];
  4267.  
  4268.   // calculate square root of fuel pressure ratio
  4269.   pressure[(unsigned int)(injCorrectionIdx)] = (unsigned long)iSqrt((unsigned int)wp);
  4270.  
  4271. }
  4272. #endif
  4273.  
  4274. #ifdef useIsqrt
  4275. unsigned int iSqrt(unsigned int n)
  4276. {
  4277.  
  4278.   unsigned long w = 4096; // square factor guess
  4279.   unsigned int t = 4096; // proposed square root
  4280.   int d; // difference between guess and proposed
  4281.   int od = 0;
  4282.  
  4283.   for (uint8_t x = 0; x < 5; x++)
  4284.   {
  4285.  
  4286.     od = d;
  4287.     d = n - (unsigned int)w;
  4288.     d >>= 1;
  4289.     t += d;
  4290.  
  4291.     od += d;
  4292.  
  4293.     if ((d == 0) || (od == 0)) break;
  4294.  
  4295.     w = (unsigned long)t * (unsigned long)t;
  4296.     w >>= 12;
  4297.  
  4298.   }
  4299.  
  4300.   return t;
  4301.  
  4302. }
  4303. #endif
  4304.  
  4305. unsigned long lastVSScycle;
  4306.  
  4307. void updateVSS(unsigned long cycle)
  4308. {
  4309.  
  4310.   unsigned long cycleLength;
  4311.  
  4312.   uint8_t x = 1;
  4313.   uint8_t i = rawIdx;
  4314.  
  4315.   if (dirty & dirtyGoodVSS)
  4316.   {
  4317.  
  4318.     cycleLength = findCycleLength(lastVSScycle, cycle);
  4319.  
  4320. #ifdef trackIdleEOCdata
  4321.     if (!(dirty & dirtyGoodInj)) x++; // if no valid fuel injector event has been read, vehicle is in EOC mode
  4322. #endif
  4323.  
  4324.     for (uint8_t y = 0; y < x; y++)
  4325.     {
  4326.  
  4327.       tripArray[(unsigned int)(i)].collectedData[(unsigned int)(rvVSSpulseIdx)]++; // update the VSS pulse count
  4328.  
  4329.       tripArray[(unsigned int)(i)].add64s(rvVSScycleIdx, cycleLength); // add to VSS cycle accumulator
  4330.  
  4331. #ifdef trackIdleEOCdata
  4332.       i ^= (rawIdx ^ rawIdleIdx);
  4333. #endif
  4334.  
  4335.     }
  4336.  
  4337.     timerCommand |= tcWakeUpOnEngine; // tell system timer to wake up the main program
  4338.  
  4339.   }
  4340.  
  4341.   vssResetCount = vssResetDelay;
  4342.   dirty |= dirtyGoodVSS; // annotate that a valid VSS pulse has been read
  4343.  
  4344.   lastVSScycle = cycle;
  4345.  
  4346. }
  4347.  
  4348. void initStatusLine(void)
  4349. {
  4350.  
  4351.   gotoXY(0, 0);
  4352.   clrEOL();
  4353. #ifdef blankScreenOnMessage
  4354.   gotoXY(0, 1);
  4355.   clrEOL();
  4356. #endif
  4357.   gotoXY(0, 0);
  4358.  
  4359. }
  4360.  
  4361. void execStatusLine(void)
  4362. {
  4363.  
  4364.   clrEOL();
  4365.   timerCommand |= tcDisplayDelay;
  4366.   while (timerCommand & tcDisplayDelay);
  4367.  
  4368. }
  4369.  
  4370. void clrEOL(void)
  4371. {
  4372.  
  4373.   while (hPos < 16) charOut(' ');
  4374.  
  4375. }
  4376.  
  4377. void gotoXY(uint8_t x, uint8_t y) // x = 0..16, y = 0..1
  4378. {
  4379.  
  4380.   LCD::gotoXY(x, y);
  4381.  
  4382.   hPos = x;
  4383.   vPos = y;
  4384.  
  4385. }
  4386.  
  4387. void blinkFlash(const char * str, uint8_t condition)
  4388. {
  4389.  
  4390.   uint8_t chr;
  4391.   uint8_t f = ((condition) && (timerHeartBeat & 0b01010101));
  4392.  
  4393.   hPos &= 0x7F;
  4394.   while (0 != (chr = pgm_read_byte(str++)))
  4395.   {
  4396.  
  4397.     if (f) charOut(' ');
  4398.     else charOut(chr);
  4399.  
  4400.   }
  4401.  
  4402. }
  4403.  
  4404. const char * findStr(const char * str, uint8_t strIdx)
  4405. {
  4406.  
  4407.   while (strIdx)
  4408.   {
  4409.  
  4410.     while (pgm_read_byte(str++));
  4411.     strIdx--;
  4412.  
  4413.   }
  4414.  
  4415.   return str;
  4416.  
  4417. }
  4418.  
  4419. void printStr(const char * str, uint8_t strIdx)
  4420. {
  4421.  
  4422.   printFlash(findStr(str, strIdx));
  4423.  
  4424. }
  4425.  
  4426. void printFlash(const char * str)
  4427. {
  4428.  
  4429.   uint8_t chr;
  4430.  
  4431.   hPos &= 0x7F;
  4432.   while (0 != (chr = pgm_read_byte(str++))) charOut(chr);
  4433.  
  4434. }
  4435.  
  4436. void print(char * str)
  4437. {
  4438.  
  4439.   hPos &= 0x7F;
  4440.   while (*str) charOut(*str++);
  4441.  
  4442. }
  4443.  
  4444. void charOut(uint8_t chr)
  4445. {
  4446.  
  4447.   if (chr == ignoreChar) hPos |= 0x80;
  4448.   else if ((chr == printChar) || (chr == '}')) hPos &= 0x7F;
  4449.   else if (hPos < 0x80)
  4450.   {
  4451.  
  4452. #ifdef blankScreenOnMessage
  4453.     if (!(timerStatus & tsDisplayDelay))
  4454. #else
  4455.     if ((!(timerStatus & tsDisplayDelay)) || (vPos > 0))
  4456. #endif
  4457.     {
  4458.  
  4459.       if ((chr > 0x07) && (chr < 0x10)) chr &= 0x07;
  4460.       LCD::writeData(chr);
  4461.  
  4462.     }
  4463.  
  4464.     hPos++;
  4465.  
  4466.   }
  4467.  
  4468. }
  4469.  
  4470. void loadCGRAM(const char * c)
  4471. {
  4472.  
  4473.   uint8_t s = pgm_read_byte(c++);
  4474.  
  4475.   if (cgramMode != s)
  4476.   {
  4477.  
  4478.     cgramMode = s;
  4479.     s = pgm_read_byte(c++);
  4480.  
  4481.     for (uint8_t x = 0; x < s; x++)
  4482.     {
  4483.  
  4484.       LCD::loadCGRAMcharacter(x, c, 1); //write the character data to the character generator ram
  4485.       c += 8;
  4486.  
  4487.     }
  4488.  
  4489.   }
  4490.  
  4491. }
  4492.  
  4493. #ifdef useBigTimeDisplay // Big time output section
  4494. void displayBigTime(char * val, uint8_t b)
  4495. {
  4496.  
  4497.   val[4] = val[0];
  4498.   val[5] = val[1];
  4499.   val[7] = val[2];
  4500.   val[8] = val[3];
  4501.   val[9] = 0;
  4502.   val[6] = ':';
  4503.  
  4504.   if (timerHeartBeat & 0b01010101) // if it's time to blink something
  4505.   {
  4506.  
  4507.     if (b == 4) val[6] = ';'; // if hh:mm separator is selected, blink it
  4508.     else if (b < 2) val[(unsigned int)(b + 4)] = ' '; // if digit 0 or 1 is selected, blink it
  4509.     else if (b < 4) val[(unsigned int)(b + 5)] = ' '; // otherwise, if digit 2 or 3 is selected, blink it
  4510.  
  4511.   }
  4512.  
  4513.   displayBigNumber(&val[4]);
  4514.  
  4515. }
  4516.  
  4517. #endif
  4518. #ifdef useBigNumberDisplay // Big number output section
  4519. void displayBigNumber(char * str)
  4520. {
  4521.  
  4522.   uint8_t c;
  4523.   uint8_t d;
  4524.   uint8_t e;
  4525.   uint8_t x = hPos;
  4526.  
  4527.   while (*str)
  4528.   {
  4529.  
  4530.     c = *str++;
  4531.     d = *str;
  4532.     e = ' ';
  4533.  
  4534.     if ((d == '.') || (d == ':') || (d == ';'))
  4535.     {
  4536.  
  4537.       if (d == ':') e = decimalPtChar;
  4538.       if (d == ';') d = ' ';
  4539.       else d = decimalPtChar;
  4540.       str++;
  4541.  
  4542.       }
  4543.       else d = ' ';
  4544.  
  4545.     c -= '0';
  4546.  
  4547.     if (c == 240) c = 10;
  4548.     else if (c > 9) c = 11;
  4549.  
  4550.     loadCGRAM(bigNumFont);
  4551.  
  4552.     gotoXY(x, 0);
  4553.     printStr(bigNumChars1, c);
  4554.     charOut(e);
  4555.     gotoXY(x, 1);
  4556.     printStr(bigNumChars2, c);
  4557.     charOut(d);
  4558.     x += 4;
  4559.  
  4560.   }
  4561.  
  4562.   gotoXY(x, 0);
  4563.  
  4564. }
  4565.  
  4566. const uint8_t fedSelectList[] PROGMEM = {
  4567.   instantIdx,
  4568.   currentIdx,
  4569.   tankIdx,
  4570. };
  4571.  
  4572. void displayBigStatus(uint8_t dIdx, const char * str)
  4573. {
  4574.  
  4575.   initStatusLine();
  4576.   printStr(bigFEDispChars, fedSelect(dIdx));
  4577.   printFlash(str); // briefly display screen name
  4578.   execStatusLine();
  4579.  
  4580. }
  4581.  
  4582. uint8_t fedSelect(uint8_t dIdx)
  4583. {
  4584.  
  4585.   return pgm_read_byte(&fedSelectList[(unsigned int)(screenCursor[(unsigned int)(dIdx)])]);
  4586.  
  4587. }
  4588.  
  4589. #endif
  4590. #ifdef useBarGraph // Bar Graph Output support section
  4591.  
  4592. uint8_t bgPlotArea[16];
  4593. unsigned long barGraphData[(unsigned int)(bgDataSize)];
  4594.  
  4595. const uint8_t bgLabels[] PROGMEM = {
  4596.   'Q',  // fuel used
  4597.   'R',  // fuel rate
  4598.   'T',  // engine run time
  4599.   'T',  // time to empty
  4600.   'D',  // distance travelled
  4601.   'S',  // average speed
  4602.   'T',  // time in motion
  4603.   'E',  // fuel economy
  4604.   'Q',  // remaining fuel
  4605.   'D',  // remaining distance
  4606.   't',  // engine speed
  4607.   'u',  // fuel used, in microseconds
  4608.   'u',  // engine run time, in microseconds
  4609.   'u',  // time in motion, in microseconds
  4610.   'p',  // injector pulses
  4611.   'p',  // VSS pulses
  4612. #ifdef useFuelCost
  4613.   'C',  // fuel cost
  4614.   'C',  // fuel rate cost
  4615.   'C',  // fuel cost per distance
  4616.   'D',  // distance per fuel cost
  4617.   'C',  // remaining fuel cost
  4618. #endif
  4619. #ifdef useAnalogRead
  4620. #ifdef TinkerkitLCDmodule
  4621.   'V',  // voltage
  4622.   'V',  // voltage
  4623.   'V',  // voltage
  4624. #else
  4625.   'V',  // voltage
  4626.   'V',  // voltage
  4627. #ifdef useAnalogButtons
  4628.   'V',  // voltage
  4629.   'V',  // voltage
  4630.   'V',  // voltage
  4631. #endif
  4632. #endif
  4633. #endif
  4634. #ifdef useChryslerMAPCorrection
  4635.   'P',  // pressure
  4636.   'P',  // pressure
  4637.   'P',  // pressure
  4638.   'P',  // pressure
  4639.   'F',  // correction factor
  4640. #endif
  4641. };
  4642.  
  4643. const uint8_t tripIDchars[tripSlotCount] PROGMEM = {
  4644.   'r',
  4645.   'i',
  4646.   'c',
  4647.   't',
  4648. #ifdef trackIdleEOCdata
  4649.   'R',
  4650.   'I',
  4651.   'C',
  4652.   'T',
  4653. #endif
  4654. #ifdef useBarFuelEconVsTime
  4655.   'p',
  4656. #endif
  4657. #ifdef useBarFuelEconVsSpeed
  4658.   '0',
  4659.   '1',
  4660.   '2',
  4661.   '3',
  4662.   '4',
  4663.   '5',
  4664.   '6',
  4665.   '7',
  4666.   '8',
  4667.   '9',
  4668.   'A',
  4669.   'B',
  4670.   'C',  // *facepalm*
  4671.   'D',
  4672.   'E',
  4673. #endif
  4674. #ifdef useCoastDownCalculator
  4675.   'T',
  4676.   'L',
  4677. #endif
  4678. };
  4679.  
  4680. void clearBGplot(uint8_t yIdx)
  4681. {
  4682.  
  4683.   for (uint8_t x = 0; x < 16; x++) bgPlotArea[(unsigned int)(x)] = 0;
  4684.   if (yIdx < 16) bgPlotArea[(unsigned int)(15 - yIdx)] = 31;
  4685.  
  4686. }
  4687.  
  4688. uint8_t bgPlotConvert(uint8_t coord)
  4689. {
  4690.  
  4691.   if (coord == 254) coord = 15;
  4692.   else if (coord > 15) coord = 0;
  4693.   else coord = 15 - coord;
  4694.  
  4695.   return coord;
  4696.  
  4697. }
  4698.  
  4699. void bgPlot(uint8_t idx, uint8_t lowerPoint, uint8_t upperPoint, uint8_t mode)
  4700. {
  4701.  
  4702.   uint8_t i = idx + 3;
  4703.   uint8_t k = i % 5;
  4704.  
  4705.   lowerPoint = bgPlotConvert(lowerPoint);
  4706.   upperPoint = bgPlotConvert(upperPoint);
  4707.  
  4708.   if (lowerPoint < upperPoint)
  4709.   {
  4710.  
  4711.     lowerPoint ^= upperPoint;
  4712.     upperPoint ^= lowerPoint;
  4713.     lowerPoint ^= upperPoint;
  4714.  
  4715.   }
  4716.  
  4717.   uint8_t bitMask = (1 << (4 - k));
  4718.  
  4719.   while ((lowerPoint >= upperPoint) && (lowerPoint < 16))
  4720.   {
  4721.  
  4722.     if ((mode) && (timerHeartBeat & 0b01010101)) bgPlotArea[(unsigned int)(lowerPoint)] ^= bitMask;
  4723.     else bgPlotArea[(unsigned int)(lowerPoint)] |= bitMask;
  4724.     lowerPoint--;
  4725.  
  4726.   }
  4727.  
  4728. }
  4729.  
  4730. void bgOutputPlot(uint8_t idx, uint8_t yIdx)
  4731. {
  4732.  
  4733.   uint8_t i = idx + 3;
  4734.   uint8_t j = i / 5;
  4735.   uint8_t k = i % 5;
  4736.  
  4737.   if ((i == 3) || (k == 0))
  4738.   {
  4739.  
  4740.     if (i == 3)
  4741.     {
  4742.  
  4743.       for (uint8_t x = 0; x < 16; x++) bgPlotArea[(unsigned int)(x)] |= 16;
  4744.  
  4745.       for (uint8_t x = ((yIdx < 16) ? ((15 - yIdx) & 0x03): 3); x < 16; x += 4) bgPlotArea[(unsigned int)(x)] |= 8;
  4746.  
  4747.     }
  4748.  
  4749.     cgramMode = 0;
  4750.  
  4751.     LCD::loadCGRAMcharacter(j, (const char *)(&bgPlotArea[0]), 0);
  4752.     j |= 0x04;
  4753.     LCD::loadCGRAMcharacter(j, (const char *)(&bgPlotArea[8]), 0);
  4754.  
  4755.     clearBGplot(yIdx);
  4756.  
  4757.   }
  4758.  
  4759. }
  4760.  
  4761. uint8_t bgConvert(unsigned long v, unsigned long ll, unsigned long d)
  4762. {
  4763.  
  4764.   uint8_t b;
  4765.  
  4766.   v *= 15;
  4767.   if (v < ll) b = 254;
  4768.   else
  4769.   {
  4770.  
  4771.     v -= ll;
  4772.     if (d == 0) b = 7;
  4773.     else
  4774.     {
  4775.  
  4776.       v /= d;
  4777.       if (v > 15) b = 255;
  4778.       else b = (uint8_t)(v);
  4779.  
  4780.     }
  4781.  
  4782.   }
  4783.  
  4784.   return b;
  4785.  
  4786. }
  4787.  
  4788. void formatBarGraph(uint8_t bgSize, uint8_t slotIdx, unsigned long centerVal, unsigned long topLimit)
  4789. {
  4790.  
  4791.   uint8_t i;
  4792.   uint8_t k;
  4793.   uint8_t t;
  4794.   uint8_t y = 0;
  4795.  
  4796.   unsigned long v;
  4797.   unsigned long v1 = centerVal;
  4798.   unsigned long v2 = centerVal;
  4799.   unsigned long v3;
  4800.   unsigned long v4 = topLimit / 4;
  4801.  
  4802.   if (centerVal) v3 = topLimit - v4;
  4803.   else v3 = 0;
  4804.   v4 += topLimit;
  4805.  
  4806.   if (v1 < v3)
  4807.   {
  4808.  
  4809.     v = v1;
  4810.     v1 = v3;
  4811.     v3 = v;
  4812.  
  4813.   }
  4814.  
  4815.   i = 0;
  4816.   while (i < bgSize)
  4817.   {
  4818.  
  4819.     v = barGraphData[(unsigned int)(i)];
  4820.     if (v > v2)
  4821.     {
  4822.  
  4823.       if (v < v4) v2 = v;
  4824.       else v2 = v4;
  4825.  
  4826.     }
  4827.     if (v < v1)
  4828.     {
  4829.  
  4830.       if (v > v3) v1 = v;
  4831.       else v1 = v3;
  4832.  
  4833.     }
  4834.     i++;
  4835.  
  4836.   }
  4837.  
  4838.   if (v2 - v1)
  4839.   {
  4840.  
  4841.     v2 -= v1;
  4842.  
  4843.     v1 *= 15;
  4844.  
  4845.     y = bgConvert(centerVal, v1, v2);
  4846.  
  4847.     i = 0;
  4848.     while (i < bgSize)
  4849.     {
  4850.  
  4851.       mBuff2[(unsigned int)(i)] = bgConvert(barGraphData[(unsigned int)(i)], v1, v2);
  4852.       i++;
  4853.  
  4854.     }
  4855.  
  4856.   }
  4857.   else
  4858.   {
  4859.  
  4860.     y = 7;
  4861.  
  4862.     i = 0;
  4863.     while (i < bgSize) mBuff2[(unsigned int)(i++)] = y;
  4864.  
  4865.   }
  4866.  
  4867.   clearBGplot(y);
  4868.   k = bgDataSize;
  4869.  
  4870.   i = 0;
  4871.  
  4872.   while (i < bgSize)
  4873.   {
  4874.  
  4875.     k--;
  4876.     t = mBuff2[(unsigned int)(i)];
  4877.  
  4878.     if ((k == slotIdx) && (timerHeartBeat & 0b01010101))
  4879.     {
  4880.  
  4881.       if (t > 253) bgPlot(k, y, t, 1);
  4882.       else bgPlot(k, t, t, 1);
  4883.  
  4884.     }
  4885.     else
  4886.     {
  4887.  
  4888.       if (t > 253) bgPlot(k, y, t, 1);
  4889.       else bgPlot(k, y, t, 0);
  4890.  
  4891.     }
  4892.  
  4893.     bgOutputPlot(k, y);
  4894.  
  4895.     i++;
  4896.  
  4897.   }
  4898.  
  4899.   while ((--k) < bgDataSize) bgOutputPlot(k, y);
  4900.  
  4901. }
  4902.  
  4903. void displayBarGraphLine(uint8_t lineNum, uint8_t tripIdx, uint8_t tripCalcIdx)
  4904. {
  4905.  
  4906.   gotoXY(0, lineNum);
  4907.  
  4908.   for (uint8_t x = 0; x < 2; x++) charOut(' ');
  4909.   for (uint8_t x = 0; x < 4; x++) charOut(x + lineNum * 4 + 8);
  4910.   for (uint8_t x = 0; x < 2; x++) charOut(' ');
  4911.  
  4912.   if (tripIdx < 255)
  4913.   {
  4914.  
  4915.     charOut(pgm_read_byte(&tripIDchars[(unsigned int)(tripIdx)]));
  4916.     charOut(pgm_read_byte(&bgLabels[(unsigned int)(tripCalcIdx)]));
  4917.  
  4918.     print(doFormat(tripIdx, tripCalcIdx, 0));
  4919.   }
  4920.   else
  4921.   {
  4922.  
  4923.     clrEOL();
  4924.  
  4925.   }
  4926.  
  4927. }
  4928.  
  4929. void displayBarGraph(uint8_t trip1idx, uint8_t trip1CalcIdx, uint8_t trip2idx, uint8_t trip2CalcIdx)
  4930. {
  4931.  
  4932.   displayBarGraphLine(0, trip1idx, trip1CalcIdx);
  4933.   displayBarGraphLine(1, trip2idx, trip2CalcIdx);
  4934.  
  4935. }
  4936. #endif
  4937. #ifdef useLegacyButtons
  4938. const uint8_t errorButtonConflict = 1; // can  have only legacy buttons, Analog MUX buttons, or Parallax 5-button joystick selected
  4939. #endif
  4940.  
  4941. #ifdef useAnalogMuxButtons
  4942. const uint8_t errorButtonConflict = 1; // can  have only legacy buttons, Analog MUX buttons, or Parallax 5-button joystick selected
  4943. #endif
  4944.  
  4945. #ifdef useParallax5PositionSwitch
  4946. const uint8_t errorButtonConflict = 1; // can  have only legacy buttons, Analog MUX buttons, or Parallax 5-button joystick selected
  4947. #endif
  4948.  
  4949. #ifdef useParallaxLCD
  4950. const uint8_t errorSerialConflict = 1; // cannot have both Parallax LCD and serial data logging enabled
  4951.  
  4952. void LCD::init(void)
  4953. {
  4954.  
  4955.   delay2(delay0005ms);
  4956.   writeData(12);
  4957.   delay2(delay0005ms);
  4958.   writeData(22);
  4959.   writeData(232);
  4960.   setBright(brightnessIdx);
  4961.  
  4962. }
  4963.  
  4964. void LCD::gotoXY(uint8_t x, uint8_t y) // x = 0..16, y = 0..1
  4965. {
  4966.  
  4967.   uint8_t dr = 128 + 20 * y + x;
  4968.  
  4969.   writeData(dr);
  4970.  
  4971. }
  4972.  
  4973. void LCD::loadCGRAMcharacter(uint8_t chr, const char * chrData, uint8_t mode)
  4974. {
  4975.  
  4976.   uint8_t b = chr & 0x07;
  4977.  
  4978.   writeData(248 + b);
  4979.  
  4980.   for (uint8_t x = 0; x < 8; x++) writeData(((mode == 1) ? pgm_read_byte(chrData++) : *chrData++)); //write the character data to the character generator ram
  4981.  
  4982. }
  4983.  
  4984. void LCD::setBright(uint8_t idx)
  4985. {
  4986.  
  4987.   if (idx) writeData(17);
  4988.   else writeData(18);
  4989.  
  4990. }
  4991.  
  4992. void LCD::writeData(uint8_t value)
  4993. {
  4994.  
  4995.   pushSerialCharacter(value);
  4996.  
  4997. }
  4998. #endif
  4999. #ifdef useLegacyLCD
  5000.  
  5001. const uint8_t lcdNullValue =        0b00000000;
  5002.  
  5003. const uint8_t lcdClearDisplay =       0b00000001;
  5004.  
  5005. const uint8_t lcdReturnHome =         0b00000010;
  5006.  
  5007. const uint8_t lcdEntryModeSet =       0b00000100;
  5008. const uint8_t lcdEMSincrement =       0b00000010;   // 1 = increment, 0 = decrement
  5009. const uint8_t lcdEMSsetDisplayShift =     0b00000001;   // 1 = display shift, 0 = no display shift
  5010.  
  5011. const uint8_t lcdDisplayControl =       0b00001000;
  5012. const uint8_t lcdDCdisplayShow =      0b00000100;   // 1 = enable display, 0 = disable display
  5013. const uint8_t lcdDCcursorControl =      0b00000010;   // 1 = cursor on, 0 = cursor off
  5014. const uint8_t lcdDCcursorBlinkControl =   0b00000001;   // 1 = cursor blink, 0 = cursor steady
  5015.  
  5016. const uint8_t lcdShift =          0b00010000;
  5017. const uint8_t lcdSdisplayShift =      0b00001000;   // 1 = shift display, 0 = cursor move
  5018. const uint8_t lcdSdirection =         0b00000100;   // 1 = move right, 0 = move left
  5019.  
  5020. const uint8_t lcdFunctionSet =        0b00100000;
  5021. const uint8_t lcdFSdataLength =       0b00010000;   // 1 = 8 bit data, 0 = 4 bit data
  5022. const uint8_t lcdFSnumberOfLines =      0b00001000;   // 1 = 2 lines, 0 = 1 line
  5023. const uint8_t lcdFScharacterFont =      0b00000100;   // 1 = 5x10 dot character font, 0 = 5x8 dot character font
  5024.  
  5025. const uint8_t lcdSetCGRAMaddress =      0b01000000;
  5026.  
  5027. const uint8_t lcdSetDDRAMaddress =      0b10000000;
  5028.  
  5029. void LCD::init(void)
  5030. {
  5031. #ifndef TinkerkitLCDmodule
  5032.  
  5033.   TCCR0A &= ~((1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0));  // put timer 0 in 8-bit fast pwm mode
  5034.   TCCR0A |= ((1 << COM0A1) | (1 << WGM01) | (1 << WGM00));
  5035.   TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B) | (1 << WGM02) | (1 << CS02)); // set timer 0 prescale factor to 64
  5036.   TCCR0B |= ((1 << CS01) | (1 << CS00));
  5037.   TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A) | (1 << TOIE0)); // disable timer 0 interrupts
  5038.   TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); // clear timer 0 interrupt flags
  5039. #endif
  5040.  
  5041. #ifdef TinkerkitLCDmodule
  5042.   TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B0) | (1 << WGM11)); // put timer 1 in 8-bit phase correct pwm mode
  5043.   TCCR1A |= ((1 << COM1A1) | (1 << COM1B1) | (1 << WGM10));
  5044. #else
  5045.   TCCR1A &= ~((1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11)); // put timer 1 in 8-bit phase correct pwm mode
  5046.   TCCR1A |= ((1 << COM1A1) | (1 << WGM10));
  5047. #endif
  5048.   TCCR1B &= ~((1 << ICNC1) | (1 << ICES1) | (1 << WGM13)  | (1 << WGM12) | (1 << CS12)); // set timer 1 prescale factor to 64
  5049.   TCCR1B |= ((1 << CS11) | (1 << CS10));
  5050.   TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
  5051.   TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); // disable timer 1 interrupts
  5052.   TIFR1 |= ((1 << ICF1) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); // clear timer 1 interrupt flags
  5053.  
  5054. #ifdef ArduinoMega2560
  5055.   DDRA = lcdBit3 | lcdBit2 | lcdBit1 | lcdBit0 | lcdEnable | lcdData; // set direction to output on selected port A pins
  5056.   DDRB = lcdBrightness | lcdContrast; // set direction to output on selected port B pins
  5057. #else
  5058. #ifdef TinkerkitLCDmodule
  5059.   DDRB = lcdBit3 | lcdContrast | lcdBrightness;
  5060.   DDRD = lcdBit2 | lcdBit1;
  5061.   DDRE = lcdEnable;
  5062.   DDRF = lcdData | lcdBit0 | lcdDirection;
  5063.   PORTF &= ~lcdDirection;
  5064. #else
  5065.   DDRB = lcdBit3 | lcdBit2 | lcdBit1 | lcdBrightness | LEDred1 | LEDgrn1; // set direction to output on selected port B pins
  5066.   DDRD = lcdBit0 | lcdContrast | lcdEnable | lcdData; // set direction to output on selected port D pins
  5067. #endif
  5068. #endif
  5069.  
  5070.   setBright(brightnessIdx);
  5071.   setContrast(eepromReadVal((unsigned int)(pContrastIdx)));
  5072.  
  5073.   cgramMode = 0; // clear CGRAM font status
  5074.  
  5075. #ifdef useLegacyLCDbuffered
  5076.   lcdBuffer.init();
  5077.   lcdBuffer.process = LCD::outputNybble;
  5078.   lcdBuffer.onNoLongerEmpty = LCD::startOutput;
  5079. #endif
  5080.   writeNybble(lcdNullValue, lcdDelay0015ms); // wait for more than 15 msec
  5081.   writeNybble(lcdFunctionSet | lcdFSdataLength, lcdCommandByte | lcdSendByte | lcdDelay4100us); // send (B0011) to DB7-4, then wait for more than 4.1 ms
  5082.   writeNybble(lcdFunctionSet | lcdFSdataLength, lcdCommandByte | lcdSendByte | lcdDelay0100us); // send (B0011) to DB7-4, then wait for more than 100 us
  5083.   writeNybble(lcdFunctionSet | lcdFSdataLength, lcdCommandByte | lcdSendByte | lcdDelay0100us); // send (B0011) to DB7-4, then wait for more than 100 us
  5084.   writeNybble(lcdFunctionSet, lcdCommandByte | lcdSendByte | lcdDelay0100us); // send (B0010) to DB7-4 for 4 bit mode, then wait for more than 100 us
  5085.  
  5086.   // ready to use normal writeCommand() function now!
  5087.   writeCommand(lcdFunctionSet | lcdFSnumberOfLines); // 4-bit interface, 2 display lines, 5x8 font
  5088.   writeCommand(lcdDisplayControl | lcdDCdisplayShow); // display control:
  5089.  
  5090.   writeCommand(lcdClearDisplay); // clear display, set cursor position to zero
  5091.   writeNybble(lcdNullValue, lcdDelay0015ms); // wait for more than 15 msec for display clear
  5092.  
  5093.   gotoXY(0, 0);
  5094.  
  5095. }
  5096.  
  5097. void LCD::gotoXY(uint8_t x, uint8_t y) // x = 0..16, y = 0..1
  5098. {
  5099.  
  5100.   uint8_t dr = lcdSetDDRAMaddress | x;
  5101.  
  5102.   if (y == 1) dr += 0x40;
  5103.   writeCommand(dr);
  5104.  
  5105. }
  5106.  
  5107. void LCD::loadCGRAMcharacter(uint8_t chr, const char * chrData, uint8_t mode)
  5108. {
  5109.  
  5110.   uint8_t b = chr & 0x07;
  5111.  
  5112.   writeCommand(lcdEntryModeSet | lcdEMSincrement); // entry mode set: increment automatically, no display shift
  5113.   writeCommand(lcdSetCGRAMaddress + (b << 3)); // set CGRAM
  5114.  
  5115.   for (uint8_t x = 0; x < 8; x++) writeData(((mode == 1) ? pgm_read_byte(chrData++) : *chrData++)); //write the character data to the character generator ram
  5116.  
  5117.   writeCommand(lcdSetDDRAMaddress); // set DDRAM to zero
  5118.  
  5119. }
  5120.  
  5121. void LCD::setBright(uint8_t idx)
  5122. {
  5123.  
  5124. #ifdef TinkerkitLCDmodule
  5125.   OCR1B = pgm_read_byte(&brightness[(unsigned int)(idx)]);
  5126. #else
  5127.   OCR1A = pgm_read_byte(&brightness[(unsigned int)(idx)]);
  5128. #endif
  5129.  
  5130. }
  5131.  
  5132. void LCD::setContrast(uint8_t idx)
  5133. {
  5134.  
  5135. #ifdef TinkerkitLCDmodule
  5136.   OCR1A = idx;
  5137. #else
  5138.   OCR0A = idx;
  5139. #endif
  5140.  
  5141. }
  5142.  
  5143. void LCD::writeCommand(uint8_t value)
  5144. {
  5145.  
  5146.   value = writeNybble(value, lcdCommandByte | lcdSendByte | lcdDelay0080us);
  5147.   writeNybble(value, lcdCommandByte | lcdSendByte | lcdDelay0080us);
  5148.  
  5149. }
  5150.  
  5151. void LCD::writeData(uint8_t value)
  5152. {
  5153.  
  5154.   value = writeNybble(value, lcdDataByte | lcdSendByte | lcdDelay0080us);
  5155.   writeNybble(value, lcdDataByte | lcdSendByte | lcdDelay0080us);
  5156.  
  5157. }
  5158.  
  5159. uint8_t LCD::writeNybble(uint8_t value, uint8_t flags)
  5160. {
  5161.  
  5162. #ifdef useLegacyLCDbuffered
  5163.   lcdBuffer.push((value & 0xF0) | (flags & 0x0F));
  5164. #else
  5165.   while (timerCommand & tcLCDdelay);
  5166.  
  5167.   outputNybble((value & 0xF0) | (flags & 0x0F));
  5168. #endif
  5169.  
  5170.   return value << 4;
  5171.  
  5172. }
  5173.  
  5174. void LCD::startOutput(void)
  5175. {
  5176.  
  5177.   timerCommand |= tcLCDdelay;
  5178.  
  5179. }
  5180.  
  5181. void LCD::outputNybble(uint8_t LCDchar)
  5182. {
  5183.  
  5184.   lcdDelayCount = pgm_read_byte(&lcdDelayTable[(unsigned int)(LCDchar & 0x03)]);
  5185.  
  5186.   if (LCDchar & lcdSendByte)
  5187.   {
  5188.  
  5189. #ifdef ArduinoMega2560
  5190.     PORTA &= ~(lcdData | lcdBit3 | lcdBit2 | lcdBit1 | lcdBit0);
  5191.     if (LCDchar & lcdDataByte) PORTA |= lcdData; // set nybble type
  5192.     if (LCDchar & 0b10000000) PORTA |= lcdBit3; // set bit 3
  5193.     if (LCDchar & 0b01000000) PORTA |= lcdBit2; // set bit 2
  5194.     if (LCDchar & 0b00100000) PORTA |= lcdBit1; // set bit 1
  5195.     if (LCDchar & 0b00010000) PORTA |= lcdBit0; // set bit 0
  5196.  
  5197.     PORTA |= lcdEnable; // set enable high
  5198.     PORTA &= ~lcdEnable; // set enable low
  5199. #else
  5200. #ifdef TinkerkitLCDmodule
  5201.     PORTF &= ~(lcdData | lcdBit0);
  5202.     if (LCDchar & lcdDataByte) PORTF |= lcdData; // set nybble type
  5203.     if (LCDchar & 0b00010000) PORTF |= lcdBit0; // set bit 0
  5204.  
  5205.     PORTB &= ~(lcdBit3);
  5206.     if (LCDchar & 0b10000000) PORTB |= lcdBit3; // set bit 3
  5207.  
  5208.     PORTD &= ~(lcdBit2 | lcdBit1);
  5209.     if (LCDchar & 0b01000000) PORTD |= lcdBit2; // set bit 2
  5210.     if (LCDchar & 0b00100000) PORTD |= lcdBit1; // set bit 1
  5211.  
  5212.     PORTE |= lcdEnable; // set enable high
  5213.     PORTE &= ~lcdEnable; // set enable low
  5214. #else
  5215.     PORTD &= ~(lcdData | lcdBit0);
  5216.     if (LCDchar & lcdDataByte) PORTD |= lcdData; // set nybble type
  5217.     if (LCDchar & 0b00010000) PORTD |= lcdBit0; // set bit 0
  5218.  
  5219.     PORTB &= ~(lcdBit3 | lcdBit2 | lcdBit1);
  5220.     if (LCDchar & 0b10000000) PORTB |= lcdBit3; // set bit 3
  5221.     if (LCDchar & 0b01000000) PORTB |= lcdBit2; // set bit 2
  5222.     if (LCDchar & 0b00100000) PORTB |= lcdBit1; // set bit 1
  5223.  
  5224.     PORTD |= lcdEnable; // set enable high
  5225.     PORTD &= ~lcdEnable; // set enable low
  5226. #endif
  5227. #endif
  5228.  
  5229.   }
  5230.  
  5231.   timerCommand |= tcLCDdelay;
  5232.  
  5233. }
  5234. #endif
  5235. #ifdef useBuffering
  5236.  
  5237. void Buffer::init(void)
  5238. {
  5239.  
  5240.   bufferStart = 0;
  5241.   bufferEnd = 0;
  5242.   bufferStatus = bufferIsEmpty;
  5243.  
  5244.   onEmpty = doNothing;
  5245.   onNoLongerEmpty = doNothing;
  5246.   process = doNothing2;
  5247.   onNoLongerFull = doNothing;
  5248.   onFull = doNothing;
  5249.  
  5250. }
  5251.  
  5252. uint8_t Buffer::updatePointer(volatile uint8_t * pointer, uint8_t clearFlag, uint8_t setFlag)
  5253. {
  5254.  
  5255.   uint8_t i = * pointer;
  5256.  
  5257.   (* pointer)++;
  5258.   if ((* pointer) == bufferSize) (* pointer) = 0;
  5259.   bufferStatus &= ~clearFlag;
  5260.   if (bufferStart == bufferEnd) bufferStatus |= setFlag;
  5261.  
  5262.   return i;
  5263.  
  5264. }
  5265.  
  5266. void Buffer::push(uint8_t value)
  5267. {
  5268.  
  5269.   while (bufferStatus & bufferIsFull);
  5270.  
  5271.   uint8_t oldSREG = SREG; // save interrupt flag status
  5272.   cli(); // disable interrupts
  5273.  
  5274.   if (bufferStatus & bufferIsFull) onFull();
  5275.   else
  5276.   {
  5277.  
  5278.     if (bufferStatus & bufferIsEmpty) onNoLongerEmpty();
  5279.     storage[(unsigned int)(updatePointer(&bufferStart, bufferIsEmpty, bufferIsFull))] = value; // save a buffered character
  5280.  
  5281.   }
  5282.  
  5283.   SREG = oldSREG; // restore interrupt flag status
  5284.  
  5285. }
  5286.  
  5287. void Buffer::pull(void)
  5288. {
  5289.  
  5290.   uint8_t s = 0;
  5291.  
  5292.   uint8_t oldSREG = SREG; // save interrupt flag status
  5293.   cli(); // disable interrupts
  5294.  
  5295.   if (bufferStatus & bufferIsEmpty) onEmpty();
  5296.   else
  5297.   {
  5298.  
  5299.     if (bufferStatus & bufferIsFull) onNoLongerFull();
  5300.     process(storage[(unsigned int)(updatePointer(&bufferEnd, bufferIsFull, bufferIsEmpty))]); // get a buffered character
  5301.  
  5302.   }
  5303.  
  5304.   SREG = oldSREG; // restore interrupt flag status
  5305.  
  5306. }
  5307. #endif
  5308.  
  5309. void Trip::reset(void)
  5310. {
  5311.  
  5312.   for (uint8_t x = 0; x < rvLength; x++) collectedData[(unsigned int)(x)] = 0;
  5313.  
  5314. }
  5315.  
  5316. void Trip::transfer(Trip t)
  5317. {
  5318.  
  5319.   for (uint8_t x = 0; x < rvLength; x++) collectedData[(unsigned int)(x)] = t.collectedData[(unsigned int)(x)];
  5320.  
  5321. }
  5322.  
  5323. void Trip::update(Trip src)
  5324. {
  5325.  
  5326.   add32(rvVSSpulseIdx, src.collectedData[(unsigned int)(rvVSSpulseIdx)]);
  5327.   add32(rvInjPulseIdx, src.collectedData[(unsigned int)(rvInjPulseIdx)]);
  5328.  
  5329.   for (uint8_t x = rvVSScycleIdx; x < rvLength; x += 2)
  5330.   {
  5331.  
  5332.     add64s(x, src.collectedData[(unsigned int)(x)]);
  5333.     add32(x + 1, src.collectedData[(unsigned int)(x + 1)]);
  5334.  
  5335.   }
  5336.  
  5337. }
  5338.  
  5339. void Trip::add64s(uint8_t calcIdx, unsigned long v)
  5340. {
  5341.  
  5342.   add32(calcIdx, v); // add to accumulator
  5343.   if (collectedData[(unsigned int)(calcIdx)] < v) collectedData[(unsigned int)(calcIdx + 1)]++; // handle any possible overflow
  5344.  
  5345. }
  5346.  
  5347. void Trip::add32(uint8_t calcIdx, unsigned long v)
  5348. {
  5349.  
  5350.   collectedData[(unsigned int)(calcIdx)] += v;
  5351.  
  5352. }
  5353.  
  5354. #ifdef useWindowFilter
  5355. void Trip::subtract(Trip t)
  5356. {
  5357.  
  5358.   sub32(rvVSSpulseIdx, t.collectedData[(unsigned int)(rvVSSpulseIdx)]);
  5359.   sub32(rvInjPulseIdx, t.collectedData[(unsigned int)(rvInjPulseIdx)]);
  5360.  
  5361.   for (uint8_t x = 2; x < rvLength; x += 2)
  5362.   {
  5363.  
  5364.     if (collectedData[(unsigned int)(x)] < t.collectedData[(unsigned int)(x)]) collectedData[(unsigned int)(x + 1)]--;
  5365.     sub32(x, t.collectedData[(unsigned int)(x)]);
  5366.     sub32(x + 1, t.collectedData[(unsigned int)(x + 1)]);
  5367.  
  5368.   }
  5369.  
  5370. }
  5371.  
  5372. void Trip::sub32(uint8_t calcIdx, unsigned long v)
  5373. {
  5374.  
  5375.   collectedData[(unsigned int)(calcIdx)] -= v;
  5376.  
  5377. }
  5378.  
  5379. #endif
  5380. #ifdef useSavedTrips
  5381. unsigned int getBaseTripPointer(uint8_t tripPos)
  5382. {
  5383.  
  5384.   return (unsigned int)(tripPos) * (unsigned int)(tripListSize) + eePtrSavedTripsStart;
  5385.  
  5386. }
  5387.  
  5388. uint8_t Trip::load(uint8_t tripPos)
  5389. {
  5390.  
  5391.   unsigned int t = getBaseTripPointer(tripPos);
  5392.   uint8_t b = (uint8_t)(eepromReadVal((unsigned int)(t + tripListSigPointer)));
  5393.  
  5394.   reset();
  5395.  
  5396.   if (b == guinosig)
  5397.   {
  5398.  
  5399.     for (uint8_t x = 0; x < tripListLength; x++) collectedData[(unsigned int)(x)] = eepromReadVal(++t);
  5400.  
  5401.     b = 1;
  5402.  
  5403.   }
  5404.   else b = 0;
  5405.  
  5406.   return b;
  5407.  
  5408. }
  5409.  
  5410. uint8_t Trip::save(uint8_t tripPos)
  5411. {
  5412.  
  5413.   unsigned int t = getBaseTripPointer(tripPos);
  5414.  
  5415. #ifndef useClock
  5416.   unsigned long outputCycles[2];
  5417.  
  5418.   cli(); // perform atomic transfer of clock to main program
  5419.  
  5420.   outputCycles[0] = systemCycles[0]; // perform atomic transfer of system time to main program
  5421.   outputCycles[1] = systemCycles[1];
  5422.  
  5423.   sei();
  5424. #endif
  5425.  
  5426.   eepromWriteVal(t++, convertTime(outputCycles));
  5427.  
  5428.   for (uint8_t x = 0; x < tripListLength; x++) eepromWriteVal(t++, collectedData[(unsigned int)(x)]);
  5429.  
  5430.   eepromWriteVal(t++, guinosig);
  5431.  
  5432.   return 1;
  5433.  
  5434. }
  5435. #endif
  5436.  
  5437. unsigned long tmp1[2] = { 0, 0 };
  5438. unsigned long tmp2[2] = { 0, 0 };
  5439. unsigned long tmp3[2] = { 0, 0 };
  5440. unsigned long tmp4[2] = { 0, 0 };
  5441. unsigned long tmp5[2] = { 0, 0 };
  5442.  
  5443. union union_64 * tempPtr[5] = {
  5444.   (union union_64 *)&tmp1,
  5445.   (union union_64 *)&tmp2,
  5446.   (union union_64 *)&tmp3,
  5447.   (union union_64 *)&tmp4,
  5448.   (union union_64 *)&tmp5,
  5449. };
  5450.  
  5451. union union_64 * tu1 = tempPtr[0];
  5452. union union_64 * tu2 = tempPtr[1];
  5453.  
  5454. const uint8_t * const S64programList[] PROGMEM = {
  5455.   prgmFuelUsed,
  5456.   prgmFuelRate,
  5457.   prgmEngineRunTime,
  5458.   prgmTimeToEmpty,
  5459.   prgmDistance,
  5460.   prgmSpeed,
  5461.   prgmMotionTime,
  5462.   prgmFuelEcon,
  5463.   prgmRemainingFuel,
  5464.   prgmDistanceToEmpty,
  5465.   prgmEngineSpeed,
  5466.   prgmInjectorOpenTime,
  5467.   prgmInjectorTotalTime,
  5468.   prgmVSStotalTime,
  5469.   prgmInjectorPulseCount,
  5470.   prgmVSSpulseCount,
  5471. #ifdef useFuelCost
  5472.   prgmFuelCost,
  5473.   prgmFuelRateCost,
  5474.   prgmFuelCostPerDistance,
  5475.   prgmDistancePerFuelCost,
  5476.   prgmRemainingFuelCost,
  5477. #endif
  5478. #ifdef useAnalogRead
  5479. #ifdef TinkerkitLCDmodule
  5480.   prgmVoltage,
  5481.   prgmVoltage,
  5482.   prgmVoltage,
  5483. #else
  5484.   prgmVoltage,
  5485.   prgmVoltage,
  5486. #ifdef useAnalogButtons
  5487.   prgmVoltage,
  5488.   prgmVoltage,
  5489.   prgmVoltage,
  5490. #endif
  5491. #endif
  5492. #endif
  5493. #ifdef useChryslerMAPCorrection
  5494.   prgmPressure,
  5495.   prgmPressure,
  5496.   prgmPressure,
  5497.   prgmPressure,
  5498.   prgmCorrF,
  5499. #endif
  5500.   prgmFindRemainingFuel,
  5501.   prgmDoMultiply,
  5502.   prgmDoDivide,
  5503.   prgmFindCyclesPerQuantity,
  5504.   prgmConvertToMicroSeconds,
  5505.   prgmDoAdjust,
  5506.   prgmFormatToNumber,
  5507. };
  5508.  
  5509. unsigned long SWEET64(const uint8_t * sched, uint8_t tripIdx)
  5510. {
  5511.  
  5512.   uint8_t spnt = 0;
  5513.   uint8_t instr;
  5514.   uint8_t b;
  5515.   uint8_t f;
  5516.   const uint8_t * prgmStack[16];
  5517.   uint8_t tf = 0;
  5518.  
  5519.   while (true)
  5520.   {
  5521.  
  5522. #ifdef useSWEET64trace
  5523.     if (tf)
  5524.     {
  5525.  
  5526.       pushSerialCharacter(13);
  5527.       pushHexWord((unsigned int)(sched));
  5528.  
  5529.     }
  5530.  
  5531. #endif
  5532.     instr = pgm_read_byte(sched++);
  5533.  
  5534. #ifdef useSWEET64trace
  5535.     if (tf)
  5536.     {
  5537.  
  5538.       pushSerialCharacter(32);
  5539.       pushHexByte(tripIdx);
  5540.       pushSerialCharacter(32);
  5541.       pushHexByte(spnt);
  5542.       pushSerialCharacter(32);
  5543.       pushHexByte(instr);
  5544.  
  5545.     }
  5546. #endif
  5547.  
  5548.     if (instr & 0x40)
  5549.     {
  5550.  
  5551.       b = pgm_read_byte(sched++) - 0x11;
  5552. #ifdef useSWEET64trace
  5553.  
  5554.       if (tf)
  5555.       {
  5556.  
  5557.         pushSerialCharacter(32);
  5558.         pushHexByte(b);
  5559.  
  5560.       }
  5561. #endif
  5562.  
  5563.       tu1 = tempPtr[(unsigned int)((b >> 4) & 0x07)];
  5564.       tu2 = tempPtr[(unsigned int)(b & 0x07)];
  5565.  
  5566.     }
  5567.  
  5568.     if (instr & 0x80)
  5569.     {
  5570.  
  5571.       b = pgm_read_byte(sched++);
  5572.  
  5573. #ifdef useSWEET64trace
  5574.       if (tf)
  5575.       {
  5576.  
  5577.         pushSerialCharacter(32);
  5578.         pushHexByte(b);
  5579.  
  5580.       }
  5581.  
  5582. #endif
  5583.     }
  5584.  
  5585. #ifdef useSWEET64trace
  5586.     if (tf) pushSerialCharacter(13);
  5587. #endif
  5588.     f = 0;
  5589.  
  5590.     if ((instr == instrLdNumer) || (instr == instrLdDenom)) b = pgm_read_byte(&convNumerIdx[(unsigned int)(tripIdx)]);
  5591.     if (instr == instrLdDenom) b ^= 1;
  5592.     if ((instr == instrLdEEPROMindirect) || (instr == instrStEEPROMindirect)) b = pgm_read_byte(&convIdx[(unsigned int)(tripIdx)]);
  5593.     if (instr == instrLdEEPROMindexed) b += tripIdx;
  5594.  
  5595.     if ((instr == instrLdNumer) || (instr == instrLdDenom)) instr = instrLdConst;
  5596.     else if ((instr == instrLdEEPROMindexed) || (instr == instrLdEEPROMindirect)) instr = instrLdEEPROM;
  5597.     else if (instr == instrStEEPROMindirect) instr = instrStEEPROM;
  5598.  
  5599.     if (instr == instrDone)
  5600.     {
  5601.  
  5602.       if (spnt--) sched = prgmStack[(unsigned int)(spnt)];
  5603.       else break;
  5604.  
  5605.     }
  5606.     else if (instr == instrTraceOn) tf = 1;
  5607.     else if (instr == instrTraceOff) tf = 0;
  5608.     else if (instr == instrSkip) f = 1;
  5609.     else if (instr == instrSkipIfMetricMode) f = metricFlag;
  5610.     else if (instr == instrSkipIfZero) f = zeroTest64(tu2);
  5611.     else if (instr == instrSkipIfLTorE) f = ltOrEtest64(tu1, tu2);
  5612.     else if (instr == instrSkipIfLSBset) f = lsbTest64(tu2);
  5613.     else if (instr == instrSkipIfMSBset) f = msbTest64(tu2);
  5614.     else if (instr == instrSkipIfIndexBelow) f = (tripIdx < pgm_read_byte(sched++));
  5615.     else if (instr == instrLd) copy64(tu1, tu2);
  5616.     else if (instr == instrLdByte) init64(tu2, b);
  5617.     else if (instr == instrLdByteFromYindexed) init64(tu1, tu2->u8[(unsigned int)(tripIdx)]);
  5618.     else if (instr == instrLdTripVar) tripVarLoad64(tu2, tripIdx, b);
  5619.     else if (instr == instrLdTtlFuelUsed) tripVarLoad64(tu2, tankIdx, rvInjOpenCycleIdx);
  5620.     else if (instr == instrLdConst) init64(tu2, pgm_read_dword(&convNumbers[(unsigned int)(b)]));
  5621.     else if (instr == instrLdEEPROM) init64(tu2, eepromReadVal((unsigned int)(b)));
  5622.     else if (instr == instrStEEPROM) EEPROMsave64(tu2, b);
  5623.     else if (instr == instrStByteToYindexed) tu2->u8[(unsigned int)(tripIdx)] = tu1->u8[0];
  5624.     else if (instr == instrLdIndex) tripIdx = b;
  5625.     else if (instr == instrCall)
  5626.     {
  5627.       prgmStack[(unsigned int)(spnt++)] = sched;
  5628.       if (spnt > 15) break;
  5629.       else sched = (const uint8_t *)pgm_read_word(&S64programList[(unsigned int)(b)]);
  5630.     }
  5631.     else if (instr == instrJump) sched = (const uint8_t *)pgm_read_word(&S64programList[(unsigned int)(b)]);
  5632.     else if (instr == instrSwap) swap64(tu1, tu2);
  5633.     else if (instr == instrSubYfromX) add64(tu1, tu2, 1);
  5634.     else if (instr == instrAddYtoX) add64(tu1, tu2, 0);
  5635. #ifndef useSWEET64multDiv
  5636.     else if (instr == instrMulXbyY) mul64(tu1, tu2);
  5637.     else if (instr == instrDivXbyY) div64(tu1, tu2);
  5638. #endif
  5639.     else if (instr == instrShiftLeft) shl64(tu2);
  5640.     else if (instr == instrShiftRight) shr64(tu2);
  5641.     else if (instr == instrAddToIndex) tripIdx += b;
  5642. #ifdef useAnalogRead
  5643.     else if (instr == instrLdVoltage) init64(tu2, analogValue[(unsigned int)(tripIdx)]);
  5644. #endif
  5645. #ifdef useChryslerMAPCorrection
  5646.     else if (instr == instrLdPressure) init64(tu2, pressure[(unsigned int)(tripIdx)]);
  5647. #endif
  5648. #ifdef useIsqrt
  5649.     else if (instr == instrIsqrt) tu2->ui[0] = iSqrt(tu2->ui[0]);
  5650. #endif
  5651.     else break; // just found an unsupported opcode
  5652.  
  5653. #ifdef useSWEET64trace
  5654.     if (tf)
  5655.     {
  5656.  
  5657.       for (uint8_t x = 0;x < 5; x++)
  5658.       {
  5659.  
  5660.         pushSerialCharacter(9);
  5661.         pushHexDWord(tempPtr[(unsigned int)(x)]->ul[1]);
  5662.         pushSerialCharacter(32);
  5663.         pushHexDWord(tempPtr[(unsigned int)(x)]->ul[0]);
  5664.         pushSerialCharacter(13);
  5665.  
  5666.       }
  5667.  
  5668.     }
  5669. #endif
  5670.  
  5671.     if (f)
  5672.     {
  5673.  
  5674.       if (b < 128) sched += b;
  5675.       else sched -= (256 - b);
  5676. #ifdef useSWEET64trace
  5677.  
  5678.       if (tf)
  5679.       {
  5680.  
  5681.         pushSerialCharacter(9);
  5682.         pushHexWord((unsigned int)(sched));
  5683.         pushSerialCharacter(13);
  5684.  
  5685.       }
  5686. #endif
  5687.  
  5688.     }
  5689.  
  5690. #ifdef useSWEET64trace
  5691.     if (tf) pushSerialCharacter(13);
  5692.  
  5693. #endif
  5694.   }
  5695.  
  5696.   return tempPtr[1]->ul[0];
  5697.  
  5698. }
  5699.  
  5700. #ifdef useSerialDebugOutput
  5701. void pushHexNybble(uint8_t val)
  5702. {
  5703.  
  5704.   val &= 0x0F;
  5705.   if (val < 0x0A) pushSerialCharacter(val + 0x30);
  5706.   else pushSerialCharacter(val + 0x37);
  5707.  
  5708. }
  5709.  
  5710. void pushHexByte(uint8_t val)
  5711. {
  5712.  
  5713.   pushHexNybble(val >> 4);
  5714.   pushHexNybble(val);
  5715.  
  5716. }
  5717.  
  5718. void pushHexWord(unsigned int val)
  5719. {
  5720.   pushHexByte(val >> 8);
  5721.   pushHexByte(val);
  5722. }
  5723.  
  5724. void pushHexDWord(unsigned long val)
  5725. {
  5726.   pushHexWord(val >> 16);
  5727.   pushHexWord(val);
  5728. }
  5729. #endif
  5730.  
  5731. void copy64(union union_64 * an, union union_64 * ann)
  5732. {
  5733.  
  5734.   for (uint8_t x = 0; x < 8; x++) an->u8[(unsigned int)(x)] = ann->u8[(unsigned int)(x)];
  5735.  
  5736. }
  5737.  
  5738. void tripVarLoad64(union union_64 * an, uint8_t tripIdx, uint8_t dataIdx)
  5739. {
  5740.  
  5741.   if (dataIdx < rvVSScycleIdx) init64(an, tripArray[(unsigned int)(tripIdx)].collectedData[(unsigned int)(dataIdx)]);
  5742.   else copy64(an, (union union_64 *)&tripArray[(unsigned int)(tripIdx)].collectedData[(unsigned int)(dataIdx)]);
  5743.  
  5744. }
  5745.  
  5746. void EEPROMsave64(union union_64 * an, uint8_t dataIdx)
  5747. {
  5748.  
  5749.   eepromWriteVal((unsigned int)(dataIdx), an->ul[0]);
  5750.  
  5751. }
  5752.  
  5753. void init64(union union_64 * an, unsigned long dWordL)
  5754. {
  5755.  
  5756.   an->ull = 0;
  5757.   an->ul[0] = dWordL;
  5758.  
  5759. }
  5760.  
  5761. void swap64(union union_64 * an, union union_64 * ann) // swap ann and an
  5762. {
  5763.  
  5764.   uint8_t b = 0;
  5765.  
  5766.   for (uint8_t x = 0; x < 8; x++)
  5767.   {
  5768.  
  5769.     b = ann->u8[(unsigned int)(x)];
  5770.     ann->u8[(unsigned int)(x)] = an->u8[(unsigned int)(x)];
  5771.     an->u8[(unsigned int)(x)] = b;
  5772.  
  5773.   }
  5774.  
  5775. }
  5776.  
  5777. void shr64(union union_64 * an)
  5778. {
  5779.  
  5780.   uint8_t b = 0;
  5781.   uint8_t c;
  5782.  
  5783.   for (uint8_t x = 7; x < 8; x--)
  5784.   {
  5785.  
  5786.     c = b;
  5787.     b = ((an->u8[(unsigned int)(x)] & 0x01) ? 0x80 : 0x00);
  5788.     an->u8[(unsigned int)(x)] >>= 1;
  5789.     an->u8[(unsigned int)(x)] += c;
  5790.  
  5791.   }
  5792.  
  5793. }
  5794.  
  5795. void shl64(union union_64 * an)
  5796. {
  5797.  
  5798.   uint8_t b = 0;
  5799.   uint8_t c;
  5800.  
  5801.   for (uint8_t x = 0; x < 8; x++)
  5802.   {
  5803.  
  5804.     c = b;
  5805.     b = ((an->u8[(unsigned int)(x)] & 0x80) ? 0x01 : 0x00);
  5806.     an->u8[(unsigned int)(x)] <<= 1;
  5807.     an->u8[(unsigned int)(x)] += c;
  5808.  
  5809.   }
  5810.  
  5811. }
  5812.  
  5813. void add64(union union_64 * an, union union_64 * ann, uint8_t mode)
  5814. {
  5815.  
  5816.   uint8_t d;
  5817.   int enn;
  5818.   union union_16 * n = (union union_16 *)&enn;
  5819.  
  5820.   n->u8[1] = ((mode) ? 0x01 : 0x00);
  5821.   for (uint8_t x = 0; x < 8; x++)
  5822.   {
  5823.  
  5824.     d = ((mode) ? 0xFF : 0x00);
  5825.     d ^= ann->u8[(unsigned int)(x)];
  5826.     n->u8[0] = n->u8[1];
  5827.     n->u8[1] = 0;
  5828.     n->ui += (unsigned int)an->u8[(unsigned int)(x)];
  5829.     n->ui += d;
  5830.     an->u8[(unsigned int)(x)] = n->u8[0];
  5831.  
  5832.   }
  5833.  
  5834. }
  5835.  
  5836. #ifndef useSWEET64multDiv
  5837. void mul64(union union_64 * an, union union_64 * ann)
  5838. {
  5839.  
  5840.   union union_64 * multiplier = tempPtr[3];
  5841.   union union_64 * multiplicand = tempPtr[4];
  5842.  
  5843.   copy64(multiplier, an);
  5844.   copy64(multiplicand, ann);
  5845.   an->ull = 0;
  5846.  
  5847.   while (!(zeroTest64(multiplier)))
  5848.   {
  5849.  
  5850.     if (lsbTest64(multiplier)) add64(an, multiplicand, 0);
  5851.  
  5852.     shl64(multiplicand);
  5853.     shr64(multiplier);
  5854.  
  5855.   }
  5856.  
  5857. }
  5858.  
  5859. void div64(union union_64 * an, union union_64 * ann) // dividend in an, divisor in ann
  5860. {
  5861.  
  5862.   union union_64 * quotientBit = tempPtr[3];
  5863.   union union_64 * divisor = tempPtr[4];
  5864.  
  5865.   copy64(divisor, ann); // copy ann value to divisor
  5866.   copy64(ann, an); // copy an value (dividend) to ann (this will become remainder)
  5867.   an->ull = 0; // zero out result
  5868.   init64(quotientBit, 1); // initialize quotient mark bit
  5869.  
  5870.   if (zeroTest64(divisor))
  5871.   { // if divisor is zero, mark as overflow, then exit
  5872.  
  5873.     add64(an, quotientBit, 1); // subtract 1 from zeroed-out result to generate overflow value
  5874.     copy64(ann, an); // copy overflow value to remainder
  5875.  
  5876.   }
  5877.   else if (!(zeroTest64(ann)))
  5878.   { // if dividend is not zero,
  5879.  
  5880.     while (!(msbTest64(divisor)))
  5881.     { // ensure that divisor MSB is set
  5882.  
  5883.       shl64(divisor); // shift divisor left one bit
  5884.       shl64(quotientBit); // shift quotient mark bit left by one
  5885.  
  5886.     }
  5887.  
  5888.     while (!(zeroTest64(quotientBit)))
  5889.     { // continue while there is a quotient mark bit
  5890.  
  5891.       if (ltOrEtest64(divisor, ann))
  5892.       { // if divisor is less than or equal to dividend,
  5893.         add64(ann, divisor, 1); // subtract divisor value from dividend
  5894.         add64(an, quotientBit, 0); // mark corresponding bit in quotient
  5895.       }
  5896.  
  5897.       shr64(divisor); // shift divisor right by one bit
  5898.       shr64(quotientBit); // shift quotient mark bit right by one bit
  5899.  
  5900.     }
  5901.  
  5902.   }
  5903.  
  5904. }
  5905. #endif
  5906.  
  5907. uint8_t zeroTest64(union union_64 * an)
  5908. {
  5909.  
  5910.   uint8_t b = 0;
  5911.  
  5912.   for (uint8_t x = 0; x < 8; x++) b |= an->u8[(unsigned int)(x)];
  5913.  
  5914.   return (b == 0);
  5915.  
  5916. }
  5917.  
  5918. uint8_t ltOrEtest64(union union_64 * an, union union_64 * ann)
  5919. {
  5920.  
  5921.   uint8_t b = 1;
  5922.  
  5923.   for (uint8_t x = 7; x < 8; x--)
  5924.   {
  5925.  
  5926.     if (an->u8[(unsigned int)(x)] < ann->u8[(unsigned int)(x)]) break;
  5927.     else if (an->u8[(unsigned int)(x)] > ann->u8[(unsigned int)(x)])
  5928.     {
  5929.  
  5930.       b = 0;
  5931.       break;
  5932.  
  5933.     }
  5934.  
  5935.   }
  5936.  
  5937.   return (b == 1);
  5938.  
  5939. }
  5940.  
  5941. uint8_t lsbTest64(union union_64 * an)
  5942. {
  5943.  
  5944.   return ((an->u8[0] & 0x01) != 0);
  5945.  
  5946. }
  5947.  
  5948. uint8_t msbTest64(union union_64 * an)
  5949. {
  5950.  
  5951.   return ((an->u8[7] & 0x80) != 0);
  5952.  
  5953. }
  5954.  
  5955. char * doFormat(uint8_t tripIdx, uint8_t dispPos)
  5956. {
  5957.  
  5958.   uint8_t r = (tripIdx & dfTripMask) >> dfBitShift;
  5959.   uint8_t f = tripIdx & dfValMask;
  5960.  
  5961.   return doFormat(r, f, dispPos);
  5962.  
  5963. }
  5964.  
  5965. #if useFuelCost
  5966. const uint8_t lblCGRAMextendedBase = 40;
  5967. #else
  5968. const uint8_t lblCGRAMextendedBase = 28;
  5969. #endif
  5970.  
  5971. const uint8_t calcLabelIdx[] PROGMEM = { // +128 is metric flag - metric label has offset of 2 bytes from index
  5972.   20 + 128,     // fuel used
  5973.   24 + 128,     // fuel rate
  5974.   0,        // engine run time
  5975.   0,        // time to empty
  5976.   12 + 128,     // distance travelled
  5977.   16 + 128,     // speed
  5978.   0,        // time in motion
  5979.   8 + 128,      // fuel economy
  5980.   20 + 128,     // remaining fuel
  5981.   12 + 128,     // remaining distance
  5982.   6,        // engine speed
  5983.   2,        // fuel used, in microseconds
  5984.   2,        // engine run time, in microseconds
  5985.   2,        // time in motion, in microseconds
  5986.   4,        // injector pulses
  5987.   4,        // injector pulses
  5988. #ifdef useFuelCost
  5989.   28,       // fuel cost
  5990.   30,       // fuel rate cost
  5991.   32 + 128,     // fuel cost per unit distance
  5992.   36 + 128,     // distance per unit fuel cost
  5993.   28,       // fuel cost remaining
  5994. #endif
  5995. #ifdef useAnalogRead
  5996. #ifdef TinkerkitLCDmodule
  5997.   lblCGRAMextendedBase,   // voltage
  5998.   lblCGRAMextendedBase,   // voltage
  5999.   lblCGRAMextendedBase,   // voltage
  6000. #else
  6001.   lblCGRAMextendedBase,   // voltage
  6002.   lblCGRAMextendedBase,   // voltage
  6003. #ifdef useAnalogButtons
  6004.   lblCGRAMextendedBase,   // voltage
  6005.   lblCGRAMextendedBase,   // voltage
  6006.   lblCGRAMextendedBase,   // voltage
  6007. #endif
  6008. #endif
  6009. #endif
  6010. #ifdef useChryslerMAPCorrection
  6011.   lblCGRAMextendedBase + 2 + 128, // voltage
  6012.   lblCGRAMextendedBase + 2 + 128, // voltage
  6013.   lblCGRAMextendedBase + 2 + 128, // voltage
  6014.   lblCGRAMextendedBase + 2 + 128, // voltage
  6015.   lblCGRAMextendedBase + 6, // correction factor
  6016. #endif
  6017. };
  6018.  
  6019. unsigned long doCalculate(uint8_t calcIdx, uint8_t tripIdx)
  6020. {
  6021.  
  6022.   uint8_t i = tripIdx;
  6023. #ifdef useAnalogRead
  6024.   if ((calcIdx >= dfMaxValCount) && (calcIdx < dfMaxValAnalogCount)) i = calcIdx - dfMaxValCount;
  6025. #endif
  6026. #ifdef useChryslerMAPCorrection
  6027.   if ((calcIdx >= dfMaxValAnalogCount) && (calcIdx < dfMaxValMAPCount)) i = calcIdx - dfMaxValAnalogCount;
  6028. #endif
  6029.  
  6030.   return SWEET64((const uint8_t *)pgm_read_word(&S64programList[(unsigned int)(calcIdx)]), i);
  6031.  
  6032. }
  6033.  
  6034. char * format64(const uint8_t * prgmPtr, unsigned long num, char * str, uint8_t ndp)
  6035. {
  6036.  
  6037.   uint8_t b;
  6038.   uint8_t c;
  6039.  
  6040.   init64(tempPtr[1], num);
  6041.   SWEET64(prgmPtr, ndp);
  6042.  
  6043.   uint8_t l = tempPtr[2]->u8[6];  // load total length
  6044.  
  6045.   if (l == 255) strcpy_P(str, overFlowStr);
  6046.   else
  6047.   {
  6048.  
  6049.     uint8_t z = tempPtr[2]->u8[7];  // load leading zero character
  6050.  
  6051.     for (uint8_t x = 0; x < l; x++)
  6052.     {
  6053.  
  6054.       uint8_t y = x * 2;
  6055.       b = tempPtr[2]->u8[(unsigned int)(x)];
  6056.       c = b / 10;
  6057.       b -= c * 10;
  6058.       c = ((c) ? c + 48 : z);
  6059.       if (c > 48) z = 48;
  6060.       if ((x + 1) == l) z = 48;
  6061.       b = ((b) ? b + 48 : z);
  6062.       if (b > 48) z = 48;
  6063.       str[(unsigned int)(y)] = c;
  6064.       str[(unsigned int)(y + 1)] = b;
  6065.  
  6066.     }
  6067.  
  6068.     str[l * 2] = 0;
  6069.  
  6070.   }
  6071.  
  6072.   return str;
  6073.  
  6074. }
  6075.  
  6076. char * format(unsigned long num, uint8_t ndp)
  6077. {
  6078.  
  6079.   uint8_t x = 9;
  6080.   uint8_t y = 10;
  6081.   uint8_t c;
  6082.  
  6083.   format64(prgmRoundOffNumber, num, mBuff1, ndp);
  6084.  
  6085.   if (mBuff1[2] != '-')
  6086.   {
  6087.  
  6088.     while (x > 5)
  6089.     {
  6090.  
  6091.       if (y != 7)
  6092.       {
  6093.  
  6094.         c = mBuff1[(unsigned int)(x)];
  6095.         if (c == ' ') c = '0';
  6096.         x--;
  6097.  
  6098.       }
  6099.       else c = '.';
  6100.  
  6101.       mBuff1[(unsigned int)(y)] = c;
  6102.       y--;
  6103.  
  6104.     }
  6105.  
  6106.     x = 1;
  6107.  
  6108.     if (ndp)
  6109.     {
  6110.  
  6111.       y = 2;
  6112.  
  6113.       while ((y < 2 + ndp) && (mBuff1[(unsigned int)(y)] == ' '))
  6114.       {
  6115.  
  6116.         y++;
  6117.         x = y;
  6118.  
  6119.       }
  6120.  
  6121.     }
  6122.  
  6123.     for (uint8_t z = 0; z < 6; z++)
  6124.     {
  6125.  
  6126.       mBuff1[(unsigned int)(z)] = mBuff1[(unsigned int)(x)];
  6127.       x++;
  6128.  
  6129.     }
  6130.  
  6131.     mBuff1[6] = 0;
  6132.  
  6133.   }
  6134.  
  6135.   return mBuff1;
  6136.  
  6137. }
  6138.  
  6139. char * doFormat(uint8_t tripIdx, uint8_t calcIdx, uint8_t dispPos)
  6140. {
  6141.  
  6142.   uint8_t numDecPt = pgm_read_byte(&calcDecimalPoints[(unsigned int)(calcIdx)]);
  6143.   uint8_t calcWord = pgm_read_byte(&calcLabelIdx[(unsigned int)(calcIdx)]);
  6144.  
  6145.   uint8_t p;
  6146.   uint8_t c;
  6147.   unsigned long an;
  6148.  
  6149.   if ((calcIdx < dfMaxValDisplayCount) && (tripIdx < tripSlotCount))
  6150.   {
  6151.  
  6152.     an = doCalculate(calcIdx, tripIdx);
  6153.  
  6154.     if ((dispPos & dispRaw) || (dispPos & dispFE) || (dispPos & dispDTE))
  6155.     {
  6156.  
  6157.       if (numDecPt) format(an, 3);
  6158.       else format64(prgmFormatToNumber, an, mBuff1, 3);
  6159.  
  6160.       if (dispPos & dispFE)
  6161.       {
  6162.  
  6163.         c = 3;
  6164.  
  6165.       }
  6166.  
  6167.       if (dispPos & dispDTE)
  6168.       {
  6169.  
  6170.         c = 4;
  6171.  
  6172.       }
  6173.  
  6174.       if ((dispPos & dispFE) || (dispPos & dispDTE))
  6175.       {
  6176.  
  6177.         p = 0;
  6178.         if (mBuff1[2] != '-') // if number did not overflow
  6179.         {
  6180.  
  6181.  
  6182.           if ((mBuff1[(unsigned int)(2)] == '.') || ((mBuff1[(unsigned int)(3)] == '.') && (dispPos & dispDTE)))
  6183.           {
  6184.  
  6185.             if (mBuff1[0] == ' ') p++; // if number is less than 10, point to start of number
  6186.             c++; // update end of number
  6187.  
  6188.           }
  6189.           else if (mBuff1[(unsigned int)(c)] != '.') strcpy_P(mBuff1, overFlowStr); // if number is greater than 999(9), mark as overflow
  6190.  
  6191.         }
  6192.  
  6193.         if (mBuff1[2] == '-') p++; // if number overflowed, point to start of overflow dashes
  6194.  
  6195.         if (p > 0) for (uint8_t x = 0; x < (c + 1); x++) mBuff1[(unsigned int)(x)] = mBuff1[(unsigned int)(p++)];
  6196.  
  6197.         mBuff1[(unsigned int)(c)] = 0;
  6198.  
  6199.       }
  6200.  
  6201.     }
  6202.     else
  6203.     {
  6204.  
  6205.       if (calcWord == 0) format64(prgmFormatToTime, an, mBuff1, 0);
  6206.       else format(an, numDecPt);
  6207.  
  6208.     }
  6209.  
  6210.   }
  6211.   else
  6212.   {
  6213.  
  6214.     strcpy_P(mBuff1, overFlowStr);
  6215.  
  6216.   }
  6217.  
  6218.   return mBuff1;
  6219.  
  6220. }
  6221.  
  6222. unsigned long rformat(void)
  6223. {
  6224.  
  6225.   unsigned long v = 0ul;
  6226.   uint8_t c;
  6227.  
  6228.   for (uint8_t p = 0; p < 10; p++)
  6229.   {
  6230.  
  6231.     c = pBuff[(unsigned int)(p)];
  6232.     if (c == 32) c = 0;
  6233.     else c -= '0';
  6234.     v *= 10;
  6235.     v += c;
  6236.  
  6237.   }
  6238.  
  6239.   return v;
  6240.  
  6241. }
  6242.  
  6243. const uint8_t prgmConvertToTime[] PROGMEM = {
  6244.   instrLdConst, 0x01, idxCyclesPerSecond,
  6245.   instrJump, idxS64doDivide
  6246. };
  6247.  
  6248. unsigned long convertTime(unsigned long * an)
  6249. {
  6250.  
  6251.   copy64(tempPtr[1], (union union_64 *)(an));
  6252.   return SWEET64(prgmConvertToTime, 0);
  6253.  
  6254. }
  6255.  
  6256. #ifdef useChryslerMAPCorrection
  6257. const uint8_t prgmGenerateVoltageSlope[] PROGMEM = {
  6258.   instrLdEEPROMindexed, 0x02, pMAPsensorCeilingIdx,
  6259.   instrLdEEPROMindexed, 0x01, pMAPsensorFloorIdx,
  6260.   instrSubYfromX, 0x21,
  6261.   instrSwap, 0x23,
  6262.  
  6263.   instrLdConst, 0x02, idxDenomVoltage,
  6264.   instrLdEEPROMindexed, 0x01, pMAPsensorRangeIdx,
  6265.   instrCall, idxS64doMultiply,
  6266.  
  6267.   instrSwap, 0x13,
  6268.   instrJump, idxS64doDivide,
  6269. };
  6270.  
  6271. const uint8_t prgmConvertVolts[] PROGMEM = {
  6272.   instrLdEEPROMindexed, 0x02, pMAPsensorFloorIdx,
  6273.   instrLdConst, 0x01, idxNumerVoltage,
  6274.   instrCall, idxS64doMultiply,
  6275.   instrLdConst, 0x01, idxDenomVoltage,
  6276.   instrJump, idxS64doDivide,
  6277. };
  6278. #endif
  6279.  
  6280. const uint8_t prgmConvertInjSettleTime[] PROGMEM = {
  6281.   instrLdConst, 0x01, idxCyclesPerSecond,
  6282.   instrLdEEPROM, 0x02, pInjectorSettleTimeIdx,
  6283.   instrCall, idxS64doMultiply,
  6284.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  6285.   instrJump, idxS64doDivide,
  6286. };
  6287.  
  6288. const uint8_t prgmFindSleepTicks[] PROGMEM = {
  6289.   instrLdConst, 0x01, idxCyclesPerSecond,
  6290.   instrLdEEPROM, 0x02, pActivityTimeoutIdx,
  6291.   instrCall, idxS64doMultiply,
  6292.   instrLdIndex, 0,
  6293.   instrShiftRight, 0x02,
  6294.   instrAddToIndex, 1,
  6295.   instrSkipIfIndexBelow, 249, 8,
  6296.   instrDone
  6297. };
  6298.  
  6299. const uint8_t prgmFindMinGoodRPM[] PROGMEM = {
  6300.   instrLdByte, 0x01, 60,            // load seconds per minute into register 1
  6301.   instrLdEEPROM, 0x02, pCrankRevPerInjIdx,      // load crank revolutions per injector event into register 2
  6302.   instrCall, idxS64doMultiply,          // perform multiply
  6303.   instrLdConst, 0x01, idxCyclesPerSecond,       // load cycles per second into register 1
  6304.   instrCall, idxS64doMultiply,          // perform conversion
  6305.   instrLdEEPROM, 0x01, pMinGoodRPMidx,        // get minimum good RPM figure from EEPROM
  6306.   instrCall, idxS64doDivide,          // convert figure into cycles
  6307.   instrLd, 0x32,              // move result into register 3 (minGoodRPMcycles)
  6308.   instrDone
  6309. };
  6310.  
  6311. const uint8_t prgmFindInjResetDelay[] PROGMEM = {
  6312.   instrLdIndex, 0,            // divide by 256 to generate timer2 cycles
  6313.   instrShiftRight, 0x02,
  6314.   instrAddToIndex, 1,
  6315.   instrSkipIfIndexBelow, 249, 8,
  6316.   instrLdByte, 0x01, 2,           // add 2 to result
  6317.   instrAddYtoX, 0x21,           // register 2 (injResetDelay)
  6318.   instrDone
  6319. };
  6320.  
  6321. const uint8_t prgmFindMaxGoodInjCycles[] PROGMEM = {
  6322.   instrLd, 0x23,              // load register 2 with contents of register 3
  6323.   instrLdByte, 0x01, 80,            // multiply minGoodRPMcycles figure by 0.8
  6324.   instrCall, idxS64doMultiply,
  6325.   instrLdByte, 0x01, 100,
  6326.   instrJump, idxS64doDivide,          // (maxGoodInjCycles)
  6327. };
  6328.  
  6329. #ifdef useBarFuelEconVsTime
  6330. const uint8_t prgmFindFEvsTimePeriod[] PROGMEM = {
  6331.   instrLdByte, 0x01, loopsPerSecond,
  6332.   instrLdEEPROM, 0x02, pFEvsTimeIdx,
  6333.   instrJump, idxS64doMultiply,
  6334. };
  6335.  
  6336. #endif
  6337. #ifdef useWindowFilter
  6338. uint8_t windowFilterIdx = 0;
  6339. uint8_t windowFilterCount = 0;
  6340.  
  6341. void resetWindowFilter(void)
  6342. {
  6343.  
  6344.   tripArray[(unsigned int)(windowFilterSumIdx)].reset();
  6345.   windowFilterCount = 0;
  6346.   windowFilterIdx = 0;
  6347.  
  6348. }
  6349.  
  6350. #endif
  6351. void initGuino(void) // initialize all the parameters
  6352. {
  6353.  
  6354.   uint8_t injDirection;
  6355.  
  6356.   vssPause = (uint8_t)eepromReadVal((unsigned int)(pVSSpauseIdx));
  6357.   metricFlag = (uint8_t)eepromReadVal((unsigned int)(pMetricFlagIdx));
  6358.   ignoreChar = (metricFlag ? '{' : '\\');
  6359.   printChar = ignoreChar ^ ('{' ^ '\\');
  6360.  
  6361. #ifdef useWindowFilter
  6362.   resetWindowFilter();
  6363.  
  6364. #endif
  6365.   cli(); // disable interrupts while messing with fuel injector settings
  6366.  
  6367. #ifdef useChryslerMAPCorrection
  6368.  
  6369.   for (uint8_t x = 0; x < 2; x++)
  6370.   {
  6371.  
  6372.     analogFloor[(unsigned int)(x)] = SWEET64(prgmConvertVolts, 0);
  6373.     analogSlope[(unsigned int)(x)] = SWEET64(prgmGenerateVoltageSlope, x);
  6374.     analogOffset[(unsigned int)(x)] = eepromReadVal((unsigned int)(pMAPsensorOffsetIdx + x));
  6375.  
  6376.   }
  6377.  
  6378.   pressure[(unsigned int)fuelPressureIdx] = eepromReadVal((unsigned int)(pSysFuelPressureIdx)); // this is in psig * 1000
  6379.   pressure[(unsigned int)injCorrectionIdx] = 4096;
  6380.  
  6381. #endif
  6382.  
  6383.   dirty &= ~(dirtyGoodInj | dirtyInjOpenRead); // reset fuel injector capture mechanism
  6384.  
  6385. #ifdef ArduinoMega2560
  6386.   EIMSK &= ~((1 << INT5) | (1 << INT4)); // disable fuel injector sense interrupts
  6387.  
  6388.   EICRB |= ((1 << ISC51) | (1 << ISC50) | (1 << ISC41) | (1 << ISC40)); // set injector sense pin control
  6389.   EICRB &= ~(1 << (eepromReadVal((unsigned int)(pInjEdgeTriggerIdx)) ? ISC50 : ISC40));
  6390.  
  6391.   EIFR |= ((1 << INTF5) | (1 << INTF4)); // clear fuel injector sense flag
  6392.   EIMSK |= ((1 << INT5) | (1 << INT4)); // enable fuel injector sense interrupts
  6393. #else
  6394.   EIMSK &= ~((1 << INT1) | (1 << INT0)); // disable fuel injector sense interrupts
  6395.  
  6396.   EICRA |= ((1 << ISC11) | (1 << ISC10) | (1 << ISC01) | (1 << ISC00)); // set injector sense pin control
  6397.   EICRA &= ~(1 << (eepromReadVal((unsigned int)(pInjEdgeTriggerIdx)) ? ISC10 : ISC00));
  6398.  
  6399.   EIFR |= ((1 << INTF1) | (1 << INTF0)); // clear fuel injector sense flag
  6400.   EIMSK |= ((1 << INT1) | (1 << INT0)); // enable fuel injector sense interrupts
  6401. #endif
  6402.  
  6403.   // convert seconds into cycles
  6404.   sleepTicks = SWEET64(prgmFindSleepTicks, 0);
  6405.   // convert microseconds into timer2 clock cycles
  6406.   injSettleCycles =  SWEET64(prgmConvertInjSettleTime, 0);
  6407.   // minimum time that consecutive injector open pulses must be received
  6408.   minGoodRPMcycles = SWEET64(prgmFindMinGoodRPM, 0);
  6409.   // used by main timer to timeout any long pending injector reads
  6410.   injResetDelay = SWEET64(prgmFindInjResetDelay, 0);
  6411.   // maximum time that injector may be open (should be 0.8 times the minimum good RPM time)
  6412.   maxGoodInjCycles = SWEET64(prgmFindMaxGoodInjCycles, 0);
  6413.  
  6414.   sei(); // re-enable interrupts
  6415.  
  6416. #ifdef useBarFuelEconVsTime
  6417.   bFEvTperiod = (unsigned int)SWEET64(prgmFindFEvsTimePeriod, 0);
  6418.   doResetBarFEvT();
  6419. #endif
  6420.  
  6421. }
  6422.  
  6423. void delay2(unsigned int ms)
  6424. {
  6425.  
  6426.   timerDelayCount = ms; // request a set number of timer tick delays per millisecond
  6427.   timerCommand |= tcDoDelay; // signal request to timer
  6428.   while (timerCommand & tcDoDelay);
  6429.  
  6430. }
  6431.  
  6432. #ifdef useSerialPortDataLogging
  6433. const uint8_t errorSerialConflict = 1; // cannot have both Parallax LCD and serial data logging enabled
  6434.  
  6435. const uint8_t dataLogInstr[] PROGMEM = {
  6436. (instantIdx << dfBitShift) | tFuelEcon,       // average fuel economy  for the past loop
  6437. (instantIdx << dfBitShift) | tSpeed,        // average vehicle speed for the past loop
  6438. (instantIdx << dfBitShift) | tInjectorOpenTime,   // fuel injector raw open time for the past loop
  6439. (instantIdx << dfBitShift) | tInjectorPulseCount, // fuel injector pulse count for the past loop
  6440. (instantIdx << dfBitShift) | tVSSpulseCount,    // vss pulse count for the past loop
  6441. };
  6442.  
  6443. const uint8_t dLIcount = (sizeof(dataLogInstr) / sizeof(uint8_t));
  6444.  
  6445. void doOutputDataLog(void)
  6446. {
  6447.  
  6448.   uint8_t c = ',';
  6449.  
  6450.   for (uint8_t x = 0; x < dLIcount; x++)
  6451.   {
  6452.  
  6453.     if ((x + 1) == dLIcount) c = '\n';
  6454.  
  6455.     simpletx(doFormat(pgm_read_byte(&dataLogInstr[(unsigned int)(x)]), dispRaw));
  6456.     pushSerialCharacter(c);
  6457.  
  6458.   }
  6459.  
  6460. }
  6461.  
  6462. void simpletx(char * str)
  6463. {
  6464.  
  6465.   while (*str) pushSerialCharacter(*str++);
  6466.  
  6467. }
  6468. #endif
  6469.  
  6470. #ifdef useSerialPort
  6471. void pushSerialCharacter(uint8_t chr)
  6472. {
  6473.  
  6474. #ifdef useBufferedSerialPort
  6475.  
  6476.   serialBuffer.push(chr);
  6477.  
  6478. #else
  6479.   if (UCSR0B != (1 << TXEN0)) UCSR0B = (1 << TXEN0); // if serial output is not yet enabled, enable it
  6480.  
  6481.   while (!(UCSR0A & (1 << UDRE0))); // wait until transmit buffer is empty
  6482.  
  6483.   UDR0 = chr; //send the data
  6484. #endif
  6485.  
  6486. }
  6487.  
  6488. #ifdef useBufferedSerialPort
  6489. void serialTransmitEnable(void)
  6490. {
  6491.  
  6492.   UCSR0B = ((1 << TXEN0) | (1 << UDRIE0)); // Enable transmitter and interrupt
  6493.  
  6494. }
  6495.  
  6496. void serialTransmitDisable(void)
  6497. {
  6498.  
  6499.   UCSR0B = 0; // Disable transmitter and interrupt
  6500.  
  6501. }
  6502.  
  6503. void serialTransmitByte(uint8_t s)
  6504. {
  6505.  
  6506.   UDR0 = s; // Transmit a byte
  6507.  
  6508. }
  6509.  
  6510. #endif
  6511. #endif
  6512.  
  6513. /* Display cursor update section */
  6514.  
  6515. void doCursorMoveAbsolute(uint8_t i, uint8_t j)
  6516. {
  6517. #ifdef useScreenEditor
  6518.  
  6519.   if (menuLevel == screenEditIdx) doSaveScreen();
  6520. #endif
  6521.  
  6522.   menuLevel = i;
  6523.   if (pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][2]) > j) screenCursor[(unsigned int)(menuLevel)] = j;
  6524.  
  6525.   callFuncPointer(&screenParameters[(unsigned int)(menuLevel)][4]);
  6526.  
  6527. }
  6528.  
  6529. void doCursorMoveRelative(uint8_t i, uint8_t j)
  6530. {
  6531.  
  6532.   uint8_t k = 0;
  6533.   uint8_t v;
  6534.   uint8_t w = pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][1]);
  6535.   uint8_t x = pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][0]);
  6536.   uint8_t y = menuLevel - x;
  6537.   uint8_t z = pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][2]);
  6538. #ifdef useScreenEditor
  6539.  
  6540.   if (menuLevel == screenEditIdx) doSaveScreen();
  6541. #endif
  6542.  
  6543.   if (j)
  6544.   {
  6545.  
  6546.     v = screenCursor[(unsigned int)(menuLevel)] + j;
  6547.  
  6548.     if (v == z)
  6549.     {
  6550.  
  6551.       v = 0;
  6552.       i = j;
  6553.       k = 1;
  6554.  
  6555.     }
  6556.     else if (v > z)
  6557.     {
  6558.  
  6559.       v = z - 1;
  6560.       i = j;
  6561.       k = 1;
  6562.  
  6563.     }
  6564.  
  6565.     screenCursor[(unsigned int)(menuLevel)] = v;
  6566.  
  6567.   }
  6568.  
  6569.   if (i)
  6570.   {
  6571.  
  6572.     y += i;
  6573.  
  6574.     if (y == w) y = 0;
  6575.     if (y > w) y = w - 1;
  6576.     menuLevel = y + x;
  6577.  
  6578.     if (k)
  6579.     {
  6580.  
  6581.       if (i == 1) v = 0;
  6582.       else v = pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][2]) - 1;
  6583.  
  6584.       screenCursor[(unsigned int)(menuLevel)] = v;
  6585.  
  6586.     }
  6587.  
  6588.   }
  6589.  
  6590.   doRefreshDisplay(); // call the appropriate display routine
  6591.   callFuncPointer(&screenParameters[(unsigned int)(menuLevel)][4]);
  6592.  
  6593. }
  6594.  
  6595. void doRefreshDisplay(void)
  6596. {
  6597.  
  6598.   gotoXY(0, 0);
  6599.   callFuncPointer(&screenParameters[(unsigned int)(menuLevel)][3]);
  6600.  
  6601. }
  6602.  
  6603. void doNothing(void)
  6604. {
  6605. }
  6606.  
  6607. void doNothing2(uint8_t s)
  6608. {
  6609. }
  6610.  
  6611. void noSupport(void)
  6612. {
  6613.  
  6614.   initStatusLine();
  6615.   printFlash(PSTR("Btn "));
  6616.   print(itoa((unsigned int)(buttonState), mBuff1, 10));
  6617.   printFlash(PSTR(" Pressed"));
  6618.   execStatusLine();
  6619.  
  6620. }
  6621.  
  6622. const uint8_t calcLabelCGRAM[] PROGMEM = {
  6623.   0b00000000,   // clock
  6624.   0b00000000,
  6625.   0b00000000,
  6626.   0b00000000,
  6627.   0b00000011,
  6628.   0b00000100,
  6629.   0b00000100,
  6630.   0b00000011,
  6631.  
  6632.   0b00100000,
  6633.   0b01000000,
  6634.   0b01100000,
  6635.   0b00000000,
  6636.   0b00010100,
  6637.   0b00010101,
  6638.   0b00010110,
  6639.   0b00010101,
  6640.  
  6641.   0b00010010,   // microseconds
  6642.   0b00010010,
  6643.   0b00010010,
  6644.   0b00011110,
  6645.   0b00010000,
  6646.   0b00110000,
  6647.   0b01000000,
  6648.   0b01100000,
  6649.  
  6650.   0b00001110,
  6651.   0b00010000,
  6652.   0b00001100,
  6653.   0b00000010,
  6654.   0b00011100,
  6655.   0b00000000,
  6656.   0b00000000,
  6657.   0b00000000,
  6658.  
  6659.   0b00000000,   // pulse count
  6660.   0b00000000,
  6661.   0b00000000,
  6662.   0b00000000,
  6663.   0b00000011,
  6664.   0b00000100,
  6665.   0b00000100,
  6666.   0b00000011,
  6667.  
  6668.   0b00100000,
  6669.   0b01000000,
  6670.   0b01100000,
  6671.   0b00000000,
  6672.   0b00001000,
  6673.   0b00011100,
  6674.   0b00001000,
  6675.   0b00001000,
  6676.  
  6677.   0b00001100,   // revolutions per minute
  6678.   0b00010000,
  6679.   0b00010001,
  6680.   0b00010010,
  6681.   0b00000100,
  6682.   0b00001000,
  6683.   0b00000000,
  6684.   0b00000000,
  6685.  
  6686.   0b00100000,
  6687.   0b01000000,
  6688.   0b01100000,
  6689.   0b00000000,
  6690.   0b00000000,
  6691.   0b00011011,
  6692.   0b00010101,
  6693.   0b00010101,
  6694.  
  6695.   0b00011011,   // miles per gallon
  6696.   0b00010101,
  6697.   0b00010101,
  6698.   0b00000000,
  6699.   0b00000001,
  6700.   0b00000010,
  6701.   0b00000100,
  6702.   0b00001000,
  6703.  
  6704.   0b00100000,
  6705.   0b01000000,
  6706.   0b01100000,
  6707.   0b00000000,
  6708.   0b00001100,
  6709.   0b00010000,
  6710.   0b00010100,
  6711.   0b00001100,
  6712.  
  6713.   0b00010000,   // liters per 100 km
  6714.   0b00010000,
  6715.   0b00011001,
  6716.   0b00000010,
  6717.   0b00000100,
  6718.   0b00001001,
  6719.   0b00000001,
  6720.   0b00000001,
  6721.  
  6722.   0b00100000,
  6723.   0b01000000,
  6724.   0b01100000,
  6725.   0b00000000,
  6726.   0b00000000,
  6727.   0b00011111,
  6728.   0b00010101,
  6729.   0b00011111,
  6730.  
  6731.   0b00000000,   // miles
  6732.   0b00000000,
  6733.   0b00000000,
  6734.   0b00000000,
  6735.   0b00010001,
  6736.   0b00011011,
  6737.   0b00010101,
  6738.   0b00010101,
  6739.  
  6740.   0b00100000,
  6741.   0b01000000,
  6742.   0b01100000,
  6743.   0b00000000,
  6744.   0b00010000,
  6745.   0b00000000,
  6746.   0b00010000,
  6747.   0b00010000,
  6748.  
  6749.   0b00000000,   // kilometers
  6750.   0b00000000,
  6751.   0b00000000,
  6752.   0b00000000,
  6753.   0b00000100,
  6754.   0b00000101,
  6755.   0b00000110,
  6756.   0b00000101,
  6757.  
  6758.   0b00100000,
  6759.   0b01000000,
  6760.   0b01100000,
  6761.   0b00000000,
  6762.   0b00000000,
  6763.   0b00001010,
  6764.   0b00010101,
  6765.   0b00010101,
  6766.  
  6767.   0b00011011,   // miles per hour
  6768.   0b00010101,
  6769.   0b00010101,
  6770.   0b00000000,
  6771.   0b00000110,
  6772.   0b00000101,
  6773.   0b00000110,
  6774.   0b00000100,
  6775.  
  6776.   0b00100000,
  6777.   0b01000000,
  6778.   0b01100000,
  6779.   0b00000000,
  6780.   0b00010100,
  6781.   0b00011100,
  6782.   0b00010100,
  6783.   0b00010100,
  6784.  
  6785.   0b00010000,   // kilometers per hour
  6786.   0b00010100,
  6787.   0b00011000,
  6788.   0b00010100,
  6789.   0b00000001,
  6790.   0b00000010,
  6791.   0b00000100,
  6792.   0b00001000,
  6793.  
  6794.   0b00100000,
  6795.   0b01000000,
  6796.   0b01100000,
  6797.   0b00000000,
  6798.   0b00010000,
  6799.   0b00010000,
  6800.   0b00011100,
  6801.   0b00010100,
  6802.  
  6803.   0b00000000,   // gallons
  6804.   0b00000000,
  6805.   0b00000000,
  6806.   0b00000000,
  6807.   0b00000011,
  6808.   0b00000100,
  6809.   0b00000101,
  6810.   0b00000011,
  6811.  
  6812.   0b00100000,
  6813.   0b01000000,
  6814.   0b01100000,
  6815.   0b00000000,
  6816.   0b00000001,
  6817.   0b00000001,
  6818.   0b00011001,
  6819.   0b00011101,
  6820.  
  6821.   0b00000000,   // liters
  6822.   0b00000000,
  6823.   0b00000000,
  6824.   0b00000000,
  6825.   0b00000100,
  6826.   0b00000100,
  6827.   0b00000100,
  6828.   0b00000111,
  6829.  
  6830.   0b00100000,
  6831.   0b01000000,
  6832.   0b01100000,
  6833.   0b00000000,
  6834.   0b00000000,
  6835.   0b00000000,
  6836.   0b00000000,
  6837.   0b00000000,
  6838.  
  6839.   0b00001100,   // gallons per hour
  6840.   0b00010000,
  6841.   0b00010100,
  6842.   0b00001100,
  6843.   0b00000001,
  6844.   0b00000010,
  6845.   0b00000100,
  6846.   0b00001000,
  6847.  
  6848.   0b00100000,
  6849.   0b01000000,
  6850.   0b01100000,
  6851.   0b00000000,
  6852.   0b00010000,
  6853.   0b00010000,
  6854.   0b00011100,
  6855.   0b00010100,
  6856.  
  6857.   0b00010000,   // liters per hour
  6858.   0b00010000,
  6859.   0b00010000,
  6860.   0b00011100,
  6861.   0b00000001,
  6862.   0b00000010,
  6863.   0b00000100,
  6864.   0b00001000,
  6865.  
  6866.   0b00100000,
  6867.   0b01000000,
  6868.   0b01100000,
  6869.   0b00000000,
  6870.   0b00010000,
  6871.   0b00010000,
  6872.   0b00011100,
  6873.   0b00010100,
  6874. #ifdef useFuelCost
  6875.  
  6876.   0b00100000,   // fuel cost
  6877.   0b01000000,
  6878.   0b01100000,
  6879.   0b00000000,
  6880.   0b00001100,
  6881.   0b00010000,
  6882.   0b00010000,
  6883.   0b00001100,
  6884.  
  6885.   0b00000010,
  6886.   0b00000101,
  6887.   0b00000100,
  6888.   0b00001110,
  6889.   0b00000100,
  6890.   0b00000100,
  6891.   0b00000100,
  6892.   0b00000100,
  6893.  
  6894.   0b00001100,   // fuel cost rate
  6895.   0b00010000,
  6896.   0b00010000,
  6897.   0b00001100,
  6898.   0b00000001,
  6899.   0b00000010,
  6900.   0b00000100,
  6901.   0b00001000,
  6902.  
  6903.   0b00100000,
  6904.   0b01000000,
  6905.   0b01100000,
  6906.   0b00000000,
  6907.   0b00010000,
  6908.   0b00010000,
  6909.   0b00011100,
  6910.   0b00010100,
  6911.  
  6912.   0b00001100,   // fuel cost per mile
  6913.   0b00010000,
  6914.   0b00010000,
  6915.   0b00001100,
  6916.   0b00000001,
  6917.   0b00000010,
  6918.   0b00000100,
  6919.   0b00001000,
  6920.  
  6921.   0b00100000,
  6922.   0b01000000,
  6923.   0b01100000,
  6924.   0b00000000,
  6925.   0b00010001,
  6926.   0b00011011,
  6927.   0b00010101,
  6928.   0b00010101,
  6929.  
  6930.   0b00001100,   // fuel cost per kilometer
  6931.   0b00010000,
  6932.   0b00010000,
  6933.   0b00001100,
  6934.   0b00000001,
  6935.   0b00000010,
  6936.   0b00000100,
  6937.   0b00001000,
  6938.  
  6939.   0b00100000,
  6940.   0b01000000,
  6941.   0b01100000,
  6942.   0b00000000,
  6943.   0b00010000,
  6944.   0b00010100,
  6945.   0b00011000,
  6946.   0b00010100,
  6947.  
  6948.   0b00011011,   // mile per unit fuel cost
  6949.   0b00010101,
  6950.   0b00010101,
  6951.   0b00000000,
  6952.   0b00000001,
  6953.   0b00000010,
  6954.   0b00000100,
  6955.   0b00001000,
  6956.  
  6957.   0b00100000,
  6958.   0b01000000,
  6959.   0b01100000,
  6960.   0b00000000,
  6961.   0b00001100,
  6962.   0b00010000,
  6963.   0b00010000,
  6964.   0b00001100,
  6965.  
  6966.   0b00010000,   // kilometer per unit fuel cost
  6967.   0b00010100,
  6968.   0b00011000,
  6969.   0b00010100,
  6970.   0b00000001,
  6971.   0b00000010,
  6972.   0b00000100,
  6973.   0b00001000,
  6974.  
  6975.   0b00100000,
  6976.   0b01000000,
  6977.   0b01100000,
  6978.   0b00000000,
  6979.   0b00001100,
  6980.   0b00010000,
  6981.   0b00010000,
  6982.   0b00001100,
  6983. #endif
  6984. #ifdef useAnalogRead
  6985.  
  6986.   0b00010001,   // voltage
  6987.   0b00010001,
  6988.   0b00010001,
  6989.   0b00001010,
  6990.   0b00000100,
  6991.   0b00000000,
  6992.   0b00000000,
  6993.   0b00000000,
  6994.  
  6995.   0b00000000,
  6996.   0b00000000,
  6997.   0b00000000,
  6998.   0b00000000,
  6999.   0b00010001,
  7000.   0b00011010,
  7001.   0b00011010,
  7002.   0b00010001,
  7003. #endif
  7004. #ifdef useChryslerMAPCorrection
  7005.  
  7006.   0b00001110,   // psi
  7007.   0b00001001,
  7008.   0b00001001,
  7009.   0b00001110,
  7010.   0b00001000,
  7011.   0b00001000,
  7012.   0b00001000,
  7013.   0b00000000,
  7014.  
  7015.   0b00001001,
  7016.   0b00010101,
  7017.   0b00010001,
  7018.   0b00001001,
  7019.   0b00000101,
  7020.   0b00010101,
  7021.   0b00001001,
  7022.   0b00000000,
  7023.  
  7024.   0b00001000,   // kPa
  7025.   0b00001000,
  7026.   0b00001001,
  7027.   0b00001010,
  7028.   0b00001100,
  7029.   0b00001010,
  7030.   0b00001001,
  7031.   0b00000000,
  7032.  
  7033.   0b00011000,
  7034.   0b00010100,
  7035.   0b00010100,
  7036.   0b00011000,
  7037.   0b00010010,
  7038.   0b00010101,
  7039.   0b00010011,
  7040.   0b00000000,
  7041.  
  7042.   0b00000000,   // correction factor
  7043.   0b00000000,
  7044.   0b00000000,
  7045.   0b00000000,
  7046.   0b00000000,
  7047.   0b00000000,
  7048.   0b00000000,
  7049.   0b00000000,
  7050.  
  7051.   0b00000000,
  7052.   0b00000000,
  7053.   0b00000000,
  7054.   0b00000000,
  7055.   0b00000000,
  7056.   0b00000000,
  7057.   0b00000000,
  7058.   0b00000000,
  7059. #endif
  7060. };
  7061.  
  7062. const uint8_t calcLabelTrip[] PROGMEM = {
  7063.   0b00000000,
  7064.   0b00000000,
  7065.   0b00000000,
  7066.   0b00000000,
  7067.  
  7068.   0b00000011,
  7069.   0b00000111,
  7070.   0b00000011,
  7071.   0b00000111,
  7072.  
  7073.   0b00000100,
  7074.   0b00000010,
  7075.   0b00000100,
  7076.   0b00000010,
  7077.  
  7078.   0b00000100,
  7079.   0b00000111,
  7080.   0b00000011,
  7081.   0b00000010,
  7082. };
  7083.  
  7084. void displayMainScreenFunction(uint8_t readingIdx, uint8_t k, uint8_t functBlink, uint8_t tripBlink)
  7085. {
  7086.  
  7087.   readingIdx &= 3;
  7088.   uint8_t x = (readingIdx & 1) << 3;
  7089.   uint8_t y = (readingIdx & 2) >> 1;
  7090.   uint8_t z = readingIdx << 1;
  7091.  
  7092.   uint8_t r = (k & dfTripMask) >> dfBitShift;
  7093.   uint8_t f = k & dfValMask;
  7094.  
  7095.   uint8_t j = pgm_read_byte(&calcLabelIdx[(unsigned int)(f)]);
  7096.   if ((j & 128) && (metricFlag)) j += 2;
  7097.   j &= 127;
  7098.  
  7099.   writeCGRAMlabelChar(z, j, r, functBlink, tripBlink);
  7100.   writeCGRAMlabelChar(z + 1, j + 1, r, functBlink, tripBlink);
  7101.  
  7102.   gotoXY(x, y);
  7103.   print(doFormat(k, 0));
  7104.   charOut(8 + z);
  7105.   charOut(9 + z);
  7106.  
  7107. }
  7108.  
  7109. void writeCGRAMlabelChar(uint8_t cgChar, uint8_t functIdx, uint8_t tripIdx, uint8_t functBlink, uint8_t tripBlink)
  7110. {
  7111.  
  7112.   uint8_t i = 0x1F;
  7113.   uint8_t j = 0x1F;
  7114.   unsigned int k = (unsigned int)(functIdx << 3);
  7115.   if (timerHeartBeat & tripBlink) j = 0; // determine if trip label component should blink or not
  7116.   if (timerHeartBeat & functBlink) i = 0; // determine if function label component should blink or not
  7117.   tripIdx &= 3; // strip off unnecessary bits of trip index
  7118.  
  7119.   for (uint8_t x = 0; x < 8; x++)
  7120.   {
  7121.  
  7122.      uint8_t l = pgm_read_byte(&calcLabelCGRAM[(unsigned int)(k++)]); // read a byte of function label bit pattern
  7123.      uint8_t m = l >> 3; // fetch partial address of trip label component
  7124.      m &= 0b00001100; // strip off un-needed bits
  7125.      m |= tripIdx; // combine with trip index to form full address of trip label component
  7126.      m = pgm_read_byte(&calcLabelTrip[(unsigned int)(m)]); // read a byte of trip label bit pattern
  7127.      l &= i; // provide for blinking function label component
  7128.      m &= j; // provide for blinking trip label component
  7129.      mBuff1[(unsigned int)(x)] = l | m; // combine trip label and function label components
  7130.  
  7131.   }
  7132.  
  7133.   cgramMode = 0; // reset CGRAM mode
  7134.   LCD::loadCGRAMcharacter(cgChar, (const char *)(mBuff1), 0); // write out generated CGRAM character
  7135.  
  7136. }
  7137.  
  7138. /* Main screen section */
  7139.  
  7140. const char mainScreenFuncNames[] PROGMEM = {
  7141.   "1 Instrument\0"
  7142.   "2 Custom\0"
  7143. #ifdef useChryslerMAPCorrection
  7144.   "Pressures\0"
  7145. #endif
  7146. #ifdef useAnalogRead
  7147.   "Voltages\0"
  7148. #endif
  7149.   "3 Instant/Current\0"
  7150.   "4 Instant/Tank\0"
  7151.   "5 Current\0"
  7152.   "6 Tank\0"
  7153. #ifdef trackIdleEOCdata
  7154.   "7 EOC/Idle\0"
  7155. #endif
  7156.   "8 Tank Data\0"
  7157.   "9 Current Data\0"
  7158. #ifdef trackIdleEOCdata
  7159.   "10 Tank EOC/Idle\0"
  7160.   "11 Current EOC/Idle\0"
  7161. #endif
  7162.   "12 Remaining\0"
  7163. };
  7164.  
  7165. void doCursorUpdateMain(void)
  7166. {
  7167.  
  7168.   printStatusMessage(findStr(mainScreenFuncNames, screenCursor[(unsigned int)(mainScreenIdx)])); // briefly display screen name
  7169.  
  7170. }
  7171.  
  7172. void doMainScreenDisplay(void)
  7173. {
  7174.  
  7175.   uint8_t i = screenCursor[(unsigned int)(mainScreenIdx)];
  7176.  
  7177.   i <<= 2;
  7178.  
  7179.   for (uint8_t x = 0; x < 4; x++)
  7180.   {
  7181.  
  7182. #ifdef useScreenEditor
  7183.     uint8_t k = displayFormats[(unsigned int)(i++)];
  7184. #else
  7185.     uint8_t k = pgm_read_byte(&displayFormats[(unsigned int)(i++)]);
  7186. #endif
  7187.     displayMainScreenFunction(x, k, 0, 136);
  7188.  
  7189.   }
  7190.  
  7191. }
  7192.  
  7193. void doNextBright(void)
  7194. {
  7195.  
  7196.   brightnessIdx++;
  7197.   if (brightnessIdx >= brightnessLength) brightnessIdx = 0;
  7198.   LCD::setBright(brightnessIdx);
  7199.  
  7200.   initStatusLine();
  7201.   printFlash(PSTR("Backlight = "));
  7202.   printStr(brightString, brightnessIdx);
  7203.   execStatusLine();
  7204.  
  7205. }
  7206.  
  7207. void doLongGoLeft(void)
  7208. {
  7209.  
  7210.   doCursorMoveRelative(255, 0);
  7211.  
  7212. }
  7213.  
  7214. void doLongGoRight(void)
  7215. {
  7216.  
  7217.   doCursorMoveRelative(1, 0);
  7218.  
  7219. }
  7220.  
  7221. void doTripResetTank(void)
  7222. {
  7223.  
  7224.   tripArray[(unsigned int)(tankIdx)].reset();
  7225. #ifdef trackIdleEOCdata
  7226.   tripArray[(unsigned int)(eocIdleTankIdx)].reset();
  7227. #endif
  7228. #ifdef useBarFuelEconVsSpeed
  7229.   doResetBarFEvS();
  7230. #endif
  7231.   printStatusMessage(PSTR("Tank Reset"));
  7232.  
  7233. }
  7234.  
  7235. void doTripResetCurrent(void)
  7236. {
  7237.  
  7238.   tripArray[(unsigned int)(currentIdx)].reset();
  7239. #ifdef trackIdleEOCdata
  7240.   tripArray[(unsigned int)(eocIdleCurrentIdx)].reset();
  7241. #endif
  7242.   printStatusMessage(PSTR("Current Reset"));
  7243.  
  7244. }
  7245.  
  7246. /* Setting selector section */
  7247.  
  7248. void doCursorUpdateSetting(void)
  7249. {
  7250.  
  7251.   paramPtr = screenCursor[(unsigned int)(settingScreenIdx)] + (uint8_t)(eePtrSettingsStart);
  7252.   doParamRevert();
  7253.  
  7254. }
  7255.  
  7256. void doSettingEditDisplay(void)
  7257. {
  7258.  
  7259.   printStr(parmLabels, screenCursor[(unsigned int)(settingScreenIdx)]); // print parameter name at top left
  7260.   clrEOL();
  7261.   gotoXY(0, 1); // go to next line
  7262.   print(pBuff);
  7263.   clrEOL();
  7264.  
  7265. }
  7266.  
  7267. void doGoSettingsEdit(void)
  7268. {
  7269.  
  7270.   prevMenuLevel = menuLevel;
  7271.   doCursorMoveAbsolute(settingScreenIdx, 0);
  7272.  
  7273. }
  7274.  
  7275. void doReturnToMain(void)
  7276. {
  7277.  
  7278.   menuLevel = prevMenuLevel;
  7279.  
  7280. }
  7281.  
  7282. /* Individual parameter editor section */
  7283.  
  7284. void doParamEditDisplay(void)
  7285. {
  7286.  
  7287.   printStr(parmLabels, screenCursor[(unsigned int)(settingScreenIdx)]); // print parameter name at top left
  7288.   clrEOL();
  7289.   gotoXY(0, 1); // go to next line
  7290.  
  7291.   uint8_t c = pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])]; // save existing character
  7292.   if ((timerHeartBeat & 0b01010101) && (screenCursor[(unsigned int)(paramScreenIdx)] < 10)) pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])] = '_'; // replace character with an underscore
  7293.   print(pBuff); // print number
  7294.   pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])] = c;
  7295.  
  7296.   blinkFlash(&paramButtonChars[0], (screenCursor[(unsigned int)(paramScreenIdx)] == 10));
  7297.   blinkFlash(&paramButtonChars[4], (screenCursor[(unsigned int)(paramScreenIdx)] == 11));
  7298.  
  7299. }
  7300.  
  7301. void doGoParamEdit(void)
  7302. {
  7303.  
  7304.   paramLength = pgm_read_byte(&paramsLength[(unsigned int)(screenCursor[(unsigned int)(settingScreenIdx)])]);
  7305.   paramMaxValue = (1 << paramLength);
  7306.   paramMaxValue -= 1;
  7307.  
  7308.   menuLevel = paramScreenIdx;
  7309.   format64(prgmFormatToNumber, paramMaxValue, mBuff2, 3);
  7310.   doParamFindLeft();
  7311.  
  7312. }
  7313.  
  7314. void doParamExit(void)
  7315. {
  7316.  
  7317.   doParamRevert();
  7318.   generalMenuLevelReturn(PSTR("Param Reverted"), settingScreenIdx);
  7319.  
  7320. }
  7321.  
  7322. #ifdef useCalculatedFuelFactor
  7323. const uint8_t prgmCalculateFuelFactor[] PROGMEM = {
  7324.   instrLdConst, 0x02, idxCorrFactor,
  7325.   instrLdEEPROM, 0x01, pSysFuelPressureIdx,
  7326.   instrCall, idxS64doMultiply,
  7327.   instrLdEEPROM, 0x01, pRefFuelPressureIdx,
  7328.   instrCall, idxS64doDivide,
  7329.   instrIsqrt, 0x02,
  7330.   instrLdEEPROM, 0x01, pInjectorCountIdx,
  7331.   instrCall, idxS64doMultiply,
  7332.   instrLdEEPROM, 0x01, pInjectorSizeIdx,
  7333.   instrCall, idxS64doMultiply,
  7334.   instrSkipIfMetricMode, 10,
  7335.  
  7336.   instrLdConst, 0x01, idxNumerVolume,
  7337.   instrCall, idxS64doMultiply,
  7338.   instrLdConst, 0x01, idxDenomVolume,
  7339.   instrCall, idxS64doDivide,
  7340.  
  7341.   instrSwap, 0x23,
  7342.   instrLdByte, 0x02, 60,                // load seconds per minute into register 2
  7343.   instrLdConst, 0x01, idxMicroSecondsPerSecond,
  7344.   instrCall, idxS64doMultiply,
  7345.   instrLdConst, 0x01, idxDecimalPoint,
  7346.   instrCall, idxS64doMultiply,
  7347.   instrLdConst, 0x01, idxCorrFactor,
  7348.   instrCall, idxS64doMultiply,
  7349.   instrSwap, 0x13,
  7350.   instrCall, idxS64doDivide,
  7351.   instrStEEPROM, 0x02, pMicroSecondsPerQuantityIdx,
  7352.   instrDone
  7353. };
  7354. #endif
  7355.  
  7356. const uint8_t prgmDoEEPROMmetricConversion[] PROGMEM = {
  7357.   instrTraceOn,
  7358.   instrLdIndex, 0,
  7359.  
  7360.   instrLdEEPROMindirect, 0x02,
  7361.  
  7362.   instrSkipIfMetricMode, 6,
  7363.   instrLdNumer, 0x01,
  7364.   instrLdDenom, 0x03,
  7365.   instrSkip, 4,
  7366.  
  7367.   instrLdNumer, 0x03,
  7368.   instrLdDenom, 0x01,
  7369.  
  7370.   instrCall, idxS64doMultiply,
  7371.   instrSwap, 0x31,
  7372.   instrCall, idxS64doDivide,
  7373.   instrCall, idxS64doAdjust,
  7374.   instrStEEPROMindirect, 0x02,
  7375.   instrAddToIndex, 1,
  7376.   instrSkipIfIndexBelow, 227, convSize,
  7377.  
  7378.   instrDone
  7379. };
  7380.  
  7381. void doParamSave(void)
  7382. {
  7383.  
  7384.   uint8_t t;
  7385.  
  7386.   if (eepromWriteVal((unsigned int)(paramPtr), rformat())) // if the setting has changed
  7387.   {
  7388.  
  7389. #ifdef useBarFuelEconVsSpeed
  7390.     if ((paramPtr == pBarLowSpeedCutoffIdx) || (paramPtr == pBarSpeedQuantumIdx)) doResetBarFEvS();
  7391. #endif
  7392.  
  7393.     if (paramPtr == pMetricFlagIdx) SWEET64(prgmDoEEPROMmetricConversion, 0); // if metric flag has changed
  7394.  
  7395. #ifdef useCalculatedFuelFactor
  7396.     // if fuel pressure, reference pressure, injector count, or injector size changed
  7397.     if ((paramPtr == pSysFuelPressureIdx) || (paramPtr == pRefFuelPressureIdx) || (paramPtr == pInjectorCountIdx) || (paramPtr == pInjectorSizeIdx))
  7398.       SWEET64(prgmCalculateFuelFactor, 0); // calculate and store microseconds per gallon factor
  7399. #endif
  7400.  
  7401.     initGuino(); // reconfigure system based on changed settings
  7402.     generalMenuLevelReturn(PSTR("Param Changed"), settingScreenIdx);
  7403.  
  7404.   }
  7405.   else generalMenuLevelReturn(PSTR("Param Unchanged"), settingScreenIdx);
  7406.  
  7407. }
  7408.  
  7409. void generalMenuLevelReturn(const char * s, uint8_t newMenuLevel)
  7410. {
  7411.  
  7412.   menuLevel = newMenuLevel;
  7413.   printStatusMessage(s);
  7414.  
  7415. }
  7416.  
  7417. void printStatusMessage(const char * s)
  7418. {
  7419.  
  7420.   initStatusLine();
  7421.   printFlash(s);
  7422.   execStatusLine();
  7423.  
  7424. }
  7425.  
  7426. void doParamFindLeft(void)
  7427. {
  7428.  
  7429.   screenCursor[(unsigned int)(paramScreenIdx)] = 9;
  7430.  
  7431.   // do a nice thing and put the edit cursor at the first non zero number
  7432.   for (uint8_t x = 9; x < 10; x--) if (pBuff[(unsigned int)(x)] != ' ') screenCursor[(unsigned int)(paramScreenIdx)] = x;
  7433.  
  7434. }
  7435.  
  7436. void doParamFindRight(void)
  7437. {
  7438.  
  7439.   screenCursor[(unsigned int)(paramScreenIdx)] = 9;
  7440.  
  7441. }
  7442.  
  7443. void doParamStoreMax(void)
  7444. {
  7445.  
  7446.   doParamStoreNumber(paramMaxValue);
  7447.  
  7448. }
  7449.  
  7450. void doParamStoreMin(void)
  7451. {
  7452.  
  7453.   doParamStoreNumber(0);
  7454.  
  7455. }
  7456.  
  7457. void doParamRevert(void)
  7458. {
  7459.  
  7460.   doParamStoreNumber(eepromReadVal((unsigned int)(paramPtr)));
  7461.  
  7462. }
  7463.  
  7464. void doParamStoreNumber(unsigned long v)
  7465. {
  7466.  
  7467.   format64(prgmFormatToNumber, v, pBuff, 3);
  7468. #ifdef useLegacyLCD
  7469.   if (paramPtr == pContrastIdx) LCD::setContrast((uint8_t)(v)); // adjust contrast dynamically
  7470. #endif
  7471.   doParamFindLeft();
  7472.  
  7473. }
  7474.  
  7475. void doParamReformat(void)
  7476. {
  7477.  
  7478.   uint8_t c = '0';
  7479.   uint8_t d = ' ';
  7480.  
  7481.   for (uint8_t x = 0; x < 9; x++)
  7482.   {
  7483.  
  7484.     if (pBuff[(unsigned int)(x)] == c) pBuff[(unsigned int)(x)] = d;
  7485.     else if ((c == '0') && (pBuff[(unsigned int)(x)] != ' '))
  7486.     {
  7487.  
  7488.       c = ' ';
  7489.       d = '0';
  7490.  
  7491.     }
  7492.  
  7493.   }
  7494.  
  7495.   if (pBuff[9] == ' ') pBuff[9] = '0';
  7496.  
  7497. }
  7498.  
  7499. void doParamChangeDigit(void)
  7500. {
  7501.  
  7502.   uint8_t w;
  7503.  
  7504.   if (screenCursor[(unsigned int)(paramScreenIdx)] == 10) doParamSave();
  7505.   else if (screenCursor[(unsigned int)(paramScreenIdx)] == 11) doParamExit();
  7506.   else
  7507.   {
  7508.  
  7509.     if (paramLength == 1) pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])] ^= 1;
  7510.     else
  7511.     {
  7512.  
  7513.       w = pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])]; // fetch digit from stored numeric string representing parameter to be changed
  7514.       if (w == ' ') w = '0'; // if this is a leading space, use 0 as working digit
  7515.       w++; // adjust working digit
  7516.       if (w > '9') w = '0'; // handle working digit rollover
  7517.  
  7518.       pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])] = w;
  7519.       doParamReformat();
  7520.  
  7521.       for (uint8_t x = 0; x < 10; x++)
  7522.       {
  7523.  
  7524.         if (pBuff[(unsigned int)(x)] < mBuff2[(unsigned int)(x)]) x = 10;
  7525.         else if (pBuff[(unsigned int)(x)] > mBuff2[(unsigned int)(x)])
  7526.         {
  7527.  
  7528.           x = 10;
  7529.           pBuff[(unsigned int)(screenCursor[(unsigned int)(paramScreenIdx)])] = '0';
  7530.           doParamReformat();
  7531.  
  7532.         }
  7533.  
  7534.       }
  7535.  
  7536. #ifdef useLegacyLCD
  7537.       if (paramPtr == pContrastIdx) LCD::setContrast((uint8_t)(rformat())); // adjust contrast dynamically
  7538. #endif
  7539.  
  7540.     }
  7541.  
  7542.   }
  7543.  
  7544. }
  7545.  
  7546. #ifdef useBigFE // large Fuel Economy display support section
  7547. void doCursorUpdateBigFEscreen(void)
  7548. {
  7549.  
  7550.   displayBigStatus(bigFEscreenIdx, PSTR(" Fuel Econ"));
  7551.  
  7552. }
  7553.  
  7554. void doBigFEdisplay(void)
  7555. {
  7556.  
  7557.   uint8_t dIdx = fedSelect(bigFEscreenIdx);
  7558.  
  7559.         displayBigNumber(doFormat(dIdx, tFuelEcon, dispFE));
  7560.  
  7561.   printStr(bigFEDispChars, dIdx);
  7562.   gotoXY(12, 1);
  7563.   printFlash(PSTR("{MPG \\L100}"));
  7564.  
  7565. }
  7566.  
  7567. #endif
  7568. #ifdef useBigDTE // large Distance-To-Empty display support section
  7569. void doCursorUpdateBigDTEscreen(void)
  7570. {
  7571.  
  7572.   displayBigStatus(bigDTEscreenIdx, PSTR(" DistToEmpty"));
  7573.  
  7574. }
  7575.  
  7576. void doBigDTEdisplay(void)
  7577. {
  7578.  
  7579.         displayBigNumber(doFormat(fedSelect(bigDTEscreenIdx), tDistanceToEmpty, dispDTE));
  7580.  
  7581. }
  7582.  
  7583. #endif
  7584. #ifdef useBigTTE // large Time-To-Empty display support section
  7585. void doCursorUpdateBigTTEscreen(void)
  7586. {
  7587.  
  7588.     displayBigStatus(bigTTEscreenIdx, PSTR(" TimeToEmpty"));
  7589.  
  7590. }
  7591.  
  7592. void doBigTTEdisplay(void)
  7593. {
  7594.  
  7595.   displayBigTime(format64(prgmFormatToTime, SWEET64(prgmTimeToEmpty, fedSelect(bigTTEscreenIdx)), mBuff1, 3), 4);
  7596.  
  7597. }
  7598.  
  7599. #endif
  7600. #ifdef useClock // Clock support section
  7601. void doCursorUpdateSystemTimeScreen(void)
  7602. {
  7603.  
  7604.   printStatusMessage(PSTR("System Time"));
  7605.  
  7606. }
  7607.  
  7608. void doDisplaySystemTime(void) // display system time
  7609. {
  7610.  
  7611.   displayBigTime(format64(prgmFormatToTime, convertTime(outputCycles), mBuff1, 3), 4);
  7612.  
  7613. }
  7614.  
  7615. void doGoEditSystemTime(void)
  7616. {
  7617.  
  7618.   format64(prgmFormatToTime, convertTime(outputCycles), pBuff, 3); // convert system time from ticks into seconds, and format for output
  7619.   doCursorMoveAbsolute(systemTimeEditScreenIdx, 0);
  7620.  
  7621. }
  7622.  
  7623. void doEditSystemTimeDisplay(void)
  7624. {
  7625.  
  7626.   displayBigTime(pBuff, screenCursor[(unsigned int)(systemTimeEditScreenIdx)]);
  7627.  
  7628. }
  7629.  
  7630. void doEditSystemTimeChangeDigit(void)
  7631. {
  7632.  
  7633.   pBuff[(unsigned int)(screenCursor[(unsigned int)(systemTimeEditScreenIdx)])]++;
  7634.   if (pBuff[(unsigned int)(screenCursor[(unsigned int)(systemTimeEditScreenIdx)])] > '9') pBuff[(unsigned int)(screenCursor[(unsigned int)(systemTimeEditScreenIdx)])] = '0';
  7635.  
  7636.   if (pBuff[2] > '5') pBuff[2] = '0'; // this will only happen if systemTimeEditScreenIdx == 2
  7637.   if ((pBuff[0] == '2') && (pBuff[1] > '3')) pBuff[1] = '0'; // this will only happen if systemTimeEditScreenIdx == 0 or 1
  7638.   if (pBuff[0] > '2') pBuff[0] = '0'; // this will only happen if systemTimeEditScreenIdx == 0
  7639.  
  7640. }
  7641.  
  7642. const uint8_t prgmConvertToCycles[] PROGMEM = {
  7643.   instrLdConst, 0x01, idxCyclesPerSecond,
  7644.   instrCall, idxS64doDivide,
  7645.   instrLdConst, 0x01, idxSecondsPerDay,
  7646.   instrCall, idxS64doDivide,
  7647.  
  7648.   instrLdIndex, 0,
  7649.   instrLdByte, 0x01, 24,
  7650.   instrCall, idxS64doMultiply,
  7651.   instrLdByteFromYindexed, 0x13,
  7652.   instrAddYtoX, 0x21,
  7653.  
  7654.   instrLdIndex, 2,
  7655.   instrLdByte, 0x01, 60,
  7656.   instrCall, idxS64doMultiply,
  7657.   instrLdByteFromYindexed, 0x13,
  7658.   instrAddYtoX, 0x21,
  7659.  
  7660.   instrLdIndex, 4,
  7661.   instrLdByte, 0x01, 60,
  7662.   instrCall, idxS64doMultiply,
  7663.   instrLdByteFromYindexed, 0x13,
  7664.   instrAddYtoX, 0x21,
  7665.  
  7666.   instrLdConst, 0x01, idxCyclesPerSecond,
  7667.   instrJump, idxS64doMultiply,
  7668. };
  7669.  
  7670. void doEditSystemTimeSave(void)
  7671. {
  7672.  
  7673.   uint8_t b;
  7674.  
  7675.   pBuff[4] = '0';
  7676.   pBuff[5] = '0';
  7677.  
  7678.   copy64(tempPtr[1], (union union_64 *)&outputCycles);
  7679.  
  7680.   for (uint8_t x = 4; x < 6; x -= 2)
  7681.   {
  7682.  
  7683.     b = pBuff[(unsigned int)(x)] - '0';
  7684.     b *= 10;
  7685.     b += pBuff[(unsigned int)(x + 1)] - '0';
  7686.     tempPtr[2]->u8[(unsigned int)(x)] = b;
  7687.  
  7688.   }
  7689.  
  7690.   SWEET64(prgmConvertToCycles, 0); // convert time into timer2 clock cycles
  7691.  
  7692.   cli();
  7693.   copy64((union union_64 *)&clockCycles, tempPtr[1]);
  7694.   sei();
  7695.  
  7696.   generalMenuLevelReturn(PSTR("Time Set"), systemTimeDisplayScreenIdx);
  7697.  
  7698. }
  7699.  
  7700. void doEditSystemTimeCancel(void)
  7701. {
  7702.  
  7703.   generalMenuLevelReturn(PSTR("Time NOT Set"), systemTimeDisplayScreenIdx);
  7704.  
  7705. }
  7706.  
  7707. #endif
  7708. #ifdef useBarFuelEconVsSpeed // (parameter) vs. Speed Bar Graph display section
  7709. uint8_t FEvSpdTripIdx;
  7710.  
  7711. void doCursorUpdateBarFEvS(void)
  7712. {
  7713.  
  7714.   uint8_t b = pgm_read_byte(&barFEvSdisplayFuncs[(unsigned int)(screenCursor[(unsigned int)(barFEvSscreenIdx)])]);
  7715.  
  7716.   for (uint8_t x = 0; x < bgDataSize; x++) barGraphData[(unsigned int)(bgDataSize - x - 1)] = doCalculate(b, (x + FEvsSpeedIdx));
  7717.  
  7718.   printStatusMessage(findStr(barFEvSfuncNames, screenCursor[(unsigned int)(barFEvSscreenIdx)])); // briefly display screen name
  7719.  
  7720. }
  7721.  
  7722. void doBarFEvSdisplay(void)
  7723. {
  7724.  
  7725.   uint8_t b = pgm_read_byte(&barFEvSdisplayFuncs[(unsigned int)(screenCursor[(unsigned int)(barFEvSscreenIdx)])]);
  7726.  
  7727.   if (FEvSpdTripIdx < 255) barGraphData[(unsigned int)(bgDataSize + FEvsSpeedIdx - FEvSpdTripIdx - 1)] = doCalculate(b, FEvSpdTripIdx);
  7728.  
  7729.   formatBarGraph(bgDataSize, (FEvSpdTripIdx - FEvsSpeedIdx), 0, doCalculate(b, tankIdx));
  7730.  
  7731.   displayBarGraph(FEvSpdTripIdx, b, ((timerHeartBeat & 0b00110011) ? tankIdx : instantIdx), ((timerHeartBeat & 0b00110011) ? b : tSpeed));
  7732.  
  7733. }
  7734.  
  7735. void doResetBarFEvS(void)
  7736. {
  7737.  
  7738.   for (uint8_t x = 0; x < bgDataSize; x++) tripArray[(unsigned int)(x + FEvsSpeedIdx)].reset();
  7739.  
  7740. }
  7741.  
  7742. #endif
  7743. #ifdef useBarFuelEconVsTime // Differential/Absolute Fuel Economy vs. Time display section
  7744. void doResetBarFEvT(void)
  7745. {
  7746.  
  7747.   tripArray[(unsigned int)(periodIdx)].reset();
  7748.   bFEvTcount = 0;
  7749.   bFEvTstartIDx = 0;
  7750.   bFEvTsize = 0;
  7751.  
  7752. }
  7753.  
  7754. void doCursorUpdateBarFEvT(void)
  7755. {
  7756.  
  7757.   printStatusMessage(findStr(barFEvTfuncNames, screenCursor[(unsigned int)(barFEvTscreenIdx)])); // briefly display screen name
  7758.  
  7759. }
  7760.  
  7761. void doBarFEvTdisplay(void)
  7762. {
  7763.  
  7764.   uint8_t i = 0;
  7765.   uint8_t j = bFEvTstartIDx;
  7766.   unsigned long v = doCalculate(tFuelEcon, currentIdx);
  7767.  
  7768.   while (i < bFEvTsize)
  7769.   {
  7770.  
  7771.     if (j == 0) j = bgDataSize;
  7772.     j--;
  7773.  
  7774.     barGraphData[(unsigned int)(i)] = barFEvsTimeData[(unsigned int)(j)];
  7775.     i++;
  7776.  
  7777.   }
  7778.  
  7779.   formatBarGraph(bFEvTsize, (bgDataSize - 1), ((screenCursor[(unsigned int)(barFEvTscreenIdx)]) ? 0 : v), v);
  7780.  
  7781.   displayBarGraph(currentIdx, tFuelEcon, periodIdx, tFuelEcon);
  7782.  
  7783. }
  7784.  
  7785. #endif
  7786. #ifdef useCPUreading // System utilization display section
  7787. void doDisplaySystemInfo(void) // display max cpu utilization and RAM
  7788. {
  7789.  
  7790.   unsigned int i = (unsigned int)(&i);
  7791.   unsigned long t[2];
  7792.  
  7793.   if ((unsigned int) __brkval == 0) i -= (unsigned int)(&__bss_end);
  7794.   else i -= (unsigned int)(__brkval);
  7795.  
  7796.   unsigned long mem = (unsigned long)i;
  7797.   mem *= 1000;
  7798.  
  7799.   cli(); // perform atomic transfer of clock to main program
  7800.  
  7801.   t[0] = systemCycles[0]; // perform atomic transfer of system time to main program
  7802.   t[1] = systemCycles[1];
  7803.  
  7804.   sei();
  7805.  
  7806.   displayCPUutil();
  7807.   printFlash(PSTR(" T"));
  7808.   print(format64(prgmFormatToTime, convertTime(t), mBuff1, 3));
  7809.   gotoXY(0, 1);
  7810.   printFlash(PSTR(" FREE MEM:"));
  7811.   print(format(mem, 0));
  7812.  
  7813. }
  7814.  
  7815. const uint8_t prgmFindCPUutilPercent[] PROGMEM = {
  7816.   instrLdConst, 0x01, idxNumerCPUutil,
  7817.   instrCall, idxS64doMultiply,
  7818.   instrLdConst, 0x01, idxDenomCPUutil,
  7819.   instrJump, idxS64doDivide,
  7820. };
  7821.  
  7822. void displayCPUutil(void)
  7823. {
  7824.  
  7825.   printFlash(PSTR("C%"));
  7826.   init64(tempPtr[1], timerLoopLength);
  7827.   print(format(SWEET64(prgmFindCPUutilPercent, 0), 2));
  7828.  
  7829. }
  7830.  
  7831. void doShowCPU(void)
  7832. {
  7833.  
  7834.   initStatusLine();
  7835.   displayCPUutil();
  7836.   execStatusLine();
  7837.  
  7838. }
  7839.  
  7840. #ifdef useBenchMark
  7841. const uint8_t prgmBenchMarkTime[] PROGMEM = {
  7842.   instrJump, idxS64doConvertToMicroSeconds,
  7843. };
  7844.  
  7845. void doBenchMark(void)
  7846. {
  7847.  
  7848.   unsigned long t = 0;
  7849.   unsigned long w;
  7850.   unsigned long s;
  7851.   unsigned long e;
  7852.  
  7853.   unsigned long c;
  7854.  
  7855.   cli(); // disable interrupts
  7856.  
  7857.   while (!(TIFR2 & (1 << TOV2))); // wait for timer2 to overflow
  7858.   TIFR2 |= (1 << TOV2); // reset timer2 overflow flag
  7859.  
  7860. #ifdef TinkerkitLCDmodule
  7861.   s = TCNT0; // do a microSeconds() - like read to determine loop length in cycles
  7862. #else
  7863.   s = TCNT2; // do a microSeconds() - like read to determine loop length in cycles
  7864. #endif
  7865.  
  7866.   for (unsigned int x = 0; x < 1000; x++)
  7867.   {
  7868.  
  7869.     if (TIFR2 & (1 << TOV2))
  7870.     {
  7871.  
  7872.       t += 256ul;
  7873.       TIFR2 |= (1 << TOV2);
  7874.  
  7875.     }
  7876.  
  7877.     c = (unsigned long)iSqrt((unsigned int)(s));
  7878. //    readMAP();
  7879. //    c = s * pressure[(unsigned int)(injCorrectionIdx)];
  7880. //    c >>= 12;
  7881.  
  7882.   }
  7883.  
  7884. #ifdef TinkerkitLCDmodule
  7885.   e = TCNT0; // do a microSeconds() - like read to determine loop length in cycles
  7886.   if (TIFR0 & (1 << TOV0))
  7887. #else
  7888.   e = TCNT2; // do a microSeconds() - like read to determine loop length in cycles
  7889.   if (TIFR2 & (1 << TOV2))
  7890. #endif
  7891.   {
  7892.  
  7893. #ifdef TinkerkitLCDmodule
  7894.     e = TCNT0;
  7895.     TIFR0 |= (1 << TOV0);
  7896. #else
  7897.     e = TCNT2;
  7898.     TIFR2 |= (1 << TOV2);
  7899. #endif
  7900.     t += 256;
  7901.  
  7902.   }
  7903.  
  7904.   e += t;
  7905.  
  7906.   sei();
  7907.  
  7908.   w = findCycleLength(s, e) - 156;
  7909.  
  7910.   init64(tempPtr[1], w);
  7911.  
  7912.   initStatusLine();
  7913.   print(format(SWEET64(prgmBenchMarkTime, 0), 3));
  7914.   printFlash(PSTR(" usec"));
  7915.   execStatusLine();
  7916.  
  7917. }
  7918.  
  7919. #endif
  7920. #endif
  7921. #ifdef useEEPROMviewer
  7922. void doEEPROMviewDisplay(void)
  7923. {
  7924.  
  7925.   print(format64(prgmFormatToNumber, (unsigned long)(screenCursor[(unsigned int)(eepromViewIdx)]), mBuff1, 3));
  7926.   clrEOL();
  7927.   gotoXY(0, 1);
  7928.   print(format64(prgmFormatToNumber, eepromReadVal((unsigned int)(screenCursor[(unsigned int)(eepromViewIdx)])), mBuff1, 3));
  7929.   clrEOL();
  7930.  
  7931. }
  7932.  
  7933. void goEEPROMview(void)
  7934. {
  7935.  
  7936.   prevMenuLevel = menuLevel;
  7937.   doCursorMoveAbsolute(eepromViewIdx, 255);
  7938.  
  7939. }
  7940.  
  7941. #endif
  7942. #ifdef useSavedTrips // Trip save/restore/raw data view support section
  7943. void doCursorUpdateTripShow(void)
  7944. {
  7945.  
  7946.   paramPtr = (uint8_t)(getBaseTripPointer(tripShowSlot)) + screenCursor[(unsigned int)(tripShowScreenIdx)];
  7947.   doParamRevert();
  7948.  
  7949. }
  7950.  
  7951. void doTripSaveDisplay(void)
  7952. {
  7953.  
  7954.   unsigned int t = getBaseTripPointer(tripShowSlot);
  7955.   uint8_t b = (uint8_t)(eepromReadVal((unsigned int)(t + tripListSigPointer)));
  7956.   uint8_t i = screenCursor[(unsigned int)(tripSaveScreenIdx)];
  7957.   uint8_t j;
  7958.  
  7959.   if (i == tslCount) j = tslSubSize;
  7960.   else
  7961.   {
  7962.  
  7963.     j = i;
  7964.     i /= tslSubSize;
  7965.     j -= i * tslSubSize;
  7966.  
  7967.     i = pgm_read_byte(&tripSelectList[(unsigned int)(i)]);
  7968.  
  7969.   }
  7970.  
  7971.   printStr(tripNames, j); // print trip function name at top left
  7972.   if (j < tslSubSize) printStr(bigFEDispChars, i);
  7973.   clrEOL();
  7974.   gotoXY(0, 1); // go to next line
  7975.  
  7976.   charOut('0' + tripShowSlot);
  7977.   charOut(':');
  7978.  
  7979.   if (b == guinosig) print(format64(prgmFormatToTime, eepromReadVal(t), mBuff1, 3));
  7980.   else printFlash(PSTR("Empty"));
  7981.  
  7982.   clrEOL();
  7983.  
  7984. }
  7985.  
  7986. void doTripShowDisplay(void)
  7987. {
  7988.  
  7989.   charOut('0' + tripShowSlot);
  7990.   charOut(':');
  7991.  
  7992.   uint8_t b = screenCursor[(unsigned int)(tripShowScreenIdx)];
  7993.  
  7994.   if (b > 16) b -= 1;
  7995.   else if (b > 3) b = b / 2 + 2;
  7996.  
  7997.   printStr(ertvNames, b);
  7998.  
  7999.   charOut(' ');
  8000.   charOut(76 - 4 * (screenCursor[(unsigned int)(tripShowScreenIdx)] & 1));
  8001.  
  8002.   clrEOL();
  8003.   gotoXY(0, 1); // go to next line
  8004.   print(pBuff);
  8005.   clrEOL();
  8006.  
  8007. }
  8008.  
  8009. void doGoTripTank(void)
  8010. {
  8011.  
  8012.   goSavedTrip(0);
  8013.  
  8014. }
  8015.  
  8016. void doGoTripCurrent(void)
  8017. {
  8018.  
  8019.   goSavedTrip(1);
  8020.  
  8021. }
  8022.  
  8023. void goSavedTrip(uint8_t tripSlot)
  8024. {
  8025.  
  8026.   tripShowSlot = tripSlot;
  8027.   prevMenuLevel = menuLevel;
  8028.   doCursorMoveAbsolute(tripSaveScreenIdx, tripSlot * tslSubSize);
  8029.  
  8030. }
  8031.  
  8032. void doTripSelect(void)
  8033. {
  8034.  
  8035.   goTripSelect(0);
  8036.  
  8037. }
  8038.  
  8039. void doTripLongSelect(void)
  8040. {
  8041.  
  8042.   goTripSelect(1);
  8043.  
  8044. }
  8045.  
  8046. void goTripSelect(uint8_t pressFlag)
  8047. {
  8048.  
  8049.   uint8_t i = screenCursor[(unsigned int)tripSaveScreenIdx];
  8050.   uint8_t j;
  8051.  
  8052.   if (i == tslCount) doCursorMoveAbsolute(tripShowScreenIdx, 0);
  8053.   else
  8054.   {
  8055.  
  8056.     j = i;
  8057.     i /= tslSubSize;
  8058.     j -= i * tslSubSize;
  8059.  
  8060.     if ((j == 0) && (pressFlag == 0)) doCursorMoveAbsolute(prevMenuLevel, i + tripScreenIdxBase);
  8061.     else
  8062.     {
  8063.  
  8064.       i = pgm_read_byte(&tripSelectList[(unsigned int)(i)]);
  8065.  
  8066.       if ((j == 1) && (pressFlag == 1)) doTripSave(i);
  8067.       else if ((j == 2) && (pressFlag == 1)) doTripLoad(i);
  8068.       else if ((j == 3) && (pressFlag == 0)) doTripReset(i);
  8069.       else doTripBumpSlot();
  8070.  
  8071.     }
  8072.  
  8073.   }
  8074.  
  8075. }
  8076.  
  8077. void doTripSave(uint8_t tripIdx)
  8078. {
  8079.  
  8080.   tripArray[(unsigned int)(tripIdx)].save(tripShowSlot);
  8081.   doTripPrintType(tripIdx);
  8082.   printFlash(PSTR(" Save"));
  8083.  
  8084. }
  8085.  
  8086. void doTripLoad(uint8_t tripIdx)
  8087. {
  8088.  
  8089.   tripArray[(unsigned int)(tripIdx)].load(tripShowSlot);
  8090.   doMainScreenDisplay();
  8091.   gotoXY(0, 0);
  8092.   doTripPrintType(tripIdx);
  8093.   printFlash(PSTR(" Load"));
  8094.   menuLevel = mainScreenIdx;
  8095.  
  8096. }
  8097.  
  8098. const uint8_t autoSaveInstr[] PROGMEM = {
  8099.   pAutoSaveActiveIdx,
  8100.   pAutoSaveActiveIdx,
  8101. #ifdef trackIdleEOCdata
  8102.   pAutoSaveIdleIdx,
  8103.   pAutoSaveIdleIdx,
  8104. #endif
  8105. };
  8106.  
  8107. uint8_t doTripAutoAction(uint8_t taaMode)
  8108. {
  8109.  
  8110.   uint8_t b;
  8111.   uint8_t c = 0;
  8112.  
  8113.   for (uint8_t x = 0; x < tslSize; x++)
  8114.   {
  8115.  
  8116.     if (eepromReadVal((unsigned int)(pgm_read_byte(&autoSaveInstr[(unsigned int)(x)]))))
  8117.     {
  8118.  
  8119.       b = pgm_read_byte(&tripSelectList[(unsigned int)(x)]);
  8120.  
  8121.       if (taaMode) c += tripArray[(unsigned int)(b)].load(x);
  8122.       else c += tripArray[(unsigned int)(b)].save(x);
  8123.  
  8124.     }
  8125.  
  8126.   }
  8127.  
  8128.   return c;
  8129.  
  8130. }
  8131.  
  8132. void doTripReset(uint8_t tripIdx)
  8133. {
  8134.  
  8135.   tripArray[(unsigned int)tripIdx].reset();
  8136.   doTripPrintType(tripIdx);
  8137.   printFlash(PSTR(" Reset"));
  8138.  
  8139. }
  8140.  
  8141. void doTripPrintType(uint8_t tripIdx)
  8142. {
  8143.  
  8144.   printStr(bigFEDispChars, tripIdx);
  8145.   printFlash(PSTR(" Trip "));
  8146.   charOut('0' + tripShowSlot);
  8147.  
  8148. }
  8149.  
  8150. void doTripBumpSlot(void)
  8151. {
  8152.  
  8153.   tripShowSlot++;
  8154.   if (tripShowSlot == eeAdrSavedTripsTemp3) tripShowSlot = 0;
  8155.  
  8156. }
  8157.  
  8158. void doTripShowCancel(void)
  8159. {
  8160.  
  8161.   menuLevel = tripSaveScreenIdx;
  8162.  
  8163. }
  8164.  
  8165. #endif
  8166. #ifdef useScreenEditor // Programmable main display screen edit support section
  8167.  
  8168. uint8_t screenEditValue = 0;
  8169.  
  8170. void doCursorUpdateScreenEdit(void)
  8171. {
  8172.  
  8173.   uint8_t b = screenCursor[(unsigned int)(screenEditIdx)] >> 1;
  8174.  
  8175.   screenEditValue = displayFormats[(unsigned int)(b)] & dfValMask;
  8176.   paramLength = (displayFormats[(unsigned int)(b)] & dfTripMask) >> dfBitShift;
  8177.  
  8178. }
  8179.  
  8180. void doScreenEditDisplay(void)
  8181. {
  8182.  
  8183.   uint8_t i = screenCursor[(unsigned int)(screenEditIdx)];
  8184.   uint8_t j = i;
  8185.   i >>= 1;
  8186.   uint8_t k = i;
  8187.   uint8_t l;
  8188.   uint8_t m;
  8189.   uint8_t n;
  8190.  
  8191.   i &= 0xFC;
  8192.   j &= 0x01;
  8193.   k &= 0x03;
  8194.  
  8195.   for (uint8_t x = 0; x < 4; x++)
  8196.   {
  8197.  
  8198.     l = displayFormats[(unsigned int)(i++)];
  8199.     m = 0;
  8200.     n = 0;
  8201.  
  8202.     if (x == k)
  8203.     {
  8204.  
  8205.         if (j == 1) m = 170;
  8206.       else n = 170;
  8207.  
  8208.       }
  8209.  
  8210.     displayMainScreenFunction(x, l, m, n);
  8211.  
  8212.   }
  8213.  
  8214. }
  8215.  
  8216. void doGoScreenEdit(void)
  8217. {
  8218.  
  8219.   prevMenuLevel = menuLevel;
  8220.   doCursorMoveAbsolute(screenEditIdx, screenCursor[(unsigned int)(mainScreenIdx)] * displayPageCount);
  8221.  
  8222. }
  8223.  
  8224. void doScreenEditReturnToMain(void)
  8225. {
  8226.  
  8227.   doSaveScreen();
  8228.   doReturnToMain();
  8229.  
  8230. }
  8231.  
  8232. void doScreenEditRevert(void)
  8233. {
  8234.  
  8235.   uint8_t b = screenCursor[(unsigned int)(screenEditIdx)] >> 1;
  8236.  
  8237.   paramPtr = (uint8_t)(eePtrScreensStart) + b;
  8238.   displayFormats[(unsigned int)(b)] = (uint8_t)(eepromReadVal((unsigned int)(paramPtr)));
  8239.  
  8240. }
  8241.  
  8242. void doScreenEditBump(void)
  8243. {
  8244.  
  8245.   uint8_t b = screenCursor[(unsigned int)(screenEditIdx)];
  8246.   uint8_t c = b;
  8247.   b &= 0x01;
  8248.   c >>= 1;
  8249.  
  8250.   if (b)
  8251.   {
  8252.  
  8253.     screenEditValue++;
  8254.     if (screenEditValue == dfMaxValDisplayCount) screenEditValue = 0;
  8255.  
  8256.   }
  8257.   else
  8258.   {
  8259.  
  8260.     paramLength++;
  8261.     if (paramLength == dfMaxTripCount) paramLength = 0;
  8262.  
  8263.   }
  8264.  
  8265.   displayFormats[(unsigned int)(c)] = (paramLength << dfBitShift) | screenEditValue;
  8266.  
  8267. }
  8268.  
  8269. void doSaveScreen(void)
  8270. {
  8271.  
  8272.   uint8_t b = screenCursor[(unsigned int)(screenEditIdx)] >> 1;
  8273.  
  8274.   paramPtr = (uint8_t)(eePtrScreensStart) + b;
  8275.   eepromWriteVal((unsigned int)(paramPtr), displayFormats[(unsigned int)(b)]);
  8276.  
  8277. }
  8278.  
  8279. #endif
  8280.  
  8281. uint8_t loadParams(void)
  8282. {
  8283.  
  8284.   uint8_t b = 1;
  8285.   uint8_t t;
  8286.  
  8287. #ifdef forceEEPROMsettingsInit
  8288.   if (true)
  8289. #else
  8290.   if (eepromReadVal((unsigned int)(eePtrSignature)) != newEEPROMsignature)
  8291. #endif
  8292.   {
  8293.  
  8294.     b = 0;
  8295.  
  8296.     eepromWriteVal((unsigned int)(eePtrSignature), newEEPROMsignature);
  8297.  
  8298.     t = eePtrSettingsStart;
  8299.     for (uint8_t x = 0; x < settingsSize; x++) eepromWriteVal((unsigned int)(t++), pgm_read_dword(&params[(unsigned int)(x)]));
  8300.  
  8301. #ifdef useScreenEditor
  8302.     t = eePtrScreensStart;
  8303.     for (uint8_t x = 0; x < displayFormatSize; x++) eepromWriteVal((unsigned int)(t++), (unsigned long)(displayFormats[(unsigned int)(x)]));
  8304.  
  8305. #endif
  8306. #ifdef useScreenEditor
  8307.  
  8308.   }
  8309.   else
  8310.   {
  8311.  
  8312.     t = eePtrScreensStart;
  8313.     for (uint8_t x = 0; x < displayFormatSize; x++) displayFormats[(unsigned int)(x)] = (uint8_t)(eepromReadVal((unsigned int)(t++)));
  8314. #endif
  8315.  
  8316.   }
  8317.  
  8318.   initGuino();
  8319.   return b;
  8320.  
  8321. }
  8322.  
  8323. uint8_t eepromWriteVal(unsigned int eePtr, unsigned long val)
  8324. {
  8325.  
  8326.   unsigned int t = eepromGetAddress(eePtr);
  8327.   uint8_t l;
  8328.   uint8_t w;
  8329.   uint8_t s = 0;
  8330.  
  8331.   l = (uint8_t)(t & 0x07);
  8332.   l++;
  8333.   t >>= 3;
  8334.   t += (unsigned int)(l);
  8335.  
  8336.   while (l > 0)
  8337.   {
  8338.  
  8339.     w = (uint8_t)(val & 0xFF);
  8340.     if (w != eeprom_read_byte((uint8_t *)(--t)))
  8341.     {
  8342.  
  8343.       eeprom_write_byte((uint8_t *)(t), w);
  8344.       s = 1;
  8345.  
  8346.     }
  8347.     val >>= 8;
  8348.     l--;
  8349.  
  8350.   }
  8351.  
  8352.   return s;
  8353.  
  8354. }
  8355.  
  8356. unsigned long eepromReadVal(unsigned int eePtr)
  8357. {
  8358.  
  8359.   unsigned int t = eepromGetAddress(eePtr);
  8360.  
  8361.   uint8_t l;
  8362.   unsigned long val = 0;
  8363.  
  8364.   l = (uint8_t)(t & 0x07);
  8365.   l++;
  8366.   t >>= 3;
  8367.  
  8368.   while (l > 0)
  8369.   {
  8370.  
  8371.     val <<= 8;
  8372.     val += (unsigned long)(eeprom_read_byte((uint8_t *)(t)));
  8373.     t++;
  8374.     l--;
  8375.  
  8376.   }
  8377.  
  8378.   return val;
  8379.  
  8380. }
  8381.  
  8382. unsigned int eepromGetAddress(unsigned int eePtr)
  8383. {
  8384.  
  8385.   unsigned int t;
  8386.   uint8_t l;
  8387.  
  8388.   if (eePtr == eePtrSignature)
  8389.   {
  8390.  
  8391.     t = (unsigned int)(eeAdrSignature);
  8392.     l = 3;
  8393.  
  8394.   }
  8395.   else if ((eePtr >= eePtrSettingsStart) && (eePtr < eePtrSettingsEnd))
  8396.   {
  8397.  
  8398.     eePtr -= eePtrSettingsStart;
  8399.     t = (unsigned int)(pgm_read_byte(&paramAddrs[eePtr]));
  8400.     l = pgm_read_byte(&paramAddrs[eePtr + 1]);
  8401.     l -= (uint8_t)(t);
  8402.  
  8403. #ifdef useScreenEditor
  8404.   }
  8405.   else if ((eePtr >= eePtrScreensStart) && (eePtr < eePtrScreensEnd))
  8406.   {
  8407.  
  8408.     eePtr -= eePtrScreensStart;
  8409.     l = 1;
  8410.     t = eePtr + eeAdrScreensStart;
  8411.  
  8412. #endif
  8413. #ifdef useSavedTrips
  8414.   }
  8415.   else if ((eePtr >= eePtrSavedTripsStart) && (eePtr < eePtrSavedTripsEnd))
  8416.   {
  8417.  
  8418.     eePtr -= eePtrSavedTripsStart;
  8419.     l = (uint8_t)(eePtr / tripListSize);
  8420.     eePtr -= (unsigned int)(l) * (unsigned int)(tripListSize);
  8421.  
  8422.     t = eeAdrSavedTripsStart + (unsigned int)(l) * (unsigned int)(eepromTripListSize);
  8423.  
  8424.     if ((eePtr > 0) && (eePtr < tripListSigPointer))
  8425.     {
  8426.  
  8427.       l = 4;
  8428.       t += 4 * (unsigned int)(eePtr - 1);
  8429.       t++;
  8430.  
  8431.     }
  8432.     else
  8433.     {
  8434.  
  8435.       if (eePtr > 0) t += (unsigned int)(eepromTripListSize - 1);
  8436.       l = 1;
  8437.  
  8438.     }
  8439. #endif
  8440.  
  8441.   }
  8442.   else
  8443.   {
  8444.  
  8445.     l = 0;
  8446.     t = 0;
  8447.  
  8448.   }
  8449.  
  8450.   t <<= 3;
  8451.   l--;
  8452.   t += (unsigned int)(l);
  8453.  
  8454.   return t;
  8455.  
  8456. }
  8457.  
  8458. void callFuncPointer(const uint8_t * funcIdx)
  8459. {
  8460.  
  8461.   pFunc mainFunc = (pFunc)pgm_read_word(&funcPointers[(unsigned int)(pgm_read_byte(funcIdx))]); // go perform action
  8462.   mainFunc();
  8463.  
  8464. }
  8465.  
  8466. unsigned long cycles2(void)
  8467. {
  8468.  
  8469.   unsigned long t;
  8470.  
  8471.   uint8_t oldSREG = SREG; // save state of interrupt flag
  8472.  
  8473.   cli(); // disable interrupts
  8474. #ifdef TinkerkitLCDmodule
  8475.   t = timer2_overflow_count + TCNT0; // do a microSeconds() - like read to determine loop length in cycles
  8476.   if (TIFR0 & (1 << TOV0)) t = timer2_overflow_count + 256 + TCNT0; // if overflow occurred, re-read with overflow flag taken into account
  8477. #else
  8478.   t = timer2_overflow_count + TCNT2; // do a microSeconds() - like read to determine loop length in cycles
  8479.   if (TIFR2 & (1 << TOV2)) t = timer2_overflow_count + 256 + TCNT2; // if overflow occurred, re-read with overflow flag taken into account
  8480. #endif
  8481.   SREG = oldSREG; // restore state of interrupt flag
  8482.  
  8483.   return t;
  8484.  
  8485. }
  8486.  
  8487. unsigned long findCycleLength(unsigned long lastCycle, unsigned long thisCycle)
  8488. {
  8489.  
  8490.   unsigned long t;
  8491.  
  8492.   if (thisCycle < lastCycle) t = 4294967295ul - lastCycle + thisCycle + 1;
  8493.   else t = thisCycle - lastCycle;
  8494.  
  8495.   return t;
  8496.  
  8497. }
  8498.  
  8499. int main(void)
  8500. {
  8501.  
  8502.   uint8_t i;
  8503.   uint8_t j;
  8504.  
  8505.   const uint8_t * bpPtr;
  8506.  
  8507.   cli(); // disable interrupts while interrupts are being fiddled with
  8508.  
  8509. #ifdef TinkerkitLCDmodule
  8510.   TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0)); // put timer 0 in 8-bit fast pwm mode
  8511.   TCCR0A |= ((1 << WGM01) | (1 << WGM00));
  8512.   TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B) | (1 << WGM02) | (1 << CS02)); // set timer 0 prescale factor to 64
  8513.   TCCR0B |= ((1 << CS01) | (1 << CS00));
  8514.   TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); // disable timer 0 output compare interrupts
  8515.   TIMSK0 |= (1 << TOIE0); // enable timer 0 overflow interrupt
  8516.   TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); // clear timer 0 interrupt flags
  8517. #else
  8518.   TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0) | (1 << COM2B1) | (1 << COM2B0)); // put timer 2 in 8-bit fast pwm mode
  8519.   TCCR2A |= ((1 << WGM21) | (1 << WGM20));
  8520.   TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B) | (1 << WGM22) | (1 << CS21) | (1 << CS20)); // set timer 2 prescale factor to 64
  8521.   TCCR2B |= (1 << CS22);
  8522.   TIMSK2 &= ~((1 << OCIE2B) | (1 << OCIE2A)); // disable timer 2 output compare interrupts
  8523.   TIMSK2 |= (1 << TOIE2); // enable timer 2 overflow interrupt
  8524.   TIFR2 |= ((1 << OCF2B) | (1 << OCF2A) | (1 << TOV2)); // clear timer 2 interrupt flags
  8525. #endif
  8526.  
  8527. #ifdef useAnalogInterrupt
  8528. #ifndef useAnalogRead
  8529.   ADMUX = (1 << REFS0); // set ADC voltage reference to AVCC, and right-adjust the ADC reading
  8530. #endif
  8531.    // enable ADC, enable ADC interrupt, clear any pending ADC interrupt, and set frequency to 1/128 of system timer
  8532.   ADCSRA = ((1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0));
  8533.   ADCSRB = 0; // disable analog comparator multiplexer, and set ADC auto trigger source to free-running mode
  8534. #ifdef useLegacyButtons
  8535.   DIDR0 = ((1 << ADC2D) | (1 << ADC1D)); // only enable digital input on VSS and button pins
  8536. #else
  8537. #ifdef TinkerkitLCDmodule
  8538.   DIDR0 = ((1 << ADC7D) | (1 << ADC6D) | (1 << ADC5D));
  8539.   DIDR2 = (1 << ADC10D);
  8540. #else
  8541.   DIDR0 = ((1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D)); // only enable digital input on VSS pin
  8542. #endif
  8543. #endif
  8544. #endif
  8545.  
  8546. #ifdef useSerialPort
  8547.   UBRR0H = (uint8_t)(myubbr >> 8); // set serial uart baud rate
  8548.   UBRR0L = (uint8_t)(myubbr);
  8549.   UCSR0A &= ~(1 << U2X0);
  8550.   UCSR0B = 0; // disable serial uart pins
  8551.   UCSR0C = (1 << UCSZ01)| (1 << UCSZ00); // set for 8 data bits, no parity, and 1 stop bit
  8552. #ifdef useBufferedSerialPort
  8553.   serialBuffer.init();
  8554.   serialBuffer.process = serialTransmitByte;
  8555.   serialBuffer.onEmpty = serialTransmitDisable;
  8556.   serialBuffer.onNoLongerEmpty = serialTransmitEnable;
  8557. #endif
  8558. #endif
  8559.  
  8560.   timer2_overflow_count = 0; // initialize timer 2 overflow counter
  8561.  
  8562. #ifdef useLegacyButtons
  8563. #ifdef ArduinoMega2560
  8564.   PORTK |= ((1 << PORTK5) | (1 << PORTK4) | (1 << PORTK3)); // enable port K button pullup resistors
  8565.   PCMSK2 |= ((1 << PCINT21) | (1 << PCINT20) | (1 << PCINT19) | (1 << PCINT16)); // enable port K button and VSS pin interrupts
  8566. #else
  8567.   PORTC |= ((1 << PORTC5) | (1 << PORTC4) | (1 << PORTC3)); // enable port C button pullup resistors
  8568.   PCMSK1 |= ((1 << PCINT13) | (1 << PCINT12) | (1 << PCINT11) | (1 << PCINT8)); // enable port C button and VSS pin interrupts
  8569. #endif
  8570. #else
  8571. #ifdef ArduinoMega2560
  8572.   PCMSK2 |= (1 << PCINT16); // enable port K VSS pin interrupt
  8573. #else
  8574. #ifdef TinkerkitLCDmodule
  8575.   PCMSK0 |= (1 << PCINT1); // enable port B VSS pin interrupt
  8576. #else
  8577.   PCMSK1 |= (1 << PCINT8); // enable port C VSS pin interrupt
  8578. #endif
  8579. #endif
  8580. #endif
  8581. #ifdef ArduinoMega2560
  8582.   PCICR |= (1 << PCIE2); // enable selected interrupts on port K
  8583. #else
  8584. #ifdef TinkerkitLCDmodule
  8585.   PCICR |= (1 << PCIE0); // enable selected interrupts on port ?
  8586. #else
  8587.   PCICR |= (1 << PCIE1); // enable selected interrupts on port C
  8588. #endif
  8589. #endif
  8590.  
  8591. #ifdef ArduinoMega2560
  8592.   lastPINKstate = PINK; // initialize last PINK state value so as to not erroneously detect a keypress on start
  8593. #else
  8594. #ifdef TinkerkitLCDmodule
  8595.   lastPINBstate = PINB; // initialize last PINB state value so as to not erroneously detect a keypress on start
  8596. #else
  8597.   lastPINCstate = PINC; // initialize last PINC state value so as to not erroneously detect a keypress on start
  8598. #endif
  8599. #endif
  8600.  
  8601.   for (uint8_t x = 0; x < tUDcount; x++) tripArray[(unsigned int)(pgm_read_byte(&tripUpdateDestList[(unsigned int)(x)]) & 0x7F)].reset();
  8602.  
  8603.   if (loadParams() != 1) doGoSettingsEdit(); // go through the initialization screen
  8604.  
  8605. #ifdef useAnalogRead
  8606.   timerCommand = tcWakeUp | tcResetADC;
  8607. #else
  8608.   timerCommand = tcWakeUp;
  8609. #endif
  8610.   timerStatus = tsButtonsUp;
  8611.   timerHeartBeat = 1;
  8612.   injResetCount = 0;
  8613.   vssResetCount = 0;
  8614.   buttonCount = 0;
  8615.   timerDelayCount = 0;
  8616.   dirty = 0;
  8617.  
  8618.   sei();
  8619.  
  8620.   LCD::init();
  8621.   gotoXY(0, 0);
  8622.   printFlash(PSTR("MPGuino v1.93tav"));
  8623.   gotoXY(0, 1);
  8624.   printFlash(PSTR("2015-MAY-20     "));
  8625.  
  8626.   delay2(delay1500ms); // show splash screen for 1.5 seconds
  8627.  
  8628. #ifdef useSavedTrips
  8629.   if (doTripAutoAction(1)) printStatusMessage(PSTR("AutoRestore Done"));
  8630. #endif
  8631.  
  8632.   while (true)
  8633.   {
  8634.    
  8635.     if (!(timerStatus & tsLoopExec)) // if not currently executing a cycle
  8636.     {
  8637.       PORTB |= (LEDred1);
  8638.       timerCommand |= tcStartLoop; // start a new cycle
  8639.       while (timerCommand & tcStartLoop);
  8640.  
  8641.       timerLoopStart = cycles2();
  8642.  
  8643. #ifdef useClock
  8644.       cli(); // perform atomic transfer of clock to main program
  8645.  
  8646.       copy64((union union_64 *)&outputCycles, (union union_64 *)&clockCycles); // perform atomic transfer of system time to main program
  8647.  
  8648.       sei();
  8649. #endif
  8650.  
  8651.       if (timerStatus & tsAwake)
  8652.       {
  8653.  
  8654.         if (timerStatus & tsFellAsleep)
  8655.         {
  8656.  
  8657.           LCD::setBright(brightnessIdx); // restore backlight brightness setting
  8658.           if ((eepromReadVal((unsigned int)(pWakeupResetCurrentOnEngineIdx))) && (timerStatus & tsAwakeOnEngine)) timerStatus &= ~tsFellAsleep;
  8659.           if ((eepromReadVal((unsigned int)(pWakeupResetCurrentOnButtonIdx))) && (timerStatus & tsAwakeOnButton)) timerStatus &= ~tsFellAsleep;
  8660.           if (!(timerStatus & tsFellAsleep)) doTripResetCurrent();
  8661.           timerStatus &= ~tsFellAsleep;
  8662.  
  8663.         }
  8664.  
  8665. #ifdef useDebugReadings
  8666.         tripArray[(unsigned int)(rawIdx)].collectedData[(unsigned int)(rvInjCycleIdx)] = (t2CyclesPerSecond / loopsPerSecond);
  8667.         tripArray[(unsigned int)(rawIdx)].collectedData[(unsigned int)(rvInjOpenCycleIdx)] = ((16391ul * processorSpeed) / (loopsPerSecond * 10));
  8668.         tripArray[(unsigned int)(rawIdx)].collectedData[(unsigned int)(rvVSScycleIdx)] = (t2CyclesPerSecond / loopsPerSecond);
  8669.         tripArray[(unsigned int)(rawIdx)].collectedData[(unsigned int)(rvInjPulseIdx)] = (20ul / loopsPerSecond);
  8670.         tripArray[(unsigned int)(rawIdx)].collectedData[(unsigned int)(rvVSSpulseIdx)] = (208ul / loopsPerSecond);
  8671.  
  8672.         timerCommand |= tcWakeUpOnEngine; // tell system timer to wake up the main program
  8673. #endif
  8674. #ifdef useBarFuelEconVsTime
  8675.         bFEvTcount++;
  8676.  
  8677.         if (bFEvTcount >= bFEvTperiod)
  8678.         {
  8679.  
  8680.           if (bFEvTsize < bgDataSize) bFEvTsize++;
  8681.  
  8682.           barFEvsTimeData[(unsigned int)(bFEvTstartIDx)] = SWEET64(prgmFuelEcon, periodIdx);
  8683.  
  8684.           bFEvTstartIDx++;
  8685.           if (bFEvTstartIDx == bgDataSize) bFEvTstartIDx = 0;
  8686.  
  8687.           tripArray[(unsigned int)(periodIdx)].reset();
  8688.           bFEvTcount = 0;
  8689.  
  8690.         }
  8691. #endif
  8692.  
  8693.         for (uint8_t x = 0; x < tUScount; x++)
  8694.         {
  8695.  
  8696.           i = pgm_read_byte(&tripUpdateDestList[(unsigned int)x]);
  8697.           j = pgm_read_byte(&tripUpdateSrcList[(unsigned int)x]);
  8698.  
  8699.           if (j & 0x80) cli(); // perform atomic transfer of raw measurements to main program
  8700.  
  8701.           if (i & 0x80)
  8702.           {
  8703.  
  8704.             tripArray[(unsigned int)(i & 0x7F)].transfer(tripArray[(unsigned int)(j & 0x7F)]);
  8705.             tripArray[(unsigned int)(j & 0x7F)].reset();
  8706.  
  8707.           }
  8708.           else tripArray[(unsigned int)(i & 0x7F)].update(tripArray[(unsigned int)(j & 0x7F)]);
  8709.  
  8710.           if (j & 0x80) sei();
  8711.  
  8712.         }
  8713.  
  8714. #ifdef useBarFuelEconVsSpeed
  8715.         FEvSpdTripIdx = (uint8_t)(SWEET64(prgmFEvsSpeed, instantIdx));
  8716.         if (FEvSpdTripIdx < 255) tripArray[(unsigned int)(FEvSpdTripIdx)].update(tripArray[(unsigned int)(instantIdx)]);
  8717.  
  8718. #endif
  8719. #ifdef useSerialPortDataLogging
  8720.         if (eepromReadVal((unsigned int)(pSerialDataLoggingIdx))) doOutputDataLog();
  8721.  
  8722. #endif
  8723. #ifdef useWindowFilter
  8724.         if (eepromReadVal((unsigned int)(pWindowFilterIdx)))
  8725.         {
  8726.  
  8727.           if (tripArray[(unsigned int)(instantIdx)].collectedData[(unsigned int)(rvInjOpenCycleIdx)] == 0)
  8728.  
  8729.             resetWindowFilter(); // if no fuel is being consumed, reset filter
  8730.  
  8731.           else
  8732.           { // update the CIC filter
  8733.  
  8734.             if (windowFilterCount < windowFilterSize) windowFilterCount++;
  8735.             else tripArray[(unsigned int)(windowFilterSumIdx)].subtract(tripArray[(unsigned int)(windowFilterElemIdx + windowFilterIdx)]);
  8736.  
  8737.             tripArray[(unsigned int)(windowFilterSumIdx)].update(tripArray[(unsigned int)(instantIdx)]);
  8738.             tripArray[(unsigned int)(windowFilterElemIdx + windowFilterIdx)].transfer(tripArray[(unsigned int)(instantIdx)]);
  8739.             tripArray[(unsigned int)(instantIdx)].transfer(tripArray[(unsigned int)(windowFilterSumIdx)]);
  8740.  
  8741.             windowFilterIdx++;
  8742.             if (windowFilterIdx == windowFilterSize) windowFilterIdx = 0;
  8743.  
  8744.           }
  8745.  
  8746.         }
  8747.  
  8748. #endif
  8749.       }
  8750.  
  8751.     }
  8752.  
  8753.     if (timerStatus & tsAwake) doRefreshDisplay();
  8754.     else
  8755.     {
  8756.  
  8757.       if (!(timerStatus & tsFellAsleep))
  8758.       {
  8759.  
  8760. #ifdef useSavedTrips
  8761.         if (doTripAutoAction(0)) printStatusMessage(PSTR("AutoSave Done"));
  8762. #endif
  8763.         LCD::setBright(0); // set backlight brightness to zero
  8764.         timerStatus |= tsFellAsleep;
  8765.  
  8766.       }
  8767.  
  8768. #ifdef useClock
  8769.       gotoXY(0, 0);
  8770.       doDisplaySystemTime();
  8771. #endif
  8772.  
  8773.     }
  8774.  
  8775.     if (timerStatus & tsMarkLoop) timerLoopLength = findCycleLength(timerLoopStart, cycles2());
  8776.     timerStatus &= ~tsMarkLoop;
  8777.  
  8778.     // wait for cycle to end, or for a keypress
  8779.     // while we're waiting anyway, let's do a few useful things
  8780.     while ((timerStatus & tsLoopExec) && (timerStatus & tsButtonsUp));
  8781.  
  8782.     if (!(timerStatus & tsButtonsUp)) // see if any buttons were pressed, display a brief message if so
  8783.     {
  8784.  
  8785.       j = buttonState;
  8786.       timerStatus |= tsButtonsUp; // reset keypress flag
  8787.  
  8788.       if (j == btnShortPressR) doCursorMoveRelative(0, 1);
  8789.       else if (j == btnShortPressL) doCursorMoveRelative(0, 255);
  8790.       else
  8791.       {
  8792.  
  8793.         bpPtr = (const uint8_t *)(pgm_read_word(&buttonPressAdrList[(unsigned int)(pgm_read_byte(&screenParameters[(unsigned int)(menuLevel)][5]))]));
  8794.  
  8795.         while (true)
  8796.         {
  8797.  
  8798.           i = pgm_read_byte(bpPtr++);
  8799.  
  8800.           if ((i == buttonsUp) || (j == i)) break;
  8801.  
  8802.           bpPtr++;
  8803.  
  8804.         }
  8805.  
  8806.         gotoXY(0, 0);
  8807.         if (j != buttonsUp) callFuncPointer(bpPtr); // go perform action
  8808.  
  8809.       }
  8810.  
  8811.     }
  8812.  
  8813.   }
  8814.  
  8815. }
Add Comment
Please, Sign In to add comment