From 419973fb81e7e9d3ed486eb82919e8eb0f996e6e Mon Sep 17 00:00:00 2001 From: tvago1972 Date: Tue, 6 Jun 2023 07:27:06 +0200 Subject: [PATCH] numerous readability enhancements, re-worked decimal string converter, simplified debug monitor interpreter code --- mpguino_tav/configs.h | 25 +- mpguino_tav/feature_base.h | 134 ++ mpguino_tav/feature_base.ino | 244 +++ mpguino_tav/feature_bignum.ino | 8 +- mpguino_tav/feature_coastdown.ino | 2 +- mpguino_tav/feature_datalogging.ino | 4 +- mpguino_tav/feature_debug.h | 99 +- mpguino_tav/feature_debug.ino | 871 +++++++--- mpguino_tav/feature_dragrace.h | 1 + mpguino_tav/feature_dragrace.ino | 104 ++ mpguino_tav/feature_outputpin.h | 12 + mpguino_tav/feature_outputpin.ino | 214 +++ mpguino_tav/feature_settings.ino | 6 +- mpguino_tav/functions.h | 70 +- mpguino_tav/functions.ino | 4 +- mpguino_tav/heart.h | 22 +- mpguino_tav/heart.ino | 537 +++++- mpguino_tav/m_input.h | 11 + mpguino_tav/m_input.ino | 82 + mpguino_tav/m_lcd.ino | 6 +- mpguino_tav/m_twi.ino | 2 +- mpguino_tav/m_usb.h | 8 + mpguino_tav/m_usb.ino | 58 + mpguino_tav/mpguino_tav.ino | 2361 +++------------------------ mpguino_tav/parameters.h | 52 +- mpguino_tav/parameters.ino | 2 +- mpguino_tav/sweet64.h | 23 +- mpguino_tav/sweet64.ino | 260 +++ mpguino_tav/trip_measurement.h | 21 +- mpguino_tav/trip_measurement.ino | 209 ++- 30 files changed, 2861 insertions(+), 2591 deletions(-) create mode 100644 mpguino_tav/feature_base.h create mode 100644 mpguino_tav/feature_base.ino create mode 100644 mpguino_tav/feature_outputpin.h create mode 100644 mpguino_tav/feature_outputpin.ino diff --git a/mpguino_tav/configs.h b/mpguino_tav/configs.h index bbc6d17..6a713b5 100644 --- a/mpguino_tav/configs.h +++ b/mpguino_tav/configs.h @@ -40,11 +40,11 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) // #define trackIdleEOCdata true // Ability to track engine idling and EOC modes #define useSpiffyTripLabels true // Ability to use enhanced trip labels on main display screens -//#define useSpiffyBigChars true +#define useSpiffyBigChars true //#define useSoftwareClock true // Shows 24 hour clock driven off of timer0, and provides a means to set it -//#define useBigFE true // Show big fuel economy displays -//#define useBigDTE true // Show big distance-to-empty displays -//#define useBigTTE true // Show big time-to-empty displays +#define useBigFE true // Show big fuel economy displays +#define useBigDTE true // Show big distance-to-empty displays +#define useBigTTE true // Show big time-to-empty displays //#define useBarFuelEconVsTime true // Show Fuel Economy over Time bar graph //#define useBarFuelEconVsSpeed true // Show Fuel Economy vs Speed, Fuel Used vs Speed bar graphs #define usePartialRefuel true // Provide means to enter partial refuel amount into MPGuino @@ -53,7 +53,7 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) #define useCPUreading true // Show CPU loading and available RAM usage //#define useChryslerMAPCorrection true // Ability to perform on-the-fly fuel injector data correction for late-model Chrysler vehicles //#define useChryslerBaroSensor true // allows use of a separate MAP sensor wired to MPGuino to read barometric pressure, for even more accurate correction -//#define useExpansionPins true // Generate analog 0-5VDC output voltage on expansion pins to drive LEDs or feed signal to external gauges +#define useOutputPins true // Generate analog 0-5VDC output voltage on expansion pins to drive LEDs or feed signal to external gauges //#define blankScreenOnMessage true // Completely blank display screen upon display of message //#define useImperialGallon true // when selected, uses Imperial gallons instead of default US gallons //#define useCarVoltageOutput true // Ability to display alternator voltage and optional secondary sensor (via meelis11) @@ -96,12 +96,13 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) // program measurement and debugging tools // #define useDebugTerminal true // (inw) terminal interface between PC and MPGuino +//#define useDebugTerminalHelp true // entering '?' in debug terminal displays brief help #define useDebugTerminalLabels true // nice labels for various terminal interface output lists - requires useDebugTerminal #define useDebugCPUreading true // Show enhanced CPU loading and available RAM usage - requires useDebugTerminal //#define useSWEET64trace true // Ability to view real-time 64-bit calculations from SWEET64 kernel - requires useDebugTerminal //#define useTestButtonValues true // Allows observation of button mapping #define useSimulatedFIandVSS true // forces simulation of VSS and fuel injector events -//#define useStatusLEDpins true // allows usage of LEDs to show status of certain bits - currently used to indicate when MPGuino is awake +#define useActivityLED true // allows usage of LEDs to show status of certain bits - currently used to indicate when MPGuino is awake #define useDebugAnalog true // forces ADC support to be compiled in, along with a dedicated analog screen //#define useObsoleteMult64 true // use obsolete slower bit-based 64-bit multiplication //#define useSWEET64mult true // shift mult64 from native C++ to SWEET64 bytecode (saves 36 bytes) @@ -179,7 +180,7 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) #undef useAnalogMuxButtons #undef useParallax5PositionSwitch #undef useAdafruitRGBLCDshield -#undef useStatusLEDpins +#undef useActivityLED #endif // defined (useJellyBeanDriverBoard) || defined (useLegacyBoard) #if not(__AVR_ATmega32U4__) && not(__AVR_ATmega2560__) && not(__AVR_ATmega328P__) @@ -401,7 +402,7 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) #define useTimer1 true #endif // useTimer1Interrupt -#ifdef useExpansionPins +#if defined(useOutputPins) #if defined(__AVR_ATmega32U4__) #define useTimer4 true #endif // defined(__AVR_ATmega32U4__) @@ -412,7 +413,7 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) #define useTimer1 true #define useTimer2 true #endif // defined(__AVR_ATmega328P__) -#endif // useExpansionPins +#endif // defined(useOutputPins) #ifdef useDragRaceFunction #define useVehicleMass true @@ -526,9 +527,9 @@ const unsigned long myBaudRate1 = 19200ul; // (Atmega2560 board) #endif // useSerial0Port && __AVR_ATmega32U4__ // Really, dcb? Really? You couldn't have used something else for LCD data bit 3? -#if useLegacyLCD && __AVR_ATmega328P__ && useStatusLEDpins -#error *** CANNOT use useLegacyLCD and useStatusLEDpins!!! *** -#endif // useLegacyLCD && __AVR_ATmega328P__ && useStatusLEDpins +#if useLegacyLCD && __AVR_ATmega328P__ && useActivityLED +#error *** CANNOT use useLegacyLCD and useActivityLED!!! *** +#endif // useLegacyLCD && __AVR_ATmega328P__ && useActivityLED #if useSoftwareClock && useDeepSleep #error *** CANNOT use both useSoftwareClock and useDeepSleep!!! *** diff --git a/mpguino_tav/feature_base.h b/mpguino_tav/feature_base.h new file mode 100644 index 0000000..2e61d7b --- /dev/null +++ b/mpguino_tav/feature_base.h @@ -0,0 +1,134 @@ +uint8_t mainScreenDisplayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); +void doReturnToMainScreen(void); +#ifdef useScreenEditor // Programmable main display screen edit support section +void doCursorUpdateScreenEdit(void); +void doScreenEditDisplay(void); +void doGoScreenEdit(void); +void doScreenEditBump(void); +void doSaveScreen(void); +void doScreenReturnToMain(void); +#endif // useScreenEditor + +uint8_t topScreenLevel; + +const uint8_t displayPageCount = 9 // count of base number of data screens +#ifdef trackIdleEOCdata + + 3 // count of Idle/EOC tracking data screens +#endif // trackIdleEOCdata +; +const uint8_t mainScreenDisplayFormatSize = displayPageCount * 4; + +const char mainScreenFuncNames[] PROGMEM = { + "Instrument\r" + "Custom\r" + "Instant/Current\r" + "Instant/Tank\r" + "Current\r" + "Tank\r" +#ifdef trackIdleEOCdata + "EOC/Idle\r" +#endif // trackIdleEOCdata + "Current Data\r" + "Tank Data\r" +#ifdef trackIdleEOCdata + "Current EOC/Idle\r" + "Tank EOC/Idle\r" +#endif // trackIdleEOCdata + "Remaining\r" +}; + +const uint8_t mainDisplayScreenFormats[(unsigned int)(mainScreenDisplayFormatSize)][2] PROGMEM = { + {lblInstantIdx, tSpeed} // Instrument + ,{lblInstantIdx, tEngineSpeed} + ,{lblInstantIdx, tFuelRate} + ,{lblInstantIdx, tFuelEcon} + + ,{lblInstantIdx, tFuelEcon} // Custom + ,{lblInstantIdx, tSpeed} + ,{lblInstantIdx, tFuelRate} + ,{lblCurrentIdx, tFuelEcon} + + ,{lblInstantIdx, tFuelEcon} // Instant / Current + ,{lblInstantIdx, tSpeed} + ,{lblCurrentIdx, tFuelEcon} + ,{lblCurrentIdx, tDistance} + + ,{lblInstantIdx, tFuelEcon} // Instant / Tank + ,{lblInstantIdx, tSpeed} + ,{lblTankIdx, tFuelEcon} + ,{lblTankIdx, tDistance} + + ,{lblCurrentIdx, tSpeed} // Current + ,{lblCurrentIdx, tFuelEcon} + ,{lblCurrentIdx, tDistance} + ,{lblCurrentIdx, tFuelUsed} + + ,{lblTankIdx, tSpeed} // Tank + ,{lblTankIdx, tFuelEcon} + ,{lblTankIdx, tDistance} + ,{lblTankIdx, tFuelUsed} + +#ifdef trackIdleEOCdata + ,{lblEOCidleCurrentIdx, tDistance} // EOC / Idle + ,{lblEOCidleCurrentIdx, tFuelUsed} + ,{lblEOCidleTankIdx, tDistance} + ,{lblEOCidleTankIdx, tFuelUsed} + +#endif // trackIdleEOCdata + ,{lblCurrentIdx, tEngineRunTime} // Current data + ,{lblCurrentIdx, tFuelUsed} + ,{lblCurrentIdx, tMotionTime} + ,{lblCurrentIdx, tDistance} + + ,{lblTankIdx, tEngineRunTime} // Tank data + ,{lblTankIdx, tFuelUsed} + ,{lblTankIdx, tMotionTime} + ,{lblTankIdx, tDistance} + +#ifdef trackIdleEOCdata + ,{lblEOCidleCurrentIdx, tEngineRunTime} // Current EOC / Idle + ,{lblEOCidleCurrentIdx, tFuelUsed} + ,{lblEOCidleCurrentIdx, tMotionTime} + ,{lblEOCidleCurrentIdx, tDistance} + + ,{lblEOCidleTankIdx, tEngineRunTime} // Tank EOC / Idle + ,{lblEOCidleTankIdx, tFuelUsed} + ,{lblEOCidleTankIdx, tMotionTime} + ,{lblEOCidleTankIdx, tDistance} + +#endif // trackIdleEOCdata + ,{lblTankIdx, tFuelUsed} // Remaining + ,{lblTankIdx, tRemainingFuel} + ,{lblTankIdx, tTimeToEmpty} + ,{lblTankIdx, tDistanceToEmpty} +}; + +#ifdef trackIdleEOCdata +const uint8_t mainEOCscreenFormats[(unsigned int)(4)][2] PROGMEM = { + {lblInstantIdx, tSpeed} + ,{lblCurrentIdx, tFuelEcon} + ,{lblEOCidleCurrentIdx, tDistance} + ,{lblEOCidleTankIdx, tDistance} +}; + +const uint8_t mainIdleScreenFormats[(unsigned int)(4)][2] PROGMEM = { + {lblInstantIdx, tFuelRate} + ,{lblCurrentIdx, tFuelEcon} + ,{lblEOCidleCurrentIdx, tFuelUsed} + ,{lblEOCidleTankIdx, tFuelUsed} +}; + +#endif // trackIdleEOCdata +#if defined(useScreenEditor) +/* Programmable main display screen edit support section */ + +uint8_t screenTripValue = 0; +uint8_t screenFunctionValue = 0; +uint8_t screenEditDirty = 0; + +const uint8_t screenEditFlag_dirty = 0x80; + +const char seFormatRevertedString[] PROGMEM = "Format reverted"; +const char seExitScreenEditString[] PROGMEM = "Screen Display"; + +#endif // defined(useScreenEditor) \ No newline at end of file diff --git a/mpguino_tav/feature_base.ino b/mpguino_tav/feature_base.ino new file mode 100644 index 0000000..51542ef --- /dev/null +++ b/mpguino_tav/feature_base.ino @@ -0,0 +1,244 @@ +/* Main screen section */ + +uint8_t mainScreenDisplayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged) +{ + +#ifdef useScreenEditor + uint8_t i; +#endif // useScreenEditor + uint8_t retVal = 0; + + switch (cmd) + { + + case menuExitIdx: + break; + + case menuEntryIdx: + topScreenLevel = menuLevel; // save current menu level for sub-function (param edit, trip load/save, etc) support + + case menuCursorUpdateIdx: + printStatusMessage(mainScreenFuncNames, cursorPos); // briefly display screen name + + case menuOutputDisplayIdx: + retVal = (activityFlags & afActivityCheckFlags); + switch (retVal) + { + + case (afVehicleStoppedFlag | afButtonFlag): +#ifdef trackIdleEOCdata +#ifdef useSpiffyTripLabels + displayMainScreenFunctions(mainIdleScreenFormats, 0, 136, 0, msTripBitPattern); +#else // useSpiffyTripLabels + displayMainScreenFunctions(mainIdleScreenFormats, 0); +#endif // useSpiffyTripLabels + break; + +#endif // trackIdleEOCdata + case (afEngineOffFlag | afButtonFlag): +#ifdef trackIdleEOCdata +#ifdef useSpiffyTripLabels + displayMainScreenFunctions(mainEOCscreenFormats, 0, 136, 0, msTripBitPattern); +#else // useSpiffyTripLabels + displayMainScreenFunctions(mainEOCscreenFormats, 0); +#endif // useSpiffyTripLabels + break; + +#endif // trackIdleEOCdata + default: +#ifdef useScreenEditor + i = cursorPos; + i <<= 2; + i += eePtrScreensStart; + +#ifdef useSpiffyTripLabels + for (uint8_t x = 0; x < 4; x++) displayFunction(x, EEPROM::readVal(i++), EEPROM::readVal(i++), 136, 0, msTripBitPattern); +#else // useSpiffyTripLabels + for (uint8_t x = 0; x < 4; x++) displayFunction(x, EEPROM::readVal(i++), EEPROM::readVal(i++)); +#endif // useSpiffyTripLabels + +#else // useScreenEditor +#ifdef useSpiffyTripLabels + displayMainScreenFunctions(mainDisplayScreenFormats, cursorPos, 136, 0, msTripBitPattern); +#else // useSpiffyTripLabels + displayMainScreenFunctions(mainDisplayScreenFormats, cursorPos); +#endif // useSpiffyTripLabels +#endif // useScreenEditor + break; + + } + retVal = 0; + break; + + default: + break; + + } + + return retVal; + +} + +void doReturnToMainScreen(void) +{ + + cursor::moveAbsolute(topScreenLevel, 255); + +} + +#if defined(useScreenEditor) +/* Programmable main display screen edit support section */ + +void doCursorUpdateScreenEdit(void) +{ + + uint8_t b; + + b = screenCursor[(unsigned int)(screenEditIdx)]; + b &= ~screenEditFlag_dirty; + + if ((screenEditDirty & ~screenEditFlag_dirty) ^ b) // if cursor moved to a different screen function altogether + { + + screenTripValue = EEPROM::readVal(b + eePtrScreensStart); + screenFunctionValue = EEPROM::readVal(b + eePtrScreensStart + 1); + + if (screenEditDirty & screenEditFlag_dirty) // if previous screen function was changed but not saved + { + + printStatusMessage(seFormatRevertedString); + + } + + screenEditDirty = b; // save current cursor position of screen function being edited + screenEditDirty &= ~screenEditFlag_dirty; // mark screen function as not modified + + } + +} + +void doScreenEditDisplay(void) +{ + + uint8_t i; + uint8_t j; + uint8_t k; + + uint8_t tripIdx; + uint8_t calcIdx; + uint8_t calcBlink; + uint8_t tripBlink; + + i = screenCursor[(unsigned int)(screenEditIdx)]; + + j = i; // extract whether trip index or trip function is to be edited + j &= 0x01; + + i >>= 1; // figure out edited screen function placement on screen + k = i; + + i &= 0xFC; // figure out start of screen page + k &= 0x03; + + for (uint8_t x = 0; x < 4; x++) + { + + calcBlink = 0; + tripBlink = 0; + + if (x == k) // if at + { + + tripIdx = screenTripValue; + calcIdx = screenFunctionValue; + if (j == 1) calcBlink = 170; + else tripBlink = 170; + + } + else + { + + tripIdx = EEPROM::readVal(eePtrScreensStart + (i + x) * 2); + calcIdx = EEPROM::readVal(eePtrScreensStart + (i + x) * 2 + 1); + + } + +#ifdef useSpiffyTripLabels + displayFunction(x, tripIdx, calcIdx, tripBlink, calcBlink, msTripBitPattern); // call main screen function display routine +#else // useSpiffyTripLabels + displayFunction(x, tripIdx, calcIdx); // call main screen function display routine +#endif // useSpiffyTripLabels + + } + +} + +void doGoScreenEdit(void) +{ + + screenEditDirty = screenCursor[(unsigned int)(screenEditIdx)]; + screenEditDirty >>= 1; + screenEditDirty ^= 0x01; // force update of screen function + screenEditDirty &= ~screenEditFlag_dirty; + + cursor::moveAbsolute(screenEditIdx, screenCursor[(unsigned int)(mainScreenIdx)] << 3); + + printStatusMessage(PSTR("Screen Editor")); + +} + +void doScreenEditBump(void) +{ + + uint8_t b; + + b = (screenCursor[(unsigned int)(screenEditIdx)] & 0x01); // figure out whether trip variable or trip function is being modified + screenEditDirty |= screenEditFlag_dirty; // mark current screen function as modified + + if (b) // if trip function is being modified + { + + screenFunctionValue++; + if (screenFunctionValue == dfMaxValDisplayCount) screenFunctionValue = 0; + + } + else // otherwise, trip variable is being modified + { + + screenTripValue++; + if (screenTripValue == dfMaxTripCount) screenTripValue = 0; + + } + +} + +void doSaveScreen(void) +{ + + uint8_t b; + + b = screenCursor[(unsigned int)(screenEditIdx)]; + + // generate and save new screen function from trip variable and trip function + EEPROM::writeVal(eePtrScreensStart + b, (unsigned long)(screenTripValue)); + EEPROM::writeVal(eePtrScreensStart + b + 1, (unsigned long)(screenFunctionValue)); + screenEditDirty &= ~screenEditFlag_dirty; + + printStatusMessage(PSTR("Format saved")); + +} + +void doScreenReturnToMain(void) +{ + + const char * str; + + if (screenEditDirty & screenEditFlag_dirty) str = seFormatRevertedString; + else s = seExitScreenEditString; + + screenCursor[(unsigned int)(mainScreenIdx)] = (screenCursor[(unsigned int)(screenEditIdx)] >> 3); + cursor::screenLevelEntry(str, topScreenLevel); + +} + +#endif // defined(useScreenEditor) diff --git a/mpguino_tav/feature_bignum.ino b/mpguino_tav/feature_bignum.ino index ff28b75..e78d764 100644 --- a/mpguino_tav/feature_bignum.ino +++ b/mpguino_tav/feature_bignum.ino @@ -5,7 +5,7 @@ static void clockSet::entry(void) { #ifdef useSoftwareClock - ull2str(tReadTicksToSeconds, pBuff, vClockCycleIdx); + ull2str(pBuff, vClockCycleIdx, tReadTicksToSeconds); #endif // useSoftwareClock cursor::moveAbsolute(clockSetScreenIdx, 0); @@ -200,13 +200,13 @@ static uint8_t bigDigit::displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t #endif // useBigFE #ifdef useBigTTE case bigTTEscreenIdx: - outputTime(ull2str(tTimeToEmpty, mBuff1, tripIdx), (mainLoopHeartBeat & 0b01010101), 4); + outputTime(ull2str(mBuff1, tripIdx, tTimeToEmpty), (mainLoopHeartBeat & 0b01010101), 4); break; #endif // useBigTTE #ifdef useClockDisplay case clockShowScreenIdx: - outputTime(ull2str(tReadTicksToSeconds, mBuff1, vClockCycleIdx), (mainLoopHeartBeat & 0b01010101), 4); + outputTime(ull2str(mBuff1, vClockCycleIdx, tReadTicksToSeconds), (mainLoopHeartBeat & 0b01010101), 4); break; case clockSetScreenIdx: @@ -275,7 +275,7 @@ static uint8_t bigDigit::outputNumber(uint8_t tripIdx, uint8_t calcIdx, uint8_t calcFuncObj thisCalcFuncObj; - thisCalcFuncObj = translateCalcIdx(tripIdx, calcIdx, mBuff1, windowLength, dfAdjustWindow); // perform the required decimal formatting + thisCalcFuncObj = translateCalcIdx(tripIdx, calcIdx, mBuff1, windowLength, dfIgnoreDecimalPoint); // perform the required decimal formatting outputNumberString(thisCalcFuncObj.strBuffer); // output the number return thisCalcFuncObj.calcFmtIdx; // for big MPG label diff --git a/mpguino_tav/feature_coastdown.ino b/mpguino_tav/feature_coastdown.ino index eaafd45..381b23c 100644 --- a/mpguino_tav/feature_coastdown.ino +++ b/mpguino_tav/feature_coastdown.ino @@ -91,7 +91,7 @@ void coastdown::goDisplay(void) i = screenCursor[(unsigned int)(coastdownIdx)] + pCoefficientDidx; SWEET64::runPrgm(prgmFetchParameterValue, i); - ull2str(tFormatToNumber, pBuff, 3); + ull2str(pBuff, 0, tFormatToNumber); text::stringOut(devLCD, parmLabels, i); // print parameter name at top left text::stringOut(devLCD, pBuff); diff --git a/mpguino_tav/feature_datalogging.ino b/mpguino_tav/feature_datalogging.ino index 09e550b..3eafa5c 100644 --- a/mpguino_tav/feature_datalogging.ino +++ b/mpguino_tav/feature_datalogging.ino @@ -82,7 +82,7 @@ void doOutputJSONnumber(union union_64 * an, uint8_t decimalPlaces, const char * void doOutputJSONnumber(uint8_t decimalPlaces, const char * labelStr) { - text::stringOut(devLogOutput, formatDecimal(mBuff1, 0, decimalPlaces, dfOverflow9s)); // output the number part + text::stringOut(devLogOutput, ull2str(mBuff1, decimalPlaces, 0, dfOverflow9s)); // output the number part text::stringOut(devLogOutput, labelStr); // output the label part } @@ -104,7 +104,7 @@ void doOutputJSON(void) //skybolt added json output function if (timer0Status & t0sOutputJSON) // replaced timerChecker with this because systemInfo::cycles0() is a compile-time option that could break JSON output if #useCPUreading is not set { - peripheral::changeBitFlags(timer0Status, t0sOutputJSON, 0); // clear JSON subtitle change timer command + changeBitFlags(timer0Status, t0sOutputJSON, 0); // clear JSON subtitle change timer command if (!(--subtitleCount1)) subtitleCount1 = 2; #ifdef useDragRaceFunction diff --git a/mpguino_tav/feature_debug.h b/mpguino_tav/feature_debug.h index 9da267d..e90e998 100644 --- a/mpguino_tav/feature_debug.h +++ b/mpguino_tav/feature_debug.h @@ -12,6 +12,7 @@ uint32_t SWEET64timerLength; namespace systemInfo /* CPU loading and RAM availability support section prototype */ { + static void idleProcess(void); static uint8_t displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); static void showCPUload(void); static void showCPUloading(void); @@ -25,12 +26,25 @@ extern char __bss_end; extern char *__brkval; #endif // useCPUreading +#if defined(useActivityLED) +namespace activityLED /* Activity status LED support section prototype */ +{ + + static void init(void); + static void shutdown(void); + static void output(uint8_t val); + +}; + +#endif // defined(useActivityLED) #ifdef useSimulatedFIandVSS namespace debugReading /* VSS / fuel injector on-board simulator support section prototype */ { static uint8_t displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); static void configurePorts(void); + static void idleProcessFuel(void); + static void idleProcessVSS(void); } @@ -77,60 +91,93 @@ namespace terminal /* debug terminal section prototype */ static void outputParameterValue(uint8_t lineNumber); static void outputParameterExtra(uint8_t lineNumber); static void outputVolatileValue(uint8_t lineNumber); + static void outputDecimalValue(uint8_t lineNumber); static void outputMainProgramValue(uint8_t lineNumber); static void outputTripVarMeasuredValue(uint8_t lineNumber); static void outputTripVarMeasuredExtra(uint8_t lineNumber); } -/* debug terminal section */ - -static uint8_t termRawIdx; - static char termNumberBuff[17]; static const uint8_t tBuffLength = 40; +#if defined(useDebugTerminalHelp) static const char terminalHelp[] PROGMEM = { - " P - list stored parameters\r" - " V - list volatile variables\r" - " M - list main program variables\r" - " T - list read-in trip variable values\r" - " O - list program constants\r" - " L - list functions for read-in trip variable\r" + " [y].[x]P - list stored parameters, optionally between [y] and [x]\r" + " xPy y y... - store one or more y values in stored parameter beginning with x\r" + "\r" + " [y].[x]V - list volatile variables, optionally between [y] and [x]\r" + " xVy y y... - store one or more y values in volatile variable beginning with x\r" + "\r" + " [y].[x]M - list main program variables, optionally between [y] and [x]\r" + " xMy y y... - store one or more y values in main program variable beginning with x\r" + "\r" + " [y].[x]T - list terminal trip variable values, optionally between [y] and [x]\r" + " xTy y y... - store one or more y values in terminal trip variable beginning with x\r" + "\r" + " [y].[x]O - list program constants, optionally between [y] and [x]\r" + " [y].[x]L - list terminal trip variable function outputs, optionally between [y] and [x]\r" + "[z]<[y].[x]U - list decimal number sample for output\r" + " z - decimal processing flag\r" + " y - window length\r" + " x - decimal digit count\r" #ifdef useSWEET64trace - " ^L - list SWEET64 source code for function\r" + " ^L - list SWEET64 source code for function\r" #endif // useSWEET64trace - "[x]R - read trip variable x into terminal trip variable\r" - "[x]W - write terminal trip variable into trip variable x\r" - " if no x specified, lists available trip variables\r" - " S - output system status\r" - " I - inject button press\r" + " [y]<[x]R - read trip variable x into trip variable y\r" + " default for x and y is terminal trip variable\r" + " if no x or y specified, lists available trip variables\r" + " S - output system status\r" + " I - inject button press\r" #ifdef useLegacyButtons - " short (l, c, r)\r" - " long (L, C, R)\r" + " short (l, c, r)\r" + " long (L, C, R)\r" #else // useLegacyButtons - " short (l, c, r, u, d)\r" - " long (L, C, R, U, D)\r" + " short (l, c, r, u, d)\r" + " long (L, C, R, U, D)\r" #endif // useLegacyButtons - " ? - displays this help\r" + " ? - displays this help\r" "\0" }; -const uint8_t tmHexInput = 0x40; -const uint8_t tmSomethingReadIn = 0x80; +#endif // defined(useDebugTerminalHelp) +const uint8_t tmByteReadIn = 0x80; +const uint8_t tmSourceReadIn = 0x40; +const uint8_t tmTargetReadIn = 0x20; +const uint8_t tmAddressReadIn = 0x10; -uint8_t terminalMode; +const uint8_t tmHexInput = 0x08; +const uint8_t tmDecimalInput = 0x04; +const uint8_t tmButtonInput = 0x02; +const uint8_t tmInitInput = 0x01; + +const uint8_t tmInputMask = (tmHexInput | tmDecimalInput | tmButtonInput | tmInitInput); +const uint8_t tmInitHex = (tmInitInput | tmHexInput); +const uint8_t tmInitDecimal = (tmInitInput | tmDecimalInput); +const uint8_t tmInitButton = (tmInitInput | tmButtonInput); + +uint8_t terminalState; uint8_t nextTerminalState; +uint8_t terminalCmd; +uint8_t terminalMode; + uint8_t terminalByte; +uint8_t terminalSource; +uint8_t terminalTarget; + uint8_t chr; uint8_t inpIdx; uint8_t readIdx; -uint8_t terminalState; uint8_t terminalAddress; uint8_t terminalLine; -char terminalBuff[tBuffLength]; uint8_t maxLine; +uint8_t decPlace; +uint8_t decWindow; +uint8_t decMode; + +char terminalBuff[tBuffLength]; + const char * labelList; const uint8_t * prgmPtr; void (* primaryFunc)(uint8_t); diff --git a/mpguino_tav/feature_debug.ino b/mpguino_tav/feature_debug.ino index 119df48..27d3f22 100644 --- a/mpguino_tav/feature_debug.ino +++ b/mpguino_tav/feature_debug.ino @@ -16,6 +16,65 @@ static const uint8_t prgmOutputAvailableRAM[] PROGMEM = { instrDone // exit to caller }; +static void systemInfo::idleProcess(void) +{ + + uint8_t oldSREG; + +#ifdef useCPUreading + mainProgramVariables[(uint16_t)(mpMainLoopAccumulatorIdx)] = systemInfo::findCycleLength(mainStart, systemInfo::cycles0()); + mainProgramVariables[(uint16_t)(mpIdleAccumulatorIdx)] = idleTimerLength; + + mainStart = systemInfo::cycles0(); + idleTimerLength = 0; + +#ifdef useDebugCPUreading + switch (monitorState) + { + + case 1: + idleProcessTimerLength = 0; + displayTimerLength = 0; + SWEET64timerLength = 0; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + volatileVariables[(uint16_t)(vInterruptAccumulatorIdx)] = 0; + + SREG = oldSREG; // restore interrupt flag status + + monitorState = 2; + break; + + case 2: + mainProgramVariables[(uint16_t)(mpDebugAccMainLoopIdx)] = mainProgramVariables[(uint16_t)(mpMainLoopAccumulatorIdx)]; + mainProgramVariables[(uint16_t)(mpDebugAccIdleIdx)] = mainProgramVariables[(uint16_t)(mpIdleAccumulatorIdx)]; + mainProgramVariables[(uint16_t)(mpDebugAccIdleProcessIdx)] = idleProcessTimerLength; + mainProgramVariables[(uint16_t)(mpDebugAccDisplayIdx)] = displayTimerLength; + mainProgramVariables[(uint16_t)(mpDebugAccSWEET64idx)] = SWEET64timerLength; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + mainProgramVariables[(uint16_t)(mpDebugAccInterruptIdx)] = volatileVariables[(uint16_t)(vInterruptAccumulatorIdx)]; + + SREG = oldSREG; // restore interrupt flag status + + monitorState = 0; + break; + + default: + monitorState = 0; + break; + + } + +#endif // useDebugCPUreading +#endif // useCPUreading + +} + static uint8_t systemInfo::displayHandler (uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged) { @@ -36,13 +95,13 @@ static uint8_t systemInfo::displayHandler (uint8_t cmd, uint8_t cursorPos, uint8 case menuOutputDisplayIdx: // display max cpu utilization and RAM showCPUload(); text::stringOut(devLCD, PSTR(" T")); - text::stringOut(devLCD, ull2str(tReadTicksToSeconds, mBuff1, vSystemCycleIdx)); // output system time (since MPGuino was powered up) + text::stringOut(devLCD, ull2str(mBuff1, vSystemCycleIdx, tReadTicksToSeconds)); // output system time (since MPGuino was powered up) text::gotoXY(devLCD, 0, 1); text::stringOut(devLCD, PSTR("FREE RAM: ")); mainProgramVariables[(uint16_t)(mpAvailableRAMidx)] = availableRAMptr; SWEET64::runPrgm(prgmOutputAvailableRAM, 0); - text::stringOut(devLCD, formatDecimal(mBuff1, 6, 2, 0)); + text::stringOut(devLCD, ull2str(mBuff1, 0, 6, 0)); break; default: @@ -59,7 +118,7 @@ static void systemInfo::showCPUload(void) text::stringOut(devLCD, PSTR("C%")); SWEET64::runPrgm(prgmFindCPUutilPercent, 0); - text::stringOut(devLCD, formatDecimal(mBuff1, 6, 2, 0)); + text::stringOut(devLCD, ull2str(mBuff1, 2, 6, 0)); #ifdef useDebugCPUreading monitorState = 1; #endif // useDebugCPUreading @@ -113,6 +172,118 @@ static uint32_t systemInfo::cycles0(void) } #endif // useCPUreading +#if defined(useActivityLED) +/* Activity status LED support section */ + +static void activityLED::init(void) +{ + +#if defined(__AVR_ATmega32U4__) +#ifdef useTinkerkitLCDmodule +// DDRB |= (1 << DDB0); // turn on digital output for RX LED + DDRC |= (1 << DDC7); // turn on digital output for LED L +// DDRD |= (1 << DDD5); // turn on digital output for TX LED +#else // useTinkerkitLCDmodule +// insert any other ATmega32U4 port information for initializing status LEDs here +#endif // useTinkerkitLCDmodule +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) +#ifdef useArduinoMega2560 + DDRB |= (1 << DDB7); // turn on digital output for LED L +#else // useArduinoMega2560 +// insert any other ATmega2560 port information for initializing status LEDs here +#endif // useArduinoMega2560 +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + DDRB |= (1 << DDB5); // turn on digital output for LED L +#endif // defined(__AVR_ATmega328P__) + + output(1); // initially turn on status LED + +} + +static void activityLED::shutdown(void) +{ + + output(0); // turn off status LED + +#if defined(__AVR_ATmega32U4__) +#ifdef useTinkerkitLCDmodule +// DDRB &= ~(1 << DDB0); // turn off digital output for RX LED + DDRC &= ~(1 << DDC7); // turn off digital output for LED L +// DDRD &= ~(1 << DDD5); // turn off digital output for TX LED +#else // useTinkerkitLCDmodule +// insert any other ATmega32U4 port information for turning off status LEDs here +#endif // useTinkerkitLCDmodule +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) +#ifdef useArduinoMega2560 + DDRB &= ~(1 << DDB7); // turn off digital output for LED L +#else // useArduinoMega2560 +// insert any other ATmega2560 port information for turning off status LEDs here +#endif // useArduinoMega2560 +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + DDRB &= ~(1 << DDB5); // turn off digital output for LED L +#endif // defined(__AVR_ATmega328P__) + +} + +static void activityLED::output(uint8_t val) +{ + + if (val) + { + +#if defined(__AVR_ATmega32U4__) +#ifdef useTinkerkitLCDmodule +// PORTB &= ~(1 << PORTB0); // active low RX + PORTC |= (1 << PORTC7); // active high L +// PORTD &= ~(1 << PORTD5); // active low TX +#else // useTinkerkitLCDmodule +// insert any other ATmega32U4 port information for turning on status LEDs here +#endif // useTinkerkitLCDmodule +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) +#ifdef useArduinoMega2560 + PORTB |= (1 << PORTB7); // active high L +#else // useArduinoMega2560 +// insert any other ATmega2560 port information for turning on status LEDs here +#endif // useArduinoMega2560 +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + PORTB |= (1 << PORTB5); // active high L +#endif // defined(__AVR_ATmega328P__) + + } + else + { + +#if defined(__AVR_ATmega32U4__) +#ifdef useTinkerkitLCDmodule +// PORTB |= (1 << PORTB0); // active low RX + PORTC &= ~(1 << PORTC7); // active high L +// PORTD |= (1 << PORTD5); // active low TX +#else // useTinkerkitLCDmodule +// insert any other ATmega32U4 port information for turning off status LEDs here +#endif // useTinkerkitLCDmodule +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) +#ifdef useArduinoMega2560 + PORTB &= ~(1 << PORTB7); // active high L +#else // useArduinoMega2560 +// insert any other ATmega2560 port information for turning off status LEDs here +#endif // useArduinoMega2560 +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + PORTB &= ~(1 << PORTB5); // active high L +#endif // defined(__AVR_ATmega328P__) + + } + +} + +#endif // defined(useActivityLED) #ifdef useTestButtonValues /* Button input value viewer section */ @@ -162,48 +333,61 @@ static uint8_t buttonView::displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_ static const uint8_t prgmParseDecimalDigit[] PROGMEM = { instrLdReg, 0x62, // load terminal register into main register instrMul2byByte, 10, // multiply by 10 - instrJump, tParseCharacterToReg + instrJump, tParseCharacterToReg // go perform number parse }; static const uint8_t prgmParseHexDigit[] PROGMEM = { instrLdReg, 0x62, // load terminal register into main register instrMul2byByte, 16, // multiply by 16 - instrJump, tParseCharacterToReg + instrJump, tParseCharacterToReg // go perform number parse }; static const uint8_t prgmFetchMainProgramValue[] PROGMEM = { instrLdRegMainIndexed, 0x02, - instrDone + instrDone // exit to caller }; static const uint8_t prgmFetchConstantValue[] PROGMEM = { instrLdRegConstIndexed, 0x02, - instrDone + instrDone // exit to caller }; static const uint8_t prgmFetchVolatileValue[] PROGMEM = { instrLdRegVolatileIndexed, 0x02, - instrDone + instrDone // exit to caller +}; + +static const uint8_t prgmFetchDecimalValue[] PROGMEM = { + instrTestIndex, // test line number + instrBranchIfNotE, 3, // skip if line number is not zero + instrLdRegByte, 0x06, 0, // initialize terminal register + +//cont: + instrLdReg, 0x62, // load terminal register into main register + instrMul2byByte, 10, // multiply by 10 + instrAddByteToX, 0x02, 5, // add 5 + instrLdReg, 0x26, // load main register into terminal register + instrDone // exit to caller }; static const uint8_t prgmFetchTripVarValue[] PROGMEM = { instrLdRegTripVarIndexedRV, 0x02, terminalIdx, - instrDone + instrDone // exit to caller }; static const uint8_t prgmWriteMainProgramValue[] PROGMEM = { instrStRegMainIndexed, 0x06, - instrDone + instrDone // exit to caller }; static const uint8_t prgmWriteVolatileValue[] PROGMEM = { instrStRegVolatileIndexed, 0x06, - instrDone + instrDone // exit to caller }; static const uint8_t prgmWriteTripMeasurementValue[] PROGMEM = { instrStRegTripVarIndexedRV, 0x06, terminalIdx, - instrDone + instrDone // exit to caller }; #ifdef useLegacyButtons @@ -301,7 +485,7 @@ static void terminal::outputConstantValue(uint8_t lineNumber) { SWEET64::runPrgm(prgmFetchConstantValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); } @@ -309,7 +493,7 @@ static void terminal::outputParameterValue(uint8_t lineNumber) { SWEET64::runPrgm(prgmFetchParameterValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); } @@ -326,7 +510,7 @@ static void terminal::outputParameterExtra(uint8_t lineNumber) text::stringOut(devDebugTerminal, PSTR(" (orig ")); SWEET64::runPrgm(prgmFetchInitialParamValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); text::stringOut(devDebugTerminal, PSTR(")")); } @@ -346,7 +530,7 @@ static void terminal::outputVolatileValue(uint8_t lineNumber) { SWEET64::runPrgm(prgmFetchVolatileValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); } @@ -354,7 +538,7 @@ static void terminal::outputMainProgramValue(uint8_t lineNumber) { SWEET64::runPrgm(prgmFetchMainProgramValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); } @@ -363,7 +547,7 @@ static void terminal::outputTripVarMeasuredValue(uint8_t lineNumber) SWEET64::runPrgm(prgmFetchTripVarValue, lineNumber); - text::stringOut(devDebugTerminal, ull2str(tFormatToNumber, termNumberBuff, 3)); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, 0, tFormatToNumber)); } @@ -375,6 +559,14 @@ static void terminal::outputTripVarMeasuredExtra(uint8_t lineNumber) } +static void terminal::outputDecimalValue(uint8_t lineNumber) +{ + + SWEET64::runPrgm(prgmFetchDecimalValue, lineNumber); + text::stringOut(devDebugTerminal, ull2str(termNumberBuff, decPlace, decWindow, decMode)); + +} + static void terminal::mainProcess(void) { @@ -383,32 +575,50 @@ static void terminal::mainProcess(void) uint8_t oldSREG; /* +the debug terminal is based off of the Apple II system monitor, which is command-line based. One or more commands are +entered at the prompt, separated by space characters. Pressing will cause the monitor to execute these commands terminal commands: - P - list stored parameters - V - list volatile variables - M - list main program variables - O - list program constants - T - list read-in trip variable values - L - list functions for read-in trip variable - ^L - list SWEET64 source code for function - [x]R - read trip variable x into terminal trip variable - [x]W - write terminal trip variable into trip variable x - if no x specified, lists available trip variables - S - output system status - I - inject button press - short (l, c, r, u, d) - long (L, C, R, U, D) - ? - displays this help + [y].[x]P - list stored parameters, optionally between [y] and [x] + xPy y y... - store one or more y values in stored parameter beginning with x + + [y].[x]V - list volatile variables, optionally between [y] and [x] + xVy y y... - store one or more y values in volatile variable beginning with x + + [y].[x]M - list main program variables, optionally between [y] and [x] + xMy y y... - store one or more y values in main program variable beginning with x + + [y].[x]T - list terminal trip variable values, optionally between [y] and [x] + xTy y y... - store one or more y values in terminal trip variable beginning with x + + [y].[x]O - list program constants, optionally between [y] and [x] + [y].[x]L - list terminal trip variable function outputs, optionally between [y] and [x] +[z]<[y].[x]U - list decimal number sample for output + z - decimal processing flag + y - window length + x - decimal digit count + ^L - list SWEET64 source code for function + [y]<[x]R - read trip variable x into trip variable y + default for x and y is terminal trip variable + if no x or y specified, lists available trip variables + S - output system status + I - inject button press + short (l, c, r, u, d) + long (L, C, R, U, D) + ? - displays this help numbers or button presses are separated by spaces ex: - ]1r << reads instant trip variable into terminal + ]1r << reads instant trip variable into terminal trip variable + + ]1.3l << outputs functions 1, 2, and 3 associated with read-in trip variable - ]1l 2l 3l << prints functions 1, 2, and 3 associated with read-in trip variable + ]0.3p << outputs stored parameters 0 through 3 - ]l << prints all available functions associated with read-in trip variable + ]1p2 66 3000 << stores 2 at stored parameter 1, 66 at stored parameter 2, and 3000 at stored parameter 3 + + ]l << outputs all available functions associated with terminal trip variable ]ild << injects short button press l+d into MPGuino @@ -426,8 +636,8 @@ static void terminal::mainProcess(void) terminalState++; inpIdx = 0; readIdx = 0; - terminalMode = tmHexInput; - terminalByte = 0; + terminalCmd = 0; + terminalMode = tmInitHex; terminalAddress = 0; case 1: // get line i = devDebugTerminal.chrIn(); @@ -500,59 +710,49 @@ static void terminal::mainProcess(void) else chr = terminalBuff[(uint16_t)(readIdx++)]; i = 1; - if ((terminalMode & tmSomethingReadIn) == 0) + + if (terminalMode & tmInitInput) { + terminalMode &= ~(tmInitInput | tmByteReadIn); + terminalByte = 0; SWEET64::init64byt((union union_64 *)(&s64reg[s64reg6]), 0); } - if (chr > 0x5F) j = chr - 0x20; - else j = chr; - switch (terminalMode) + + j = chr; // save raw input character for button press processing + + if (chr > 0x5F) chr &= 0x5F; // force input character to uppercase + + switch (terminalMode & tmInputMask) // process a possible digit, hexit, or button press character { - case 'I': // parse a button press character - case ('I' | tmSomethingReadIn): // parse a button press character + case (tmButtonInput): // parse a button press character + case (tmButtonInput | tmByteReadIn): // parse a button press character for (uint8_t x = 0; x < terminalButtonCount; x++) - if (chr == pgm_read_byte(&terminalButtonChars[(uint16_t)(x)])) + if (j == pgm_read_byte(&terminalButtonChars[(uint16_t)(x)])) { - i = 0; // signal that a valid character was already read in + i = 0; // signal that a valid character was read in terminalByte |= (pgm_read_byte(&terminalButtonValues[(uint16_t)(x)])); - terminalMode |= (tmSomethingReadIn); + terminalMode |= (tmByteReadIn); } break; - case ('.' | tmHexInput): // parse an address range upper limit -#ifdef useSWEET64trace - case (0x1B | tmHexInput): // parse a specific SWEET64 argument hexadecimal value input digit -#endif // useSWEET64trace - case (0x0D | tmHexInput): // parse a specific main program variable hexadecimal value input digit - case (0x10 | tmHexInput): // parse a specific parameter value input hexadecimal digit - case (0x14 | tmHexInput): // parse a specific trip variable measurement hexadecimal value input digit - case (0x16 | tmHexInput): // parse a specific volatile variable value input hexadecimal digit - case (tmHexInput): // parse a generic hexadecimal digit - case ('.' | tmSomethingReadIn | tmHexInput): // parse an address range upper limit -#ifdef useSWEET64trace - case (0x1B | tmSomethingReadIn | tmHexInput): // parse a specific SWEET64 argument hexadecimal value input digit -#endif // useSWEET64trace - case (0x0D | tmSomethingReadIn | tmHexInput): // parse a specific main program variable value input hexadecimal digit - case (0x10 | tmSomethingReadIn | tmHexInput): // parse a specific parameter value input hexadecimal digit - case (0x14 | tmSomethingReadIn | tmHexInput): // parse a specific trip variable measurement value input hexadecimal digit - case (0x16 | tmSomethingReadIn | tmHexInput): // parse a specific volatile variable value input hexadecimal digit - case (tmSomethingReadIn | tmHexInput): // parse a generic hexadecimal digit - switch (j) + case (tmHexInput): // parse a generic hexadecimal digit + case (tmHexInput | tmByteReadIn): // parse a generic hexadecimal digit + switch (chr) { case 'A' ... 'F': - j -= 7; + chr -= 7; case '0' ... '9': - j -= 48; - i = 0; // signal that a valid character was already read in - terminalMode |= (tmSomethingReadIn); - terminalByte = SWEET64::runPrgm(prgmParseHexDigit, j); + chr -= 48; + i = 0; // signal that a valid character was read in + terminalMode |= (tmByteReadIn); + terminalByte = SWEET64::runPrgm(prgmParseHexDigit, chr); break; default: @@ -561,48 +761,34 @@ static void terminal::mainProcess(void) } break; - case '.': // parse an address range upper limit -#ifdef useSWEET64trace - case 0x1B: // parse a specific SWEET64 argument hexadecimal value input digit -#endif // useSWEET64trace - case 0x0D: // parse a specific main program decimal digit variable input decimal digit or switch to hex mode - case 0x10: // parse a specific parameter decimal digit input decimal digit or switch to hex mode - case 0x14: // parse a specific trip variable measurement decimal digit input decimal digit or switch to hex mode - case 0x16: // parse a specific volatile variable decimal digit input decimal digit or switch to hex mode - case 0x00: // parse a generic decimal digit or switch to hex mode - if ((j == 'X') || (j == '$')) + case (tmDecimalInput): // parse a generic decimal digit or switch to hex mode + if ((chr == 'X') || (chr == '$')) { - terminalMode |= (tmHexInput); - i = 0; // signal that a valid character was already read in + terminalMode &= ~(tmDecimalInput); // clear decimal input mode + terminalMode |= (tmHexInput); // set hexadecimal input mode + i = 0; // signal that a valid character was read in break; } - case ('.' | tmSomethingReadIn): // parse an address range upper limit -#ifdef useSWEET64trace - case (0x1B | tmSomethingReadIn): // parse a specific SWEET64 argument hexadecimal value input digit -#endif // useSWEET64trace - case (0x0D | tmSomethingReadIn): // parse a specific main program variable decimal digit - case (0x10 | tmSomethingReadIn): // parse a specific parameter decimal digit - case (0x14 | tmSomethingReadIn): // parse a specific trip variable measurement decimal digit - case (0x16 | tmSomethingReadIn): // parse a specific volatile variable decimal digit - case (tmSomethingReadIn): // parse a generic decimal digit - switch (j) + case (tmDecimalInput | tmByteReadIn): // parse a generic decimal digit + switch (chr) { case '0' ... '9': - j -= 48; - i = 0; // signal that a valid character was already read in - terminalMode |= (tmSomethingReadIn); - terminalByte = SWEET64::runPrgm(prgmParseDecimalDigit, j); + chr -= 48; + i = 0; // signal that a valid character was read in + terminalMode |= (tmByteReadIn); + terminalByte = SWEET64::runPrgm(prgmParseDecimalDigit, chr); break; default: break; } - default: // nothing to parse - could be a possible command + + default: // nothing to parse - could be a possible command break; } @@ -610,104 +796,221 @@ static void terminal::mainProcess(void) if (i) // parsing wasn't valid, so check for a command { - if (chr > 0x5F) chr &= 0x5F; nextTerminalState = 2; // get another character from input buffer switch (chr) { +#if defined(useDebugTerminalHelp) case '?': // display help terminalLine = 0; // initialize terminal output line - terminalMode = tmHexInput; // shift to parsing a generic input value + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to parsing a generic input value terminalState = 12; // this command WILL print a lot of different lines, so handle this command one iteration at a time break; +#endif // defined(useDebugTerminalHelp) + case '.': // specify source address + if (terminalMode & tmButtonInput) // if in button injection mode, reset input mode and pending command + { + + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to parsing a generic input value + terminalState = nextTerminalState; // go fetch next command + + } + else + { + + terminalSource = terminalByte; // save source start byte value + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitHex | tmSourceReadIn); // shift to hex input + + } + + break; + + case '<': // specify target address + if (terminalMode & tmButtonInput) // if in button injection mode, reset input mode and pending command + { + + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to parsing a generic input value + terminalState = nextTerminalState; // go fetch next command + + } + else + { + + terminalTarget = terminalByte; // save source start byte value + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitHex | tmTargetReadIn); // shift to hex input + + } + + break; + + case 'S': // print system status + terminal::outputFlags(activityFlags, terminalActivityFlagStr); + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to reading hex words + break; + + case 'I': // inject button press + terminalCmd = chr; // save command for later + terminalMode = tmInitButton; // shift to reading button press words + break; + #ifdef useSWEET64trace case 0x0C: + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to parsing a generic input value + terminalState = nextTerminalState; // go fetch next command + break; + #endif // useSWEET64trace case 'L': // list available trip functions from terminalIdx case 'M': // list available main program variables case 'O': // list available program constants case 'P': // list available stored parameters case 'T': // list available trip variable measurements + case 'U': // list a range of decimal numbers case 'V': // list available volatile variables - i = terminalMode; // save old terminal mode - terminalMode = chr; // prepare to shift to parsing an array-specific input value + terminalCmd = chr; // save command for later + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitDecimal); // shift to decimal input chr = '>'; // do unified list output preparation break; - case '.': // specify address range - terminalAddress = terminalByte; - terminalMode = (chr | tmHexInput); // shift to reading button press words - break; + case 'R': // read trip variable into terminal + if (terminalMode & tmButtonInput) // if in button injection mode, reset input mode and pending command + { - case 'I': // inject button press - terminalMode = chr; // shift to reading button press words - break; + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to parsing a generic input value + terminalState = nextTerminalState; // go fetch next command - case 'W': // write trip variable - terminalLine = terminalByte; - terminalByte = terminalIdx; - terminalState = 20; - break; + } + else + { - case 'R': // read trip variable into terminal - terminalLine = terminalIdx; - terminalState = 20; - break; + // if no target was read in, assume terminal trip index + if ((terminalMode & tmTargetReadIn) == 0) terminalTarget = terminalIdx; + + // if no source was read in, assume terminal trip index + if ((terminalMode & tmByteReadIn) == 0) terminalByte = terminalIdx; + + if (terminalTarget != terminalByte) // if target and source are not the same + { + + if (terminalTarget >= tripSlotTotalCount) + { + + text::stringOut(devDebugTerminal, PSTR("Invalid target trip variable specified\r")); + terminalState = 0; + + } + else if (terminalByte >= tripSlotTotalCount) + { + + text::stringOut(devDebugTerminal, PSTR("Invalid source trip variable specified\r")); + terminalState = 0; + + } + else + { + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + SWEET64::runPrgm(prgmLoadTrip, terminalByte); // this allows direct loading/saving of trips to EEPROM + SWEET64::runPrgm(prgmSaveTrip, terminalTarget); + + SREG = oldSREG; // restore interrupt flag status + + text::stringOut(devDebugTerminal, PSTR("transferred ")); + text::stringOut(devDebugTerminal, terminalTripVarNames, terminalByte); + text::stringOut(devDebugTerminal, PSTR(" to ")); + text::stringOut(devDebugTerminal, terminalTripVarNames, terminalTarget); + + terminalState = nextTerminalState; // go fetch next command + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to reading hex words + + } + + } + else // source and target trip variables are the same, output a list of available trip variables + { + + terminalCmd = chr; // save command for later + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitDecimal); // shift to decimal input + chr = '>'; // do unified list output preparation + + } + + } - case 'S': // print system status - terminal::outputFlags(activityFlags, terminalActivityFlagStr); - terminalMode = tmHexInput; // shift to parsing a generic input value break; case 0x0D: // carriage return - treat as a special space nextTerminalState = 0; // when finished processing, go back to terminal state 0 - initialize input and print prompt character case ' ': // space character - switch (terminalMode) + switch (terminalCmd) { - case ('I' | tmSomethingReadIn): - peripheral::injectButton(terminalByte); // inject the parsed button press value into timer0 - terminalState = 14; - terminalMode &= ~(tmSomethingReadIn); // go parse another button press value + case 'I': // inject button press + if (terminalMode & tmByteReadIn) + { + + button::inject(terminalByte); // inject the parsed button press value into timer0 + terminalState = 14; + terminalMode |= (tmInitInput); // go parse another button press value + + } + break; -#ifdef useSWEET64trace - case 0x1B: // if no address was specified - primaryFunc = 0; -#endif // useSWEET64trace - case 'L': // if no address was specified - case 'M': // if no address was specified - case 'O': // if no address was specified - case 'P': // if no address was specified - case 'T': // if no address was specified - case 'V': // if no address was specified - case (0x0D): // if no values were input - case (0x10): // if no values were input - case (0x14): // if no values were input - case (0x16): // if no values were input - terminalState = 32; // this command could print a lot of different lines, so handle this command one iteration at a time + case 'P': // list available stored parameters + //text::hexByteOut(devDebugTerminal, terminalMode); + if ((terminalMode & tmAddressReadIn) && (terminalMode & tmByteReadIn) && ((terminalMode & tmSourceReadIn) == 0) && (prgmPtr)) + { + + parameterEdit::onEEPROMchange(prgmPtr, terminalAddress++); + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitDecimal); // shift to reading a new decimal or hexadecimal value + + } + else terminalState = 32; // this command could print a lot of different lines, so handle this command one iteration at a time + break; - case (0x10 | tmSomethingReadIn | tmHexInput): // process a specific parameter hexadecimal value input - case (0x10 | tmSomethingReadIn): // process a specific parameter decimal value - if (prgmPtr) parameterEdit::onEEPROMchange(prgmPtr, terminalAddress); - terminalAddress = 0; - terminalMode = tmHexInput; // go parse a generic hexadecimal digit - terminalState = nextTerminalState; + case 'M': // list available main program variables + case 'T': // list available trip variable measurements + case 'V': // list available volatile variables + if ((terminalMode & tmAddressReadIn) && (terminalMode & tmByteReadIn) && ((terminalMode & tmSourceReadIn) == 0) && (prgmPtr)) + { + + SWEET64::runPrgm(prgmPtr, terminalAddress++); + terminalMode &= ~(tmInputMask); // clear input mode processing bits + terminalMode |= (tmInitDecimal); // shift to reading a new decimal or hexadecimal value + + } + else terminalState = 32; // this command could print a lot of different lines, so handle this command one iteration at a time + + break; + + case 'L': // list available trip functions from terminalIdx + case 'O': // list available program constants + case 'R': // list available trip variables + case 'U': // list a range of decimal numbers + terminalState = 32; // this command could print a lot of different lines, so handle this command one iteration at a time break; - case (0x0D | tmSomethingReadIn | tmHexInput): // process a specific main program variable hexadecimal value input - case (0x14 | tmSomethingReadIn | tmHexInput): // process a specific trip variable measurement hexadecimal value input - case (0x16 | tmSomethingReadIn | tmHexInput): // process a specific volatile variable hexadecimal value input - case (0x0D | tmSomethingReadIn): // process a specific main program variable decimal value - case (0x14 | tmSomethingReadIn): // process a specific trip variable measurement decimal value - case (0x16 | tmSomethingReadIn): // process a specific volatile variable decimal value - if (prgmPtr) SWEET64::runPrgm(prgmPtr, terminalAddress); default: - terminalAddress = 0; - terminalMode = tmHexInput; // go parse a generic hexadecimal digit - terminalState = nextTerminalState; + terminalState = nextTerminalState; // go fetch next command + terminalCmd = 0; // reset any pending commands + terminalMode = tmInitHex; // shift to reading hex words break; } @@ -728,13 +1031,10 @@ static void terminal::mainProcess(void) maxLine = 0; prgmPtr = 0; labelList = 0; - switch (terminalMode) + + switch (terminalCmd) { -#ifdef useSWEET64trace - case 0x0C: // generate SWEET64 source code for a given function - terminalMode = 0x1B; -#endif // useSWEET64trace case 'L': // list available trip functions from terminalIdx maxLine = dfMaxValDisplayCount; #if (useDebugTerminalLabels) || (useSWEET64trace) @@ -770,6 +1070,13 @@ static void terminal::mainProcess(void) prgmPtr = prgmTerminalWriteParameterValue; break; + case 'R': // list available trip variables + maxLine = tripSlotTotalCount; +#ifdef useDebugTerminalLabels + labelList = terminalTripVarNames; +#endif // useDebugTerminalLabels + break; + case 'T': // list available trip variable measurements maxLine = rvMeasuredCount; #ifdef useDebugTerminalLabels @@ -780,6 +1087,11 @@ static void terminal::mainProcess(void) prgmPtr = prgmWriteTripMeasurementValue; break; + case 'U': // list a range of decimal numbers + maxLine = 11; + primaryFunc = terminal::outputDecimalValue; + break; + case 'V': // list available volatile variables maxLine = vVariableMaxIdx; #ifdef useDebugTerminalLabels @@ -794,75 +1106,85 @@ static void terminal::mainProcess(void) } - if (i & tmSomethingReadIn) // examine old terminal mode to see if a hex byte was read in + if (terminalCmd == 'U') // handle decimal format in a special case { - if (terminalByte < maxLine) + if (terminalMode & tmByteReadIn) decPlace = terminalByte; + + if (terminalMode & tmSourceReadIn) decWindow = terminalSource; + + if (terminalMode & tmTargetReadIn) decMode = terminalTarget; + + terminalLine = 0; + + } + else + { + + if (terminalMode & tmSourceReadIn) { - switch (i) + if (terminalSource >= maxLine) + { + + text::stringOut(devDebugTerminal, PSTR("index start value too large\r")); + terminalState = 0; // go back to terminal state 0 - initialize input and print prompt character + + } + else { - case (tmSomethingReadIn | tmHexInput): - case (tmSomethingReadIn): - terminalLine = terminalByte; // if a hex byte was read in and is less than maxLine, use it - maxLine = terminalByte; // only output one line + terminalLine = terminalSource; + + if (terminalMode & tmByteReadIn) + { - if (prgmPtr) // if this command could result in storing a value instead + if (terminalByte >= maxLine) { - terminalMode &= 0x1F; // go parse a decimal or hex value for possible saving - terminalAddress = terminalByte; // save for possible saving + text::stringOut(devDebugTerminal, PSTR("index end value too large\r")); + terminalState = 0; // go back to terminal state 0 - initialize input and print prompt character } - break; + else + { - case ('.' | tmSomethingReadIn | tmHexInput): - case ('.' | tmSomethingReadIn): - if (terminalAddress < terminalByte) terminalLine = terminalAddress; - else terminalLine = terminalByte; + maxLine = terminalByte + 1; - maxLine = terminalByte + 1; - prgmPtr = 0; - break; + if (terminalLine >= maxLine) maxLine = terminalLine + 1; - default: - break; + } + + } } } - else // otherwise + else { - text::stringOut(devDebugTerminal, PSTR("input value too large\r")); - terminalState = 0; // go back to terminal state 0 - initialize input and print prompt character - - } + if (terminalMode & tmByteReadIn) + { - } - else - { + if (terminalByte >= maxLine) + { - prgmPtr = 0; // no address was specified, so do not store anything - switch (i) - { + text::stringOut(devDebugTerminal, PSTR("index value too large\r")); + terminalState = 0; // go back to terminal state 0 - initialize input and print prompt character - case ('.' | tmHexInput): - case '.': - if (terminalAddress < maxLine) terminalLine = terminalAddress; + } else { - text::stringOut(devDebugTerminal, PSTR("input value too large\r")); - terminalState = 0; // go back to terminal state 0 - initialize input and print prompt character + terminalAddress = terminalByte; + terminalMode |= (tmAddressReadIn); + terminalLine = terminalByte; + maxLine = terminalByte + 1; } - break; - default: - terminalLine = 0; - break; + } + else terminalLine = 0; } @@ -873,15 +1195,17 @@ static void terminal::mainProcess(void) } break; +#if defined(useDebugTerminalHelp) case 12: // print a line of help text::stringOut(devDebugTerminal, terminalHelp, terminalLine++); if (pgm_read_byte(findStr(terminalHelp, terminalLine)) == 0) terminalState = nextTerminalState; break; +#endif // defined(useDebugTerminalHelp) case 14: // wait for injected buttonpress to be accepted into timer0 if (timer0Command & t0cProcessButton) break; terminalState++; - peripheral::injectButton(buttonsUp); // inject a buttons-up press into timer0 + button::inject(buttonsUp); // inject a buttons-up press into timer0 break; case 15: // wait for injected buttonpress to be accepted into timer0 @@ -889,54 +1213,6 @@ static void terminal::mainProcess(void) terminalState = nextTerminalState; break; - case 20: - if (terminalMode & 0x80) // if a hex byte was read in - { - - if (terminalByte >= tripSlotTotalCount) - { - - text::stringOut(devDebugTerminal, PSTR("Invalid trip variable specified\r")); - terminalState = 0; - break; - - } - else - { - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operation atomic - - termRawIdx = terminalByte; - SWEET64::runPrgm(prgmLoadTrip, terminalByte); // this allows direct loading/saving of trips to EEPROM - SWEET64::runPrgm(prgmSaveTrip, terminalLine); - - SREG = oldSREG; // restore interrupt flag status - - text::stringOut(devDebugTerminal, PSTR("transferred ")); - text::stringOut(devDebugTerminal, terminalTripVarNames, terminalByte); - text::stringOut(devDebugTerminal, PSTR(" to ")); - text::stringOut(devDebugTerminal, terminalTripVarNames, terminalLine); - - terminalState = nextTerminalState; // go fetch next command - terminalMode = tmHexInput; // shift to reading hex words - break; - - } - - } - terminalState = 32; - terminalMode = tmHexInput; // shift to reading hex words - terminalLine = 0; - maxLine = tripSlotTotalCount; -#ifdef useDebugTerminalLabels - labelList = terminalTripVarNames; -#else // useDebugTerminalLabels - labelList = 0; -#endif // useDebugTerminalLabels - primaryFunc = 0; - extraFunc = 0; - case 32: // output list of selected items text::hexByteOut(devDebugTerminal, terminalLine); text::stringOut(devDebugTerminal, PSTR(": ")); @@ -991,19 +1267,19 @@ static uint8_t debugReading::displayHandler(uint8_t cmd, uint8_t cursorPos, uint { case 0: - peripheral::changeBitFlags(debugFlags, 0, (debugInjectorFlag | debugVSSflag)); + changeBitFlags(debugFlags, 0, (debugInjectorFlag | debugVSSflag)); break; case 1: - peripheral::changeBitFlags(debugFlags, debugInjectorFlag, debugVSSflag); + changeBitFlags(debugFlags, debugInjectorFlag, debugVSSflag); break; case 2: - peripheral::changeBitFlags(debugFlags, (debugInjectorFlag | debugVSSflag), 0); + changeBitFlags(debugFlags, (debugInjectorFlag | debugVSSflag), 0); break; case 3: - peripheral::changeBitFlags(debugFlags, debugVSSflag, debugInjectorFlag); + changeBitFlags(debugFlags, debugVSSflag, debugInjectorFlag); break; default: @@ -1131,4 +1407,89 @@ static void debugReading::configurePorts(void) } +static void debugReading::idleProcessFuel(void) +{ + + debugFIPidx++; + if (debugFIPidx >= debugFIPlength) + { + + debugFIPidx = 0; + debugFIPstate++; + debugFIPstate &= 3; + + } + + switch (debugFIPstate) + { + + case 0: + debugFIPtickLength = pgm_read_word(&debugFIPvalues[(unsigned int)(debugFIPidx)]); + debugFIPWreadTickLength = pgm_read_word(&debugFIPWvalues[(unsigned int)(debugFIPidx)]); + debugFIPWgoodTickLength = debugFIPtickLength - 63; + changeBitFlags(debugFlags, 0, debugFIPready); + break; + + case 1: + break; + + case 2: + debugFIPtickLength = pgm_read_word(&debugFIPvalues[(unsigned int)(debugFIPlength - debugFIPidx - 1)]); + debugFIPWreadTickLength = pgm_read_word(&debugFIPWvalues[(unsigned int)(debugFIPlength - debugFIPidx - 1)]); + debugFIPWgoodTickLength = debugFIPtickLength - 63; + changeBitFlags(debugFlags, 0, debugFIPready); + break; + + case 3: + break; + + default: + break; + + } + + if (debugFIPWreadTickLength > debugFIPWgoodTickLength) debugFIPWreadTickLength = debugFIPWgoodTickLength; + else debugFIPWtickLength = debugFIPWreadTickLength; + +} + +static void debugReading::idleProcessVSS(void) +{ + + debugVSSidx++; + if (debugVSSidx >= debugVSSlength) + { + + debugVSSidx = 0; + debugVSSstate++; + debugVSSstate &= 3; + + } + + switch (debugVSSstate) + { + + case 0: + debugVSStickLength = pgm_read_word(&debugVSSvalues[(unsigned int)(debugVSSidx)]); + changeBitFlags(debugFlags, 0, debugVSSready); + break; + + case 1: + break; + + case 2: + debugVSStickLength = pgm_read_word(&debugVSSvalues[(unsigned int)(debugVSSlength - debugVSSidx - 1)]); + changeBitFlags(debugFlags, 0, debugVSSready); + break; + + case 3: + break; + + default: + break; + + } + +} + #endif // useSimulatedFIandVSS diff --git a/mpguino_tav/feature_dragrace.h b/mpguino_tav/feature_dragrace.h index 0943cd9..7a94628 100644 --- a/mpguino_tav/feature_dragrace.h +++ b/mpguino_tav/feature_dragrace.h @@ -5,6 +5,7 @@ namespace accelerationTest /* Acceleration Test support section prototype */ void goDisplay(void); void goTrigger(void); uint8_t triggerTest(void); + void idleProcess(void); } diff --git a/mpguino_tav/feature_dragrace.ino b/mpguino_tav/feature_dragrace.ino index 81502df..233f710 100644 --- a/mpguino_tav/feature_dragrace.ino +++ b/mpguino_tav/feature_dragrace.ino @@ -241,4 +241,108 @@ uint8_t accelerationTest::triggerTest(void) } +void accelerationTest::idleProcess(void) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + accelTestStatus = lastAccelTestStatus; // copy last loop's accel test flag status to this loop + lastAccelTestStatus = accelerationFlags; // copy current accel test flag status for next loop + + SREG = oldSREG; // restore interrupt flag status + + accelTestStatus = (lastAccelTestStatus ^ accelTestStatus) & accelTestClearFlags; // detect any drag race flag changes + + if (accelTestStatus) + { + + accelTestState = accelerationFlags & accelTestClearFlags; + + switch (accelTestState) + { + + case (accelTestTriggered | accelTestFullSpeed | accelTestHalfSpeed | accelTestDistance): + accelTestState = 1; + break; + + case (accelTestActive | accelTestFullSpeed | accelTestHalfSpeed | accelTestDistance): + accelTestState = 2; + break; + + case (accelTestFinished): + if (SWEET64::runPrgm(prgmAccelTestCompareFullSpeeds, 0)) + { + + tripVar::transfer(dragRawHalfSpeedIdx, dragHalfSpeedIdx); + tripVar::transfer(dragRawFullSpeedIdx, dragFullSpeedIdx); + tripVar::transfer(dragRawDistanceIdx, dragDistanceIdx); + + } + + accelTestState = 3; + break; + + case (accelTestFinished | accelTestCancelled): + accelTestState = 4; + break; + + case (accelTestActive | accelTestFullSpeed | accelTestHalfSpeed): + accelTestState = 5; + break; + + case (accelTestActive | accelTestFullSpeed | accelTestDistance): + accelTestState = 6; + break; + + case (accelTestActive | accelTestFullSpeed): + accelTestState = 7; + break; + + case (accelTestActive | accelTestHalfSpeed | accelTestDistance): + accelTestState = 8; + break; + + case (accelTestActive | accelTestHalfSpeed): + accelTestState = 9; + break; + + case (accelTestActive | accelTestDistance): + accelTestState = 10; + break; + + case (accelTestActive): + accelTestState = 11; + break; + + default: + accelTestState = 12; + break; + + } + + } + else + { + + accelTestState = 0; + + if (accelerationFlags & accelTestFinished) + { + + if (EEPROM::readVal(pDragAutoFlagIdx)) + { + + if (accelerationTest::triggerTest() == 0) accelTestState = 1; + + } + + } + + } + +} + #endif // useDragRaceFunction diff --git a/mpguino_tav/feature_outputpin.h b/mpguino_tav/feature_outputpin.h new file mode 100644 index 0000000..b2fb6ba --- /dev/null +++ b/mpguino_tav/feature_outputpin.h @@ -0,0 +1,12 @@ +#if defined(useOutputPins) +namespace outputPin +{ + + static void init(void); + static void shutdown(void); + static void setOutputPin1(uint8_t pin); + static void setOutputPin2(uint8_t pin); + +}; + +#endif // defined(useOutputPins) diff --git a/mpguino_tav/feature_outputpin.ino b/mpguino_tav/feature_outputpin.ino new file mode 100644 index 0000000..d742757 --- /dev/null +++ b/mpguino_tav/feature_outputpin.ino @@ -0,0 +1,214 @@ +#if defined(useOutputPins) +/* Analog output pin driver section */ + +/* + Modes + 0 Off + 1 instant fuel economy < current fuel economy (0 - false, 255 - true) + 2 instant fuel economy > current fuel economy (0 - false, 255 - true) + 3 instant fuel economy < tank fuel economy (0 - false, 255 - true) + 4 instant fuel economy > tank fuel economy (0 - false, 255 - true) + 5 estimated tank fuel consumed (0 (none) to 255 (all of the tank), based on tank size) + 6 estimated tank fuel remaining (0 (empty) to 255 (full), based on tank size) +*/ +static const uint8_t prgmCalculateOutputPinValue[] PROGMEM = { + instrCmpIndex, 2, // is a valid expansion output pin number being requested? + instrBranchIfGTorE, 13, // skip to output a zero if not + instrLxdIEEPROMoffset, pOutputPin1Mode, // load the indexed stored parameter index for the expansion output pin setting + instrTestIndex, // test pin mode value for zero + instrBranchIfZero, 8, // exit out if pin mode is zero + instrCmpIndex, 4, // test if pin mode is "fuel economy comparison between instant and whatever" + instrBranchIfLTorE, 26, // if so, skip ahead + instrCmpIndex, 6, // test if pin mode is analog output tank quantity or quantity remaining + instrBranchIfLTorE, 4, // if so, skip ahead + +//zeroOutRet: + instrLdRegByte, 0x02, 0, // zero out result + instrDone, // exit to caller + +//analogOut: + instrCall, tCalculateRemainingTank, // fetch remaining fuel value in injector open cycles + instrCmpIndex, 6, // outputting remaining value? + instrBranchIfE, 7, // go do conversion if so + instrLdReg, 0x21, // shift contents to register 1 + instrLdRegMain, 0x02, mpTankSizeIdx, // fetch calculated tank size in injector open cycles + instrSubYfromX, 0x12, // subtract remaining fuel value from tank size + +//analogOut2: + instrMul2byByte, 255, // multiply tank quantity by 255 + instrDiv2byMain, mpTankSizeIdx, // divide by calculated tank size + instrDone, // return to caller + +// US (inst FE > accumulated FE) = /(inst FE <= accumulated FE) +// +// (inst distance) (accum distance) +// --------------- <= ---------------- >>> (inst distance) * (accum quantity) <= (inst quantity) * (accum distance) +// (inst quantity) (accum quantity) +// +// +// +// metric (inst FE > accumulated FE) = /(inst FE <= accumulated FE) +// +// (inst quantity) (accum quantity) +// --------------- => ---------------- >>> (inst quantity) * (accum distance) => (inst distance) * (accum quantity) +// (inst distance) (accum distance) or +// (inst distance) * (accum quantity) <= (inst quantity) * (accum distance) +// +// therefore, for (inst FE > accumulated FE) comparison, there is no need to check whether MPGuino is in metric mode or not +// (inst FE < accumulated FE) is treated in a similar way, but the left and right terms are swapped around +// + instrCmpIndex, 2, // comparing instant to current? + instrBranchIfLTorE, 10, // if so, skip ahead + instrLdRegTripVar, 0x03, tankIdx, rvInjCycleIdx, // fetch tank (accum quantity) + instrLdRegTripVar, 0x02, tankIdx, rvVSSpulseIdx, // fetch tank (accum distance) + instrSkip, 8, // skip ahead + instrLdRegTripVar, 0x03, currentIdx, rvInjCycleIdx, // fetch current (accum quantity) + instrLdRegTripVar, 0x02, currentIdx, rvVSSpulseIdx, // fetch current (accum distance) + instrLdRegTripVar, 0x01, instantIdx, rvInjCycleIdx, // fetch (inst quantity) + instrMul2by1, // calculate (inst quantity) * (accum distance) as right term + instrSwapReg, 0x23, // swap right term and (accum quantity) values + instrLdRegTripVar, 0x01, instantIdx, rvVSSpulseIdx, // fetch (inst distance) + instrMul2by1, // calculate (inst distance) * (accum quantity) as left term + instrCmpIndex, 2, // testing (inst distance) * (current quantity) <= (inst quantity) * (current distance)? + instrBranchIfE, 6, // if so, skip ahead + instrCmpIndex, 4, // testing (inst distance) * (tank quantity) <= (inst quantity) * (tank distance)? + instrBranchIfE, 2, // if so, skip ahead + instrSwapReg, 0x23, // swap left and right terms + instrCmpXtoY, 0x32, // compare left term to right term + instrBranchIfLTorE, 4, // if left term <= right term, go zero out and return + + instrLdRegByte, 0x02, 255, // max out result + instrDone, // return to caller + + instrLdRegByte, 0x02, 0, // zero out result + instrDone // exit to caller +}; + +static void outputPin::init(void) +{ + +#if defined(__AVR_ATmega32U4__) + // set OC4A to clear-up/set-down PWM mode for EXP1 option pin + TCCR4A &= ~(1 << COM4A0); + TCCR4A |= ((1 << COM4A1) | (1 << PWM4A)); + + // set OC4D to clear-up/set-down PWM mode for EXP2 option pin + TCCR4C &= ~(1 << COM4D0); + TCCR4C |= ((1 << COM4D1) | (1 << PWM4D)); + + // enable EXP1 and EXP2 option pin outputs + DDRC |= (1 << DDC6); // set OC4A as output + DDRD |= (1 << DDD7); // set OC4D as output + +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + // set OC1B to clear-up/set-down for EXP1 option pin + TCCR1A &= ~(1 << COM1B0); + TCCR1A |= (1 << COM1B1); + + // set OC2A to clear-up/set-down for EXP2 option pin + TCCR2A &= ~(1 << COM2A0); + TCCR2A |= (1 << COM2A1); + + // enable EXP1 and EXP2 option pin outputs + DDRB |= ((1 << PB6) | (1 << PB4)); + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // set OC1B to non-inverting mode for EXP1 option pin + TCCR1A &= ~(1 << COM1B0); + TCCR1A |= (1 << COM1B1); + + // set OC2A to clear-up/set-down for EXP2 option pin + TCCR2A &= ~(1 << COM2A0); + TCCR2A |= (1 << COM2A1); + + // enable EXP1 and EXP2 option pin outputs + DDRB |= ((1 << PB3) | (1 << PB2)); + +#endif // defined(__AVR_ATmega328P__) + setOutputPin1(2); // initially set EXP1 option pin to 0 + setOutputPin2(2); // initially set EXP2 option pin to 0 + +} + +static void outputPin::shutdown(void) +{ + + setOutputPin1(2); // set EXP1 option pin to 0 + setOutputPin2(2); // set EXP2 option pin to 0 + +#if defined(__AVR_ATmega32U4__) + // disable expansion pin output + DDRC &= ~(1 << DDC6); + DDRD &= ~(1 << DDD7); + + // set OC4A to disabled for EXP1 option pin + TCCR4A &= ~((1 << COM4A1) | (1 << COM4A0) | (1 << PWM4A)); + + // set OC4D to disabled for EXP2 option pin + TCCR4C &= ~((1 << COM4D1) | (1 << COM4D0) | (1 << PWM4D)); + +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + // disable expansion pin output + DDRB &= ~((1 << PB6) | (1 << PB4)); + + // set OC1B to disabled for EXP1 option pin + TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); + + // set OC2A to disabled for EXP2 option pin + TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // disable expansion pin output + DDRB &= ~((1 << PB3) | (1 << PB2)); + + // set OC1B to disabled for EXP1 option pin + TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); + + // set OC2A to disabled for EXP2 option pin + TCCR2A &= ~(1 << COM2A0); + TCCR2A |= (1 << COM2A1); + +#endif // defined(__AVR_ATmega328P__) +} + +// sets EXP1 option pin PWM output from 0-100% +static void outputPin::setOutputPin1(uint8_t pin) +{ + + uint8_t val = SWEET64::runPrgm(prgmCalculateOutputPinValue, pin); + +#if defined(__AVR_ATmega32U4__) + OCR4A = val; +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + OCR1B = val; +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + OCR1B = val; +#endif // defined(__AVR_ATmega328P__) + +} + +// sets EXP2 option pin PWM output from 0-100% +static void outputPin::setOutputPin2(uint8_t pin) +{ + + uint8_t val = SWEET64::runPrgm(prgmCalculateOutputPinValue, pin); + +#if defined(__AVR_ATmega32U4__) + OCR4D = val; +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + OCR2A = val; +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + OCR2A = val; +#endif // defined(__AVR_ATmega328P__) + +} + +#endif // defined(useOutputPins) diff --git a/mpguino_tav/feature_settings.ino b/mpguino_tav/feature_settings.ino index 52e6a50..2d17bb7 100644 --- a/mpguino_tav/feature_settings.ino +++ b/mpguino_tav/feature_settings.ino @@ -103,7 +103,7 @@ static uint8_t parameterEdit::sharedFunctionCall(uint8_t cmd) SWEET64::runPrgm(prgmFetchParameterValue, parameterPtr); case nesLoadValue: - ull2str(tFormatToNumber, pBuff, 3); + ull2str(pBuff, 3, tFormatToNumber); parameterEdit::findLeft(); case nesOnChange: @@ -370,7 +370,7 @@ static void parameterEdit::save(void) { case 10: - str2ull(pBuff); // convert parameter string to a number + str2ull(pBuff); // convert parameter buffer string into uint64_t #ifdef usePartialRefuel if (numberEditObj.parameterIdx == pRefuelSizeIdx) SWEET64::runPrgm(prgmAddToPartialRefuel, 0); #endif // usePartialRefuel @@ -552,7 +552,7 @@ static void partialRefuel::select(void) break; default: - noSupport(); + menu::noSupport(); break; } diff --git a/mpguino_tav/functions.h b/mpguino_tav/functions.h index 7127ae4..6996095 100644 --- a/mpguino_tav/functions.h +++ b/mpguino_tav/functions.h @@ -614,20 +614,23 @@ static const uint8_t prgmAlternatorChannel[] PROGMEM = { static const uint8_t prgmRoundOffNumber[] PROGMEM = { instrTestReg, 0x02, // test register 2 instrBranchIfOverflow, 23, // if register 2 has overflow value, exit + instrCmpIndex, 2, // check if 3 or more right hand digits were specified + instrBranchIfGT, 17, // if so, just exit + instrBranchIfE, 12, // if 2 right hand digits were specified, round to nearest 100th instrCmpIndex, 1, // check if 0 or 1 right-hand digits were specified - instrBranchIfLT, 11, // branch if 0 right-hand digits were specified - instrBranchIfE, 14, // branch if 1 right-hand digit was specified - instrCmpIndex, 2, // check if 2 right-hand digits were specified - instrBranchIfGT, 13, // skip if 3 or more right-hand digits were specified - instrAddByteToX, 0x02, 5, // round off to nearest 1/100th - instrSkip, 8, // skip to exit + instrBranchIfE, 4, // if 1 right hand digit was specified, round to nearest 10th + instrDiv2byConst, idxDecimalPoint, // shift number right 3 digits to round to nearest whole digit + instrSkip, 6, // skip to adjustment -//roundint: - instrAddConstToX, 0x02, idxNumber500, // round off to nearest whole integer - instrSkip, 3, // skip to exit +//to10ths: + instrDiv2byByte, 100, // shift number right 2 digits + instrSkip, 2, // skip to adjustment -//round10th: - instrAddByteToX, 0x02, 50, // round off to nearest 1/10th +//to100ths: + instrDiv2byByte, 10, // shift number right 1 digit + +//adjust: + instrAdjustQuotient, // bump up quotient by adjustment term (0 if remainder/divisor < 0.5, 1 if remainder/divisor >= 0.5) //exit: instrJump, tFormatToNumber // go call prgmFormatToNumber to perform actual formatting @@ -906,51 +909,6 @@ static const uint8_t prgmPressureChannel[] PROGMEM = { instrDone // exit to caller }; -static const uint8_t prgmCalculateMAPpressure[] PROGMEM = { - instrLdRegVoltage, 0x02, analogMAPchannelIdx, // load analog channel ADC step value - instrSubMainFromX, 0x02, mpAnalogMAPfloorIdx, // is reading below MAP sensor voltage floor? - instrBranchIfLT, 3, // if not, continue - instrLdRegByte, 0x02, 0, // zero out result in register 2 - -//cont1: - instrMul2byMain, mpAnalogMAPnumerIdx, // perform conversion to get pressure units per volts value - instrDiv2byMain, mpAnalogMAPdenomIdx, // divide by pressure units per volts value - instrAddEEPROMtoX, 0x02, pMAPsensorOffsetIdx, // add pressure offset value from EEPROM - instrStRegMain, 0x02, mpMAPpressureIdx, // store resulting MAP sensor reading -#ifdef useChryslerBaroSensor - instrDone // exit to caller -}; - -static const uint8_t prgmCalculateBaroPressure[] PROGMEM = { - instrLdRegVoltage, 0x02, analogBaroChannelIdx, // load analog channel ADC step value - instrSubMainFromX, 0x02, mpAnalogBaroFloorIdx, // is reading below barometric sensor voltage floor? - instrBranchIfLT, 3, // if not, continue - instrLdRegByte, 0x02, 0, // zero out result in register 2 - -//cont1: - instrMul2byMain, mpAnalogBaroNumerIdx, // convert to obtain pressure units per volts value - instrDiv2byMain, mpAnalogBaroDenomIdx, // divide by pressure units per volts value - instrAddEEPROMtoX, 0x02, pBaroSensorOffsetIdx, // add pressure offset value from EEPROM - instrStRegMain, 0x02, mpBaroPressureIdx, // store resulting barometric sensor reading -#endif // useChryslerBaroSensor - instrLdRegMain, 0x02, mpFuelPressureIdx, // get fuel system differential pressure - instrAddMainToX, 0x02, mpBaroPressureIdx, // add to reference barometric pressure to get fuel system absolute pressure - instrSubMainFromX, 0x02, mpMAPpressureIdx, // subtract MAP to get differential pressure across the fuel injector - instrStRegMain, 0x02, mpInjPressureIdx, // store differential pressure across the fuel injector - instrMul2byConst, idxCorrectionFactor, // set up for iSqrt - instrDiv2byMain, mpFuelPressureIdx, // divide by the fuel system differential pressure - instrTestReg, 0x02, // test whether overflow occurred - instrBranchIfOverflow, 6, // if overflow occurred, go handle it - instrIsqrt, 0x02, // perform square root on result - instrStRegVolatile, 0x02, vInjectorCorrectionIdx, // save square root of presssure differential ratio as fuel injector correction factor - instrDone, // return to caller - -//cont3: - instrLdRegConst, 0x02, idxCorrectionFactor, - instrStRegVolatile, 0x02, vInjectorCorrectionIdx, // save initial injector correction index for pressure differential calculation - instrDone // return to caller -}; - #endif // useChryslerMAPCorrection #ifdef useDragRaceFunction static const uint8_t prgmDragSpeed[] PROGMEM = { diff --git a/mpguino_tav/functions.ino b/mpguino_tav/functions.ino index 3307db5..79e8873 100644 --- a/mpguino_tav/functions.ino +++ b/mpguino_tav/functions.ino @@ -48,12 +48,12 @@ static calcFuncObj translateCalcIdx(uint8_t tripIdx, uint8_t calcIdx, char * str { - if (thisCalcFuncObj.calcFmtIdx == calcFormatTimeHHmmSSIdx) ull2str(thisCalcFuncObj.calcIdx, strBuff, thisCalcFuncObj.tripIdx); + if (thisCalcFuncObj.calcFmtIdx == calcFormatTimeHHmmSSIdx) ull2str(strBuff, thisCalcFuncObj.tripIdx, thisCalcFuncObj.calcIdx); else { SWEET64::doCalculate(thisCalcFuncObj.tripIdx, thisCalcFuncObj.calcIdx); - formatDecimal(strBuff, windowLength, thisCalcFuncObj.decimalPlaces, decimalFlag); + ull2str(strBuff, thisCalcFuncObj.decimalPlaces, windowLength, decimalFlag); } diff --git a/mpguino_tav/heart.h b/mpguino_tav/heart.h index 82a7fc0..1d7b429 100644 --- a/mpguino_tav/heart.h +++ b/mpguino_tav/heart.h @@ -1,6 +1,20 @@ +#if defined(__AVR_ATmega32U4__) +#ifndef PRTIM4 +#define PRTIM4 4 + +#endif // PRTIM4 +#endif // defined(__AVR_ATmega32U4__) + static void updateVSS(unsigned long thisVSStime); -unsigned long findCycleLength(unsigned long lastCycle, unsigned long thisCycle); -void delay0(unsigned int ms); +static void initCore(void); +static void initHardware(void); +#ifdef useDeepSleep +static void doGoDeepSleep(void); +#endif // useDeepSleep +static uint32_t findCycleLength(unsigned long lastCycle, unsigned long thisCycle); +static void delay0(unsigned int ms); +static void changeBitFlags(volatile uint8_t &flagRegister, uint8_t maskAND, uint8_t maskOR); +static void performSleepMode(uint8_t sleepMode); #ifdef useBuffering typedef struct @@ -343,8 +357,8 @@ static const uint8_t metricMode = 0b00000001; static const uint8_t detectEEPROMchangeFlag = 0b11111100; static const uint8_t fuelEconOutputFlags = 0b00000011; -static char mBuff1[17]; // used by formatDecimal(), translateCalcIdx(), bigDigit::, bar graph routines -static char pBuff[12]; // used by parameterEdit::, clockSet::, function result output routines +static char mBuff1[17]; // used by ull2str(), translateCalcIdx(), bigDigit::, bar graph routines +static char pBuff[14]; // used by parameterEdit::, clockSet::, function result output routines volatile uint8_t lastPINxState; diff --git a/mpguino_tav/heart.ino b/mpguino_tav/heart.ino index 322fcfd..30ead7d 100644 --- a/mpguino_tav/heart.ino +++ b/mpguino_tav/heart.ino @@ -1343,7 +1343,499 @@ static void updateVSS(unsigned long thisVSStime) } -unsigned long findCycleLength(unsigned long lastCycle, unsigned long thisCycle) // this is only to be meant to be used with interrupt handlers +static void initCore(void) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + + // timer0 is the taskmaster driving MPGuino's measurement functionality +#if defined(__AVR_ATmega32U4__) + // turn on timer0 module + PRR0 &= ~(1 << PRTIM0); + + // set timer 0 to fast PWM mode, TOP = 0xFF + TCCR0A |= ((1 << WGM01) | (1 << WGM00)); + TCCR0B &= ~(1 << WGM02); + + // set timer 0 prescale factor to 64 + TCCR0B &= ~(1 << CS02); + TCCR0B |= ((1 << CS01) | (1 << CS00)); + + // set OC0A to disabled + TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); + + // set OC0B to disabled + TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); + + // clear timer 0 output compare force bits for OC0A and OC0B + TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); + + // disable timer 0 output compare interrupts + TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); + + // enable timer 0 overflow interrupt to generate ~1 ms tick + TIMSK0 |= (1 << TOIE0); + + // clear timer 0 interrupt flags + TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); + + // disable digital inputs for all ADC capable pins to reduce power consumption + DIDR0 |= ((ADC7D) | (1 << ADC6D) | (1 << ADC5D) | (1 << ADC4D) | (1 << ADC1D) | (1 << ADC0D)); + DIDR1 |= (1 << AIN0D); + DIDR2 |= ((1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D) | (1 << ADC10D) | (1 << ADC9D) | (1 << ADC8D)); + + // shut off on-board peripherals to reduce power consumption + PRR0 |= ((1 << PRTWI) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRADC)); + PRR1 |= ((1 << PRUSB) | (1 << PRTIM4) | (1 << PRTIM3) | (1 << PRUSART1)); + +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + // turn on timer0 module + PRR0 &= ~(1 << PRTIM0); + + // set timer 0 to fast PWM mode, TOP = 0xFF + TCCR0A |= ((1 << WGM01) | (1 << WGM00)); + TCCR0B &= ~(1 << WGM02); + + // set timer 0 prescale factor to 64 + TCCR0B &= ~(1 << CS02); + TCCR0B |= ((1 << CS01) | (1 << CS00)); + + // set OC0A to disabled + TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); + + // set OC0B to disabled + TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); + + // clear timer 0 output compare force bits for OC0A and OC0B + TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); + + // disable timer 0 output compare interrupts + TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); + + // enable timer 0 overflow interrupt to generate ~1 ms tick + TIMSK0 |= (1 << TOIE0); + + // clear timer 0 interrupt flags + TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); + + // disable digital inputs for all ADC capable pins to reduce power consumption + DIDR0 |= ((1 << ADC7D) | (1 << ADC6D) | (1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D)); + DIDR1 |= ((1 << AIN1D) | (1 << AIN0D)); + DIDR2 |= ((1 << ADC15D) | (1 << ADC14D) | (1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D) | (1 << ADC10D) | (1 << ADC9D) | (1 << ADC8D)); + + // shut off on-board peripherals to reduce power consumption + PRR0 |= ((1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRUSART0) | (1 << PRADC)); + PRR1 |= ((1 << PRTIM5) | (1 << PRTIM4) | (1 << PRTIM3) | (1 << PRUSART3) | (1 << PRUSART2) | (1 << PRUSART1)); + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // turn on timer0 module + PRR &= ~(1 << PRTIM0); + + // set timer 0 to fast PWM mode, TOP = 0xFF + TCCR0A |= ((1 << WGM01) | (1 << WGM00)); + TCCR0B &= ~(1 << WGM02); + + // set timer 0 prescale factor to 64 + TCCR0B &= ~(1 << CS02); + TCCR0B |= ((1 << CS01) | (1 << CS00)); + + // set OC0A to disabled + TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); + + // set OC0B to disabled + TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); + + // clear timer 0 output compare force bits for OC0A and OC0B + TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); + + // disable timer 0 output compare interrupts + TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); + + // enable timer 0 overflow interrupt to generate ~1 ms tick + TIMSK0 |= (1 << TOIE0); + + // clear timer 0 interrupt flags + TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); + + // disable digital inputs for all ADC capable pins to reduce power consumption + DIDR0 |= ((1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D)); + DIDR1 |= ((1 << AIN1D) | (1 << AIN0D)); + + // shut off on-board peripherals to reduce power consumption + PRR |= ((1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRUSART0) | (1 << PRADC)); + +#endif // defined(__AVR_ATmega328P__) + ACSR &= ~(1 << ACIE); // disable analog comparator interrupt + ACSR |= (1 << ACD); // disable analog comparator module + ADCSRB &= ~(1 << ACME); // disable analog comparator multiplexer + + timer0Command = t0cResetTimer; +#ifdef useTimer1Interrupt + timer1Command = t1cResetTimer; +#endif // useTimer1Interrupt + + SREG = oldSREG; // restore interrupt flag status + +} + +static void initHardware(void) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + + // timer initialization section - multiple peripherals may use the same timer +#ifdef useTimer1 +#if defined(__AVR_ATmega32U4__) + // turn on timer1 module + PRR0 &= ~(1 << PRTIM1); + + // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF + TCCR1A &= ~(1 << WGM11); + TCCR1A |= (1 << WGM10); + TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); + + // set timer 1 prescale factor to 1 + TCCR1B &= ~((1 << CS12) | (1 << CS11)); + TCCR1B |= (1 << CS10); + + // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture + TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); + + // set OC1A to disabled + TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); + + // set OC1B to disabled + TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); + + // set OC1C to disabled + TCCR1A &= ~((1 << COM1C1) | (1 << COM1C0)); + + // clear timer 1 output compare force bits for OC1A, OC1B, and OC1C + TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B) | (1 << FOC1C)); + +#ifdef useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A)); + + // enable timer1 overflow interrupt + TIMSK1 |= (1 << TOIE1); +#else // useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); +#endif // useTimer1Interrupt + + // clear timer 1 interrupt flags + TIFR1 |= ((1 << ICF1) | (1 << OCF1C) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); + +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + // turn on timer1 module + PRR0 &= ~(1 << PRTIM1); + + // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF + TCCR1A &= ~(1 << WGM11); + TCCR1A |= (1 << WGM10); + TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); + + // set timer 1 prescale factor to 1 + TCCR1B &= ~((1 << CS12) | (1 << CS11)); + TCCR1B |= (1 << CS10); + + // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture + TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); + + // set OC1A to disabled + TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); + + // set OC1B to disabled + TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); + + // clear timer 1 output compare force bits for OC1A, OC1B, and OC1C + TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B) | (1 << FOC1C)); + +#ifdef useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A)); + + // enable timer1 overflow interrupt + TIMSK1 |= (1 << TOIE1); +#else // useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); +#endif // useTimer1Interrupt + + // clear timer 1 interrupt flags + TIFR1 |= ((1 << ICF1) | (1 << OCF1C) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // turn on timer1 module + PRR &= ~(1 << PRTIM1); + + // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF + TCCR1A &= ~(1 << WGM11); + TCCR1A |= (1 << WGM10); + TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); + + // set timer 1 prescale factor to 1 + TCCR1B &= ~((1 << CS12) | (1 << CS11)); + TCCR1B |= (1 << CS10); + + // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture + TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); + + // set OC1A to disabled + TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); + + // set OC1B to disabled + TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); + + // clear timer 1 output compare force bits for OC1A and OC1B + TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B)); + +#ifdef useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A)); + + // enable timer1 overflow interrupt + TIMSK1 |= (1 << TOIE1); +#else // useTimer1Interrupt + // disable timer 1 interrupts + TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); +#endif // useTimer1Interrupt + + // clear timer 1 interrupt flags + TIFR1 |= ((1 << ICF1) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); + +#endif // defined(__AVR_ATmega328P__) +#endif // useTimer1 +#ifdef useTimer2 +#if defined(__AVR_ATmega2560__) + // turn on timer2 module + PRR0 &= ~(1 << PRTIM2); + + // set timer 2 to 8-bit phase correct PWM mode, TOP = 0xFF + TCCR2A &= ~(1 << WGM21); + TCCR2A |= (1 << WGM20); + TCCR2B &= ~(1 << WGM22); + + // set timer 2 prescale factor to 64 + TCCR2B &= ~((1 << CS22)); + TCCR2B |= ((1 << CS21) | (1 << CS20)); + + // set OC2A to disabled + TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); + + // set OC2B to disabled + TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); + + // clear timer 2 output compare force bits for OC2A and OC2B + TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B)); + + // disable timer 2 interrupts + TIMSK2 &= ~((1 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2)); + + // clear timer 2 interrupt flags + TIFR2 |= ((1 << OCF2B) | (1 << OCF2A) | (1 << TOV2)); + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // turn on timer2 module + PRR &= ~(1 << PRTIM2); + + // set timer 2 to phase correct PWM mode, TOP = 0xFF + TCCR2A &= ~(1 << WGM21); + TCCR2A |= (1 << WGM20); + TCCR2B &= ~(1 << WGM22); + + // set timer 2 prescale factor to 64 + TCCR2B &= ~((1 << CS22)); + TCCR2B |= ((1 << CS21) | (1 << CS20)); + + // set OC2A to disabled + TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); + + // set OC2B to disabled + TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); + + // clear force bits for OC2A and OC2B + TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B)); + + // disable timer 2 interrupts + TIMSK2 &= ~((1 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2)); + + // clear timer 2 interrupt flags + TIFR2 |= ((1 << OCF2B) | (1 << OCF2A) | (1 << TOV2)); + +#endif // defined(__AVR_ATmega328P__) +#endif // useTimer2 +#ifdef useTimer4 +#if defined(__AVR_ATmega32U4__) + // turn on timer4 module + PRR1 &= ~(1 << PRTIM4); + + // set timer 4 to phase and frequency correct mode + TCCR4D &= ~(1 << WGM41); + TCCR4D |= (1 << WGM40); + + // set timer 4 prescale factor to 64 + TCCR4B &= ~(1 << CS43); + TCCR4B |= ((1 << CS42) | (1 << CS41) | (1 << CS40)); + + // clear timer 4 fault protection + TCCR4D &= ~((1 << FPIE4) | (1 << FPEN4) | (1 << FPNC4) | (1 << FPES4) | (1 << FPAC4) | (1 << FPF4)); + + // set OC4A to disabled + TCCR4A &= ~((1 << COM4A1) | (1 << COM4A0) | (1 << PWM4A)); + + // set OC4B to disabled + TCCR4A &= ~((1 << COM4B1) | (1 << COM4B0) | (1 << PWM4B)); + + // set OC4D to disabled + TCCR4C &= ~((1 << COM4D1) | (1 << COM4D0) | (1 << PWM4D)); + + // clear timer 4 PWM inversion mode + TCCR4B &= ~(1 << PWM4X); + + // set timer 4 dead time prescaler to 1 + TCCR4B &= ~((1 << DTPS41) | (1 << DTPS40)); + + // clear timer 4 output compare force bits for OC4A and OC4B + TCCR4A &= ~((1 << FOC4A) | (1 << FOC4B)); + + // clear timer 4 output compare force bits for OC4D + TCCR4C &= ~(1 << FOC4D); + + // clear timer 4 update lock, disable timer 4 enhanced compare mode + TCCR4E &= ~((1 << TLOCK4) | (1 << ENHC4)); + + // disable timer 4 interrupts + TIMSK4 &= ~((1 < OCIE4D) | (1 < OCIE4A) | (1 < OCIE4B) | (1 < TOIE4)); + + // clear timer 4 interrupt flags + TIFR4 |= ((1 << OCF4D) | (1 << OCF4A) | (1 << OCF4B) | (1 << TOV4)); + + // set timer 4 dead time to 0 + DT4 = 0; + + // set timer 4 TOP value to 0x00FF, setting 8 bit mode + TC4H = 0; + OCR4C = 255; + +#endif // defined(__AVR_ATmega32U4__) +#endif // useTimer4 + SREG = oldSREG; // restore interrupt flag status + +#ifdef useTWIsupport + TWI::init(); +#ifdef useAdafruitRGBLCDshield + adafruitRGBLCDsupport::init(); // go init Adafruit RGB LCD shield +#endif // useAdafruitRGBLCDshield +#endif // useTWIsupport +#ifdef useSerial0Port + serial0::init(); +#endif // useSerial0Port +#ifdef useSerial1Port + serial1::init(); +#endif // useSerial1Port +#if defined(__AVR_ATmega32U4__) + usbSupport::init(); +#endif // defined(__AVR_ATmega32U4__) + button::init(); + LCD::init(); +#if defined(useActivityLED) + activityLED::init(); +#endif // defined(useActivityLED) +#if defined(useOutputPins) + outputPin::init(); +#endif // defined(useOutputPins) + +} + +#ifdef useDeepSleep // Deep Sleep support section +static void doGoDeepSleep(void) +{ + +#if defined(useOutputPins) + outputPin::shutdown(); +#endif // defined(useOutputPins) +#if defined(useActivityLED) + activityLED::shutdown(); +#endif // defined(useActivityLED) + changeBitFlags(timer0Command, t0cDisplayDelay, 0); // cancel any display delays in progress + LCD::shutdown(); // shut down the LCD display + button::shutdown(); +#if defined(__AVR_ATmega32U4__) + usbSupport::shutdown(); +#endif // defined(__AVR_ATmega32U4__) +#ifdef useSerial1Port + serial1::shutdown(); +#endif // useSerial1Port +#ifdef useSerial0Port + serial0::shutdown(); +#endif // useSerial0Port +#ifdef useTWIsupport + TWI::shutdown(); +#endif // useTWIsupport + +#ifdef useTimer4 +#if defined(__AVR_ATmega32U4__) + PRR0 |= (1 << PRTIM4); // shut off timer4 module to reduce power consumption +#endif // defined(__AVR_ATmega32U4__) + +#endif // useTimer4 +#ifdef useTimer2 +#if defined(__AVR_ATmega2560__) + PRR0 |= (1 << PRTIM2); // shut off timer2 module to reduce power consumption +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + PRR |= (1 << PRTIM2); // shut off timer2 module to reduce power consumption +#endif // defined(__AVR_ATmega328P__) + +#endif // useTimer2 +#ifdef useTimer1Interrupt +#if defined(__AVR_ATmega32U4__) + // disable timer1 overflow interrupt + TIMSK1 &= ~(1 << TOIE1); +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + // disable timer1 overflow interrupt + TIMSK1 &= ~(1 << TOIE1); +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + // disable timer1 overflow interrupt + TIMSK1 &= ~(1 << TOIE1); +#endif // defined(__AVR_ATmega328P__) + +#endif // useTimer1Interrupt +#ifdef useTimer1 +#if defined(__AVR_ATmega32U4__) + PRR0 |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption +#endif // defined(__AVR_ATmega32U4__) +#if defined(__AVR_ATmega2560__) + PRR0 |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + PRR |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption +#endif // defined(__AVR_ATmega328P__) + +#endif // useTimer1 + performSleepMode(SLEEP_MODE_PWR_DOWN); // go perform power-down sleep mode + + initHardware(); // restart all peripherals + +} + +#endif // useDeepSleep +static uint32_t findCycleLength(unsigned long lastCycle, unsigned long thisCycle) // this is only to be meant to be used with interrupt handlers { if (thisCycle < lastCycle) thisCycle = 4294967295ul - lastCycle + thisCycle + 1; @@ -1353,7 +1845,34 @@ unsigned long findCycleLength(unsigned long lastCycle, unsigned long thisCycle) } -void delay0(unsigned int ms) +static void delay0(unsigned int ms) +{ + + uint8_t oldSREG; + + if (ms) + { + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + + timer0DelayCount = ms; // request a set number of timer tick delays per millisecond + timer0Command |= t0cDoDelay; // signal request to timer + + SREG = oldSREG; // restore interrupt flag status + + } + + while (timer0Command & t0cDoDelay) idleProcess(); // wait for delay timeout + +} + +// this function is needed since there is no way to perform an atomic bit change of an SRAM byte value +// most MPGuino variables that are shared between main program and interrupt handlers should not need to +// be treated as atomic (!) because only one side or the other is supposed to change said variables +// however, status flag registers are obviously an exception, and status flag changes are common +// enough to warrant an explicit function definition +static void changeBitFlags(volatile uint8_t &flagRegister, uint8_t maskAND, uint8_t maskOR) { uint8_t oldSREG; @@ -1361,11 +1880,19 @@ void delay0(unsigned int ms) oldSREG = SREG; // save interrupt flag status cli(); // disable interrupts - timer0DelayCount = ms; // request a set number of timer tick delays per millisecond - timer0Command |= t0cDoDelay; // signal request to timer + flagRegister = (flagRegister & ~(maskAND)) | (maskOR); // go perform atomic status flag change SREG = oldSREG; // restore interrupt flag status - while (timer0Command & t0cDoDelay) idleProcess(); // wait for delay timeout +} + +static void performSleepMode(uint8_t sleepMode) +{ + + set_sleep_mode(sleepMode); // set for specified sleep mode + sleep_enable(); // enable sleep mode + sleep_mode(); // go sleep for a bit + sleep_disable(); // disable sleep mode } + diff --git a/mpguino_tav/m_input.h b/mpguino_tav/m_input.h index 3b3dd72..bc39dfe 100644 --- a/mpguino_tav/m_input.h +++ b/mpguino_tav/m_input.h @@ -1,3 +1,14 @@ +namespace button /* button input support section prototype */ +{ + + static void init(void); + static void shutdown(void); +#if useAnalogButtons || useDebugTerminal + static void inject(uint8_t buttonValue); +#endif // useAnalogButtons || useDebugTerminal + +}; + #ifdef useTWIbuttons #ifdef useAdafruitRGBLCDshield #define useButtonCrossConfig true diff --git a/mpguino_tav/m_input.ino b/mpguino_tav/m_input.ino index e69de29..1565a86 100644 --- a/mpguino_tav/m_input.ino +++ b/mpguino_tav/m_input.ino @@ -0,0 +1,82 @@ +/* button input support section */ + +static void button::init(void) +{ + +#ifdef useAdafruitRGBLCDshield + uint16_t MCP23017registers; +#endif // useAdafruitRGBLCDshield + uint8_t oldSREG; + +#ifdef useAdafruitRGBLCDshield +#if useTWIbuttons && useTWILCD + LCD::disableIntSample(); // disable TWI button sampling + +#endif // useTWIbuttons && useTWILCD + MCP23017registers = (uint16_t)(buttonMask); + + adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_IODIRx, (union_16 *)(&MCP23017registers)); // write out port direction (only buttons as input) + adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_GPPUx, (union_16 *)(&MCP23017registers)); // write out pull-up resistor config (only buttons as input) + adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_IPOLx, (union_16 *)(&MCP23017registers)); // write out input pin polarity config (only buttons as input) + + adafruitRGBLCDsupport::setTransferMode(adaTWIbyteMode); // ensure address mode is in byte mode + +#if useTWIbuttons && useTWILCD + LCD::enableIntSample(); // enable TWI button sampling + +#endif // useTWIbuttons && useTWILCD +#endif // useAdafruitRGBLCDshield + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + +#ifdef useLegacyButtons +#if defined(__AVR_ATmega2560__) + DIDR2 &= ~((1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D)); // enable digital input on port K button pins + + PORTK |= ((1 << PORTK5) | (1 << PORTK4) | (1 << PORTK3)); // enable port K button pullup resistors + + PCMSK2 |= ((1 << PCINT21) | (1 << PCINT20) | (1 << PCINT19)); // enable port K button interrupts + + PCICR |= (1 << PCIE2); // enable selected interrupts on port K + + lastPINxState = PINK; // initialize last input pin state value so as to not erroneously detect a button press on start + +#endif // defined(__AVR_ATmega2560__) +#if defined(__AVR_ATmega328P__) + DIDR0 &= ~((1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D)); // enable digital input on port C button pins + + PORTC |= ((1 << PORTC5) | (1 << PORTC4) | (1 << PORTC3)); // enable port C button pullup resistors + + PCMSK1 |= ((1 << PCINT13) | (1 << PCINT12) | (1 << PCINT11)); // enable port C button interrupts + + PCICR |= (1 << PCIE1); // enable selected interrupts on port C + + lastPINxState = PINC; // initialize last input pin state value so as to not erroneously detect a button press on start + +#endif // defined(__AVR_ATmega328P__) +#endif // useLegacyButtons + SREG = oldSREG; // restore interrupt flag status + +} + +static void button::shutdown(void) +{ +} + +#if defined(useAnalogButtons) || defined(useDebugTerminal) +static void button::inject(uint8_t buttonValue) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + thisButtonState = buttonValue; + timer0Command |= (t0cProcessButton); // send timer0 notification that a button was just read in + + SREG = oldSREG; // restore interrupt flag status + +} + +#endif // useAnalogButtons || useDebugTerminal diff --git a/mpguino_tav/m_lcd.ino b/mpguino_tav/m_lcd.ino index 704e397..5266e43 100644 --- a/mpguino_tav/m_lcd.ino +++ b/mpguino_tav/m_lcd.ino @@ -747,7 +747,7 @@ static void LCD::writeNybble(uint8_t value, uint8_t flags) #endif // useTWILCD #endif // useBufferedLCD - peripheral::changeBitFlags(timer1Command, 0, t1cDelayLCD); // enable LCD delay + changeBitFlags(timer1Command, 0, t1cDelayLCD); // enable LCD delay } @@ -898,7 +898,7 @@ static void LCD::outputNybble(uint8_t LCDchar) static void LCD::disableIntSample(void) { - peripheral::changeBitFlags(timer0Command, t0cEnableTWIsample, 0); // disable TWI button sampling as it interferes with TWI LCD output + changeBitFlags(timer0Command, t0cEnableTWIsample, 0); // disable TWI button sampling as it interferes with TWI LCD output while (twiStatusFlags & twiBlockMainProgram) idleProcess(); // wait for any in-progress TWI button samples to finish } @@ -906,7 +906,7 @@ static void LCD::disableIntSample(void) static void LCD::enableIntSample(void) { - peripheral::changeBitFlags(timer0Command, 0, t0cEnableTWIsample); // re-enable TWI button sampling + changeBitFlags(timer0Command, 0, t0cEnableTWIsample); // re-enable TWI button sampling } diff --git a/mpguino_tav/m_twi.ino b/mpguino_tav/m_twi.ino index 506a679..4bfafd5 100644 --- a/mpguino_tav/m_twi.ino +++ b/mpguino_tav/m_twi.ino @@ -209,7 +209,7 @@ static uint8_t TWI::writeByte(uint8_t data) // this can be in either main progra else { - peripheral::changeBitFlags(twiStatusFlags, twiOpen, 0); // free up TWI for main program use + changeBitFlags(twiStatusFlags, twiOpen, 0); // free up TWI for main program use return 1; // signal buffer overflow } diff --git a/mpguino_tav/m_usb.h b/mpguino_tav/m_usb.h index 729721f..0a6b737 100644 --- a/mpguino_tav/m_usb.h +++ b/mpguino_tav/m_usb.h @@ -1,6 +1,14 @@ #if defined(__AVR_ATmega32U4__) /* start of baseline ATmega native USB support */ +namespace usbSupport +{ + + static void init(void); + static void shutdown(void); + +}; + #ifdef useUSBserial namespace usbDevice { diff --git a/mpguino_tav/m_usb.ino b/mpguino_tav/m_usb.ino index 767c90a..6c44e72 100644 --- a/mpguino_tav/m_usb.ino +++ b/mpguino_tav/m_usb.ino @@ -1,4 +1,62 @@ #if defined(__AVR_ATmega32U4__) +static void usbSupport::init(void) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + + PRR1 &= ~(1 << PRUSB); // turn on USB hardware + + UHWCON = (1 << UVREGE); // enable USB pad regulator + + USBCON = ((1 << USBE) | (1 << FRZCLK)); // enable USB controller, disable clock inputs + +#if F_CPU == 16000000UL + PLLCSR = ((1 << PINDIV) | (1 << PLLE)); // set PLL input prescaler for 16 MHz clock source, and enable PLL +#elif F_CPU == 8000000UL + PLLCSR = (1 << PLLE); // set PLL input prescaler for 8 MHz clock source, and enable PLL +#else // F_CPU == 16000000UL +#error *** F_CPU clock rate not supported!!! *** +#endif // F_CPU == 16000000UL + + while (!(PLLCSR & (1 << PLOCK))); // wait for PLL lock + + USBCON = ((1 << USBE) | (1 << OTGPADE)); // keep USB controller enabled, enable clock inputs, enable VBUS pad + + UDCON = 0; // select USB high speed mode + + usbConfiguration = 0; + + UDIEN = ((1 << EORSTE) | (1 << SOFE)); // enable End-Of-Reset, Start-Of-Frame interrupts + + SREG = oldSREG; // restore interrupt flag status + +} + +static void usbSupport::shutdown(void) +{ + + uint8_t oldSREG; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts + + UDIEN = 0; // disable all USB interrupts + + USBCON = 0; // disable USB controller + + PLLCSR = 0; // disable PLL + + UHWCON = 0; // disable USB pad regulator + + PRR1 |= (1 << PRUSB); // turn off USB hardware + + SREG = oldSREG; // restore interrupt flag status + +} + #ifdef useUSBserial static void usbDevice::init(void) { diff --git a/mpguino_tav/mpguino_tav.ino b/mpguino_tav/mpguino_tav.ino index 2e7869d..1f84f50 100644 --- a/mpguino_tav/mpguino_tav.ino +++ b/mpguino_tav/mpguino_tav.ino @@ -348,85 +348,66 @@ Logging outputs #include "m_input.h" #include "m_lcd.h" #include "functions.h" +#include "feature_base.h" #include "feature_settings.h" #include "feature_datalogging.h" #include "feature_bignum.h" #include "feature_bargraph.h" +#include "feature_outputpin.h" #include "feature_debug.h" #include "feature_dragrace.h" #include "feature_coastdown.h" -// This is where direct-ported (not analog) pushbutton definitions should go +static const char titleMPGuino[] PROGMEM = { + "\xED" "MPGuino v1.95tav\r" +}; + +static const char dateMPGuino[] PROGMEM = { + "2023-MAR-18\r" +}; + +typedef uint8_t (* displayHandlerFunc)(uint8_t, uint8_t, uint8_t); // type for various handler functions + +typedef struct +{ + + uint8_t buttonCode; + void (* buttonCommand)(void); + +} buttonVariable; + +typedef struct +{ -#if defined(__AVR_ATmega32U4__) -#ifndef PRTIM4 -#define PRTIM4 4 + uint8_t menuIndex; + uint8_t modeIndex; + uint8_t modeYcount; + uint8_t modeXcount; + displayHandlerFunc screenDisplayHandler; + const buttonVariable (* modeButtonList); -#endif // PRTIM4 -#endif // defined(__AVR_ATmega32U4__) +} modeInformation; const char * findStr(const char * str, uint8_t strIdx); static void printStatusMessage(const char * s); static void printStatusMessage(const char * s, uint8_t strIdx); -void doNothing(void); -void noSupport(void); void initStatusLine(void); void execStatusLine(void); -char findDigit(uint8_t value, char &zeroChar); -unsigned long str2ull(char * strBuffer); -char * ull2str(uint8_t prgmIdx, char * strBuffer, uint8_t decimalPlaces); -char * formatDecimal(char * strBuffer, uint8_t windowLength, uint8_t decimalPlaces, uint8_t decimalFlag); -uint8_t mainScreenDisplayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); /* Main screen section */ -void doReturnToMainScreen(void); -void doNextBright(void); -#ifdef useDeepSleep // Deep Sleep support section -void doGoDeepSleep(void); -#endif // useDeepSleep -#ifdef useScreenEditor // Programmable main display screen edit support section -void doCursorUpdateScreenEdit(void); -void doScreenEditDisplay(void); -void doGoScreenEdit(void); -void doScreenEditBump(void); -void doSaveScreen(void); -void doScreenReturnToMain(void); -#endif // useScreenEditor static void idleProcess(void); // place all time critical main program internal functionality here - no I/O! -static void performSleepMode(uint8_t sleepMode); int main(void); -namespace peripheral /* MPGuino human interface I/O peripheral device prototype */ +namespace menu /* Top-down menu selector section prototype */ { - static void initMain(void); - static void shutdownMain(void); - static void initButton(void); - static void shutdownButton(void); - static void changeBitFlags(volatile uint8_t &flagRegister, uint8_t maskAND, uint8_t maskOR); -#if useAnalogButtons || useDebugTerminal - static void injectButton(uint8_t buttonValue); -#endif // useAnalogButtons || useDebugTerminal -#ifdef useExpansionPins - static void initExpansionPin(void); - static void shutdownExpansionPin(void); - static void outputExpansionPin1(uint8_t pin); - static void outputExpansionPin2(uint8_t pin); -#endif // useExpansionPins -#if defined(__AVR_ATmega32U4__) - static void initUSB(void); - static void shutdownUSB(void); -#endif // defined(__AVR_ATmega32U4__) -#ifdef useStatusLEDpins - static void initStatusLED(void); - static void shutdownStatusLED(void); - static void outputStatusLED(uint8_t val); -#endif // useStatusLEDpins + static uint8_t displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); + static void entry(void); + static void select(void); + static void doNextBright(void); + static void noSupport(void); + static void doNothing(void); }; -uint8_t menuLevel; -uint8_t topScreenLevel; -uint8_t brightnessIdx; - namespace cursor /* LCD screen cursor manipulation section prototype */ { @@ -442,22 +423,17 @@ namespace cursor /* LCD screen cursor manipulation section prototype */ }; +uint8_t menuLevel; +uint8_t brightnessIdx; + +volatile uint8_t cursorXdirection; +volatile uint8_t menuTop; + const uint8_t menuExitIdx = 0; // this call may not even be necessary const uint8_t menuEntryIdx = menuExitIdx + 1; // typically, this call will fall through const uint8_t menuCursorUpdateIdx = menuEntryIdx + 1; // ...to this call, then will fall through const uint8_t menuOutputDisplayIdx = menuCursorUpdateIdx + 1; // ...to this call -typedef uint8_t (* displayHandlerFunc)(uint8_t, uint8_t, uint8_t); // type for various handler functions - -namespace menu /* Top-down menu selector section prototype */ -{ - - static uint8_t displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); - static void entry(void); - static void select(void); - -}; - namespace text /* text string output section prototype */ { @@ -478,20 +454,6 @@ namespace text /* text string output section prototype */ }; -static const char titleMPGuino[] PROGMEM = { - "\xED" "MPGuino v1.95tav\r" -}; - -static const char dateMPGuino[] PROGMEM = { - "2023-MAR-18\r" -}; - -const char overFlowStr[] PROGMEM = "----------"; -const char overFlow9Str[] PROGMEM = "9999999999"; - -const uint8_t dfAdjustWindow = 0b00000001; -const uint8_t dfOverflow9s = 0b10000000; - // Menu display / screen cursor support section // the following screen index defines are for the legacy MPGuino screen displays @@ -596,49 +558,20 @@ const uint8_t screenEditIdx = nextAllowedValue; static const char menuTotalSize = nextAllowedValue; -const uint8_t displayPageCount = 9 // count of base number of data screens -#ifdef trackIdleEOCdata - + 3 // count of Idle/EOC tracking data screens -#endif // trackIdleEOCdata -; -const uint8_t mainScreenDisplayFormatSize = displayPageCount * 4; - -typedef struct -{ - - uint8_t buttonCode; - void (* buttonCommand)(void); - -} buttonVariable; - -typedef struct -{ - - uint8_t menuIndex; - uint8_t modeIndex; - uint8_t modeYcount; - uint8_t modeXcount; - displayHandlerFunc screenDisplayHandler; -// void (* modeDisplay)(void); -// void (* modeCursorUpdate)(void); - const buttonVariable (* modeButtonList); - -} modeInformation; - static const buttonVariable bpListMenu[] PROGMEM = { {btnShortPressC, menu::select} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::shortRight} ,{btnShortPressU, cursor::shortLeft} - ,{btnLongPressU, doNextBright} - ,{btnShortPressL, doNothing} + ,{btnLongPressU, menu::doNextBright} + ,{btnShortPressL, menu::doNothing} ,{btnShortPressR, menu::select} #else // useButtonCrossConfig ,{btnShortPressR, cursor::shortRight} ,{btnShortPressL, cursor::shortLeft} - ,{btnLongPressC, doNextBright} + ,{btnLongPressC, menu::doNextBright} #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; static const buttonVariable bpListMain[] PROGMEM = { @@ -648,7 +581,7 @@ static const buttonVariable bpListMain[] PROGMEM = { ,{btnLongPressL, cursor::longLeft} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::longRight} - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnLongPressUR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -667,7 +600,7 @@ static const buttonVariable bpListMain[] PROGMEM = { ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} ,{btnLongPressCR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -682,7 +615,7 @@ static const buttonVariable bpListMain[] PROGMEM = { ,{btnLongPressLCR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; static const buttonVariable bpListSetting[] PROGMEM = { @@ -691,20 +624,20 @@ static const buttonVariable bpListSetting[] PROGMEM = { ,{btnLongPressL, menu::entry} ,{btnShortPressLR, parameterEdit::entry} #ifdef useButtonCrossConfig - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnShortPressD, cursor::shortRight} #ifdef useCPUreading ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} #ifdef useCPUreading ,{btnLongPressLCR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; static const buttonVariable bpListParameterEdit[] PROGMEM = { @@ -730,7 +663,7 @@ static const buttonVariable bpListParameterEdit[] PROGMEM = { ,{btnLongPressLC, parameterEdit::readMaxValue} ,{btnShortPressC, parameterEdit::changeDigitUp} #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #ifdef useBigDigitDisplay @@ -741,7 +674,7 @@ static const buttonVariable bpListBigNum[] PROGMEM = { ,{btnLongPressL, cursor::longLeft} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::longRight} - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnLongPressUR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -753,7 +686,7 @@ static const buttonVariable bpListBigNum[] PROGMEM = { ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} ,{btnLongPressCR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -765,7 +698,7 @@ static const buttonVariable bpListBigNum[] PROGMEM = { ,{btnLongPressLCR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useBigDigitDisplay @@ -779,7 +712,7 @@ static const buttonVariable bpListClockShow[] PROGMEM = { ,{btnShortPressLR, clockSet::entry} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::longRight} - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnLongPressUR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -791,7 +724,7 @@ static const buttonVariable bpListClockShow[] PROGMEM = { ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} ,{btnLongPressCR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -803,7 +736,7 @@ static const buttonVariable bpListClockShow[] PROGMEM = { ,{btnLongPressLCR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; static const buttonVariable bpListClockSet[] PROGMEM = { @@ -820,7 +753,7 @@ static const buttonVariable bpListClockSet[] PROGMEM = { #else // useButtonCrossConfig ,{btnShortPressC, clockSet::changeDigitUp} #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useClockDisplay @@ -832,7 +765,7 @@ static const buttonVariable bpListCPUmonitor[] PROGMEM = { ,{btnLongPressL, cursor::longLeft} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::longRight} - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnLongPressUR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -841,7 +774,7 @@ static const buttonVariable bpListCPUmonitor[] PROGMEM = { ,{btnLongPressUL, tripSupport::resetTank} #endif // usePartialRefuel #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} ,{btnLongPressCR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -850,7 +783,7 @@ static const buttonVariable bpListCPUmonitor[] PROGMEM = { ,{btnLongPressLC, tripSupport::resetTank} #endif // usePartialRefuel #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useCPUreading @@ -870,7 +803,7 @@ static const buttonVariable bpListPartialRefuel[] PROGMEM = { #else // useButtonCrossConfig ,{btnShortPressC, partialRefuel::select} #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // usePartialRefuel @@ -880,25 +813,25 @@ static const buttonVariable bpListMiscViewer[] PROGMEM = { ,{btnShortPressL, cursor::shortLeft} ,{btnLongPressL, menu::entry} #ifdef useButtonCrossConfig - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} #ifdef useCPUreading ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} #ifdef useCPUreading ,{btnLongPressLCR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // defined(useSimulatedFIandVSS) || defined(useChryslerMAPCorrection) || defined(useDebugAnalog) #ifdef useTestButtonValues static const buttonVariable bpListButtonView[] PROGMEM = { - {buttonsUp, doNothing} + {buttonsUp, menu::doNothing} }; #endif // useTestButtonValues @@ -915,7 +848,7 @@ static const buttonVariable bpListTripSave[] PROGMEM = { #else // useButtonCrossConfig ,{btnLongPressC, tripSupport::select} #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useSavedTrips @@ -927,7 +860,7 @@ static const buttonVariable bpListBarGraph[] PROGMEM = { ,{btnLongPressL, cursor::longLeft} #ifdef useButtonCrossConfig ,{btnShortPressD, cursor::longRight} - ,{btnShortPressU, doNextBright} + ,{btnShortPressU, menu::doNextBright} ,{btnShortPressC, menu::entry} ,{btnLongPressUR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -942,7 +875,7 @@ static const buttonVariable bpListBarGraph[] PROGMEM = { ,{btnLongPressU, systemInfo::showCPUloading} #endif // useCPUreading #else // useButtonCrossConfig - ,{btnShortPressC, doNextBright} + ,{btnShortPressC, menu::doNextBright} ,{btnShortPressLCR, menu::entry} ,{btnLongPressCR, tripSupport::resetCurrent} #ifdef usePartialRefuel @@ -957,7 +890,7 @@ static const buttonVariable bpListBarGraph[] PROGMEM = { ,{btnLongPressLR, systemInfo::showCPUloading} #endif // useCPUreading #endif // useButtonCrossConfig - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useBarGraph @@ -967,21 +900,21 @@ static const buttonVariable bpListScreenEdit[] PROGMEM = { {btnShortPressU, doScreenEditBump} ,{btnShortPressD, doCursorUpdateScreenEdit} // revert screen format value ,{btnLongPressU, doSaveScreen} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useScreenEditor #ifdef useDragRaceFunction static const buttonVariable bpListDragRace[] PROGMEM = { {btnLongPressR, accelerationTest::goTrigger} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useDragRaceFunction #ifdef useCoastDownCalculator static const buttonVariable bpListCoastdown[] PROGMEM = { {btnLongPressR, coastdown::goTrigger} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useCoastDownCalculator @@ -991,21 +924,21 @@ static const buttonVariable bpListScreenEdit[] PROGMEM = { {btnShortPressC, doScreenEditBump} ,{btnLongPressLR, doCursorUpdateScreenEdit} // revert screen format value ,{btnLongPressC, doSaveScreen} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useScreenEditor #ifdef useDragRaceFunction static const buttonVariable bpListDragRace[] PROGMEM = { {btnLongPressR, accelerationTest::goTrigger} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useDragRaceFunction #ifdef useCoastDownCalculator static const buttonVariable bpListCoastdown[] PROGMEM = { {btnLongPressR, coastdown::goTrigger} - ,{buttonsUp, noSupport} + ,{buttonsUp, menu::noSupport} }; #endif // useCoastDownCalculator @@ -1106,10 +1039,10 @@ static const modeInformation screenParameters[(unsigned int)(menuTotalSize)] PRO ,{timeoutSettingsScreenIdx, timeoutSettingsScreenIdx | 0x80, 1, eePtrSettingsTimeoutLen, settings::displayHandler, bpListSetting} ,{miscSettingsScreenIdx, miscSettingsScreenIdx | 0x80, 1, eePtrSettingsMiscLen, settings::displayHandler, bpListSetting} #ifdef useDragRaceFunction - ,{dragRaceIdx, 1, 4, accelerationTest::goDisplay, doNothing, bpListDragRace} + ,{dragRaceIdx, 1, 4, accelerationTest::goDisplay, menu::doNothing, bpListDragRace} #endif // useDragRaceFunction #ifdef useCoastDownCalculator - ,{coastdownIdx | 0x80, 1, 3, coastdown::goDisplay, doNothing, bpListCoastdown} + ,{coastdownIdx | 0x80, 1, 3, coastdown::goDisplay, menu::doNothing, bpListCoastdown} #endif // useCoastDownCalculator #ifdef useSimulatedFIandVSS ,{debugReadingIdx, debugReadingIdx | 0x80, 1, 4, debugReading::displayHandler, bpListMiscViewer} @@ -1142,9 +1075,6 @@ static const modeInformation screenParameters[(unsigned int)(menuTotalSize)] PRO #endif // useScreenEditor }; -volatile uint8_t cursorXdirection; -volatile uint8_t menuTop; - static uint8_t menu::displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged) { @@ -1210,6 +1140,31 @@ static void menu::select(void) } +static void menu::doNextBright(void) +{ + + initStatusLine(); + text::stringOut(devLCD, PSTR("Backlight = ")); + text::stringOut(devLCD, brightString, brightnessIdx); + execStatusLine(); + +} + +static void menu::doNothing(void) +{ +} + +static void menu::noSupport(void) +{ + + initStatusLine(); + text::stringOut(devLCD, PSTR("Btn 0x")); + text::hexByteOut(devLCD, buttonPress); + text::stringOut(devLCD, PSTR(" Pressed")); + execStatusLine(); + +} + /* LCD screen cursor manipulation section */ static void cursor::screenLevelEntry(const char * str, uint8_t newScreenLevel) @@ -1411,21 +1366,6 @@ static void printStatusMessage(const char * s, uint8_t strIdx) } -void doNothing(void) -{ -} - -void noSupport(void) -{ - - initStatusLine(); - text::stringOut(devLCD, PSTR("Btn 0x")); - text::hexByteOut(devLCD, buttonPress); - text::stringOut(devLCD, PSTR(" Pressed")); - execStatusLine(); - -} - void initStatusLine(void) { @@ -1653,2023 +1593,192 @@ static uint8_t text::numberOut(interfaceDevice &dev, uint8_t tripIdx, uint8_t ca } -static const uint8_t prgmMultiplyBy100[] PROGMEM = { - instrMul2byByte, 100, // multiply result by 100 - instrAddIndexToX, 0x02 , // add whatever's in the trip variable index to result - instrDone // exit to caller -}; - -static const uint8_t prgmMultiplyBy10[] PROGMEM = { - instrMul2byByte, 10, // multiply result by 10 - instrAddIndexToX, 0x02 , // add whatever's in the trip variable index to result - instrDone // exit to caller -}; - -unsigned long str2ull(char * strBuffer) +// this function is called whenever the main program has to wait for some external condition to occur +// when the main program performs some I/O activity, the target peripheral may take some time to acknowledge the activity +// and let the main program know that the peripheral is ready for more activity +// oftentimes, the main program has to wait for the peripheral in question, so instead of spinning its wheels, it will simply +// cause the processor to go to sleep by calling this function +// any interrupt will wake up the processor - this also means the primary timer0 +// this function is therefore ideal for placing all purely internal operations that do not require direct interaction with the outside world +// +// - fuel/vehicle speed data transfers +// - acceleration test state changes +// - debug sensor simulation counter updates +// - analog button read translations +// - Chrysler fuel correction factor calculations +// - any other operation not requiring interaction with peripherals that require waiting periods to finish +// +// said internal operations would hopelessly bog down interrupt handlers, were they loaded with these internal operations +// +static void idleProcess(void) { - uint8_t c; - uint8_t n; - - uint8_t x; - uint8_t f; - uint8_t loopFlag; +#ifdef useCPUreading + uint32_t idleStart; +#endif // useCPUreading - x = 0; - n = 0; - f = 1; - loopFlag = 1; +#if defined(useActivityLED) + activityLED::output(0); - SWEET64::init64byt((union union_64 *)(&s64reg[s64reg2]), 0); // initialize 64-bit number to zero +#endif // defined(useActivityLED) +#ifdef useCPUreading + idleStart = systemInfo::cycles0(); // record starting time - while ((loopFlag) && (x < 17)) - { +#endif // useCPUreading + performSleepMode(SLEEP_MODE_IDLE); // go perform idle sleep mode - if ((c = strBuffer[(unsigned int)(x++)])) // if a non-NULL character is read in - { +#ifdef useCPUreading + idleTimerLength += systemInfo::findCycleLength(idleStart, systemInfo::cycles0()); +#ifdef useDebugCPUreading + idleStart = systemInfo::cycles0(); // record starting time +#endif // useDebugCPUreading - n *= 10; // shift accumulator left one digit - if (c != ' ') n += (uint8_t)(c) - 48; // if character is not a leading space, go add it to accumulator - f= 1 - f; // flip-flop the SWEET64 addition flag +#endif // useCPUreading +#if defined(useActivityLED) + activityLED::output(1); - if (f) - { +#endif // defined(useActivityLED) + // this is the part of the main loop that only executes twice a second (or what is defined by loopsPerSecond), to collect and process readings + if (timer0Status & t0sTakeSample) // if main timer has commanded a sample be taken + { - SWEET64::runPrgm(prgmMultiplyBy100, n); // call SWEET64 routine to perform (accumulated 64-bit number) * 100 + n - n = 0; + changeBitFlags(timer0Status, t0sTakeSample, 0); // acknowledge sample command - } +#ifdef useCPUreading + systemInfo::idleProcess(); - } - else loopFlag = 0; // otherwise, terminate loop upon receipt of a NULL character +#endif // useCPUreading + tripSupport::idleProcess(); } - if (f == 0) SWEET64::runPrgm(prgmMultiplyBy10, n); // call SWEET64 routine to perform (accumulated 64-bit number) * 10 + n - - return ((union union_64 *)(&s64reg[s64reg2]))->ul[0]; - -} - -char findDigit(uint8_t value, char &zeroChar) -{ - - if (value) +#if defined(useAnalogRead) +#ifdef useChryslerMAPCorrection + if (analogStatus & asReadMAPchannel) { - value += '0'; - zeroChar = '0'; - } - else value = zeroChar; - return value; + changeBitFlags(analogStatus, asReadMAPchannel, 0); // acknowledge ADC read completion -} + SWEET64::runPrgm(prgmCalculateMAPpressure, 0); -char * ull2str(uint8_t prgmIdx, char * strBuffer, uint8_t decimalPlaces) -{ + } - union union_64 * tmpPtr2 = (union union_64 *)(&s64reg[s64reg2]); +#endif // useChryslerMAPCorrection +#ifdef useChryslerBaroSensor + if (analogStatus & asReadBaroChannel) + { - uint8_t b; - char c; - uint8_t l; - uint8_t y; - char z; + changeBitFlags(analogStatus, asReadBaroChannel, 0); // acknowledge ADC read completion - SWEET64::doCalculate(decimalPlaces, prgmIdx); // call SWEET64 routine to perform decimal point rounding to next nearest decimal place + SWEET64::runPrgm(prgmCalculateBaroPressure, 0); - l = tmpPtr2->u8[6]; // load total length of binary-coded decimal bytes of converted number + } - if (l == 255) strcpy_P(strBuffer, overFlowStr); // if length is 255, this number overflowed - else +#endif // useChryslerBaroSensor +#ifdef useAnalogButtons + if (analogStatus & asReadButtonChannel) { - z = (char)(tmpPtr2->u8[7]); // load leading zero character - y = 0; + changeBitFlags(analogStatus, asReadButtonChannel, 0); // acknowledge ADC read completion - for (uint8_t x = 0; x < l; x++) // go through all of the binary-coded decimal bytes of converted number + for (uint8_t x = analogButtonCount - 1; x < analogButtonCount; x--) { - b = tmpPtr2->u8[(unsigned int)(x)]; // load a binary-coded decimal byte of number + if (analogValue[(unsigned int)(analogButtonChannelIdx)] >= pgm_read_word(&analogButtonThreshold[(unsigned int)(x)])) + { - c = findDigit(b / 10, z); // perform leading zero conversion on 10's place digit - strBuffer[(unsigned int)(y++)] = c; // store 10's place digit in string buffer +#ifdef useTestAnalogButtonIdx + thisButtonIdx = x; +#endif // useTestAnalogButtonIdx + button::inject(pgm_read_byte(&analogTranslate[(unsigned int)(x)])); + break; - c = findDigit(b % 10, z); // perform leading zero conversion on 1's place digit - strBuffer[(unsigned int)(y++)] = c; // store 1's place digit in string buffer + } } - if (c == ' ') strBuffer[(unsigned int)(y - 1)] = '0'; // ensure that at least one numeric digit exists - strBuffer[(unsigned int)(y)] = 0; // mark end of string buffer with a NULL character - } - return strBuffer; // return pointer to string buffer containing the number - -} - -char * formatDecimal(char * strBuffer, uint8_t windowLength, uint8_t decimalPlaces, uint8_t decimalFlag) // format number for output -{ +#endif // useAnalogButtons +#endif // useAnalogRead +#ifdef useDragRaceFunction + if (timer0Status & t0sAccelTestFlag) + { - uint8_t x; - uint8_t y; - uint8_t z; // pointer to end of integer digits in string - uint8_t c; // temporary character storage - uint8_t i; // integer digit count + changeBitFlags(timer0Status, t0sAccelTestFlag, 0); // acknowledge sample command - ull2str(tRoundOffNumber, strBuffer, decimalPlaces); // perform rounding of number to nearest decimal place, then format for ASCII output + accelerationTest::idleProcess(); - if (windowLength > 11) windowLength = 0; // if window length is larger than the contents of the output string buffer, zero out window length + } - if (strBuffer[2] != '-') // if number did not overflow +#endif // useDragRaceFunction +#ifdef useSimulatedFIandVSS + if (timer1Status & t1sDebugUpdateFIP) // if debug fuel injector pulse period needs adjustment { - x = 6 + decimalPlaces; // source string index - y = 10; // destination string index - i = 0; + changeBitFlags(timer1Status, t1sDebugUpdateFIP, 0); // acknowledge debug update request - while (y < 12) // loop through entire string buffer, insert padding and a decimal point as required, and preserve ending NULL - { + debugReading::idleProcessFuel(); - if (x < 10) - { + } - c = strBuffer[(unsigned int)(x)]; // read in a digit of formatted number from string buffer, bump down source string index by one + if (timer1Status & t1sDebugUpdateVSS) // if VSS pulse period needs adjustment + { - if ((x > 5) && (c == ' ')) c = '0'; // change 1's place and lower places leading spaces into leading zeros - if ((x == 6) && (decimalPlaces)) strBuffer[(unsigned int)(y--)] = '.'; // if a decimal position was specified, and at decimal point, insert it - if ((x < 7) && (c != ' ')) i++; // count the number of non-space integer characters + changeBitFlags(timer1Status, t1sDebugUpdateVSS, 0); // acknowledge debug update request - x--; + debugReading::idleProcessVSS(); - } - else c = ' '; // otherwise, pad front of number with extra spaces + } - strBuffer[(unsigned int)(y--)] = c; // store processed character back into string buffer, bump down destination string index by one +#endif // useSimulatedFIandVSS +#ifdef useDebugCPUreading + idleProcessTimerLength += systemInfo::findCycleLength(idleStart, systemInfo::cycles0()); - } +#endif // useDebugCPUreading +} - if (decimalPlaces) z = 10 - decimalPlaces; // point to either decimal point or to end of string - else z = 11; // results in pointing to first character past the 1's digit in both cases +// primary MPGuino processing routine - overwrites Arduino sketch main if compiled in Arduino IDE - if (windowLength) - { +int main(void) +{ - if (i > windowLength) // if window length is smaller than the number of integer digits, overflow - { + uint8_t i; + uint8_t j; +#ifdef useDebugCPUreading + uint32_t displayStart; +#endif // useDebugCPUreading - x = 0; // signal 'do not perform string buffer move' - strcpy_P(strBuffer, overFlowStr); // copy overflow string to string buffer + const buttonVariable * bpPtr; - } - else - { + cli(); // disable interrupts while interrupts are being fiddled with - if ((decimalFlag & dfAdjustWindow) && (i < windowLength)) windowLength++; // if variable window length, and window length > the # of integer digits, expand window to include decimal point + initCore(); // go initialize core MPGuino functionality - if ((i == windowLength) || ((i + 1) == windowLength)) x = z - windowLength; - else - { + j = EEPROM::powerUpCheck(); - x = z - i; - if ((x + windowLength) > 10) x = 11 - windowLength; + tripSupport::init(); - } +#ifdef useSimulatedFIandVSS + debugFlags = (debugVSSflag | debugInjectorFlag); + debugReading::configurePorts(); - } - - } - else // no window length specified, just eliminate leading spaces - { - - x = z - i; // point to first integer character in string buffer - strBuffer[11] = 0; // mark new end of string buffer - - } - - if (x) for (y = 0; y < (12 - x); y++) strBuffer[(unsigned int)(y)] = strBuffer[(unsigned int)(y + x)]; // shift number left to remove unneeded leading spaces - - } - else - { - - if (decimalFlag & dfOverflow9s) strcpy_P(strBuffer, overFlow9Str); - - } - - if (windowLength) strBuffer[(unsigned int)(windowLength)] = 0; // mark new end of string buffer - - return strBuffer; - -} - -/* Main screen section */ - -const char mainScreenFuncNames[] PROGMEM = { - "Instrument\r" - "Custom\r" - "Instant/Current\r" - "Instant/Tank\r" - "Current\r" - "Tank\r" -#ifdef trackIdleEOCdata - "EOC/Idle\r" -#endif // trackIdleEOCdata - "Current Data\r" - "Tank Data\r" -#ifdef trackIdleEOCdata - "Current EOC/Idle\r" - "Tank EOC/Idle\r" -#endif // trackIdleEOCdata - "Remaining\r" -}; - -const uint8_t mainDisplayScreenFormats[(unsigned int)(mainScreenDisplayFormatSize)][2] PROGMEM = { - {lblInstantIdx, tSpeed} // Instrument - ,{lblInstantIdx, tEngineSpeed} - ,{lblInstantIdx, tFuelRate} - ,{lblInstantIdx, tFuelEcon} - - ,{lblInstantIdx, tFuelEcon} // Custom - ,{lblInstantIdx, tSpeed} - ,{lblInstantIdx, tFuelRate} - ,{lblCurrentIdx, tFuelEcon} - - ,{lblInstantIdx, tFuelEcon} // Instant / Current - ,{lblInstantIdx, tSpeed} - ,{lblCurrentIdx, tFuelEcon} - ,{lblCurrentIdx, tDistance} - - ,{lblInstantIdx, tFuelEcon} // Instant / Tank - ,{lblInstantIdx, tSpeed} - ,{lblTankIdx, tFuelEcon} - ,{lblTankIdx, tDistance} - - ,{lblCurrentIdx, tSpeed} // Current - ,{lblCurrentIdx, tFuelEcon} - ,{lblCurrentIdx, tDistance} - ,{lblCurrentIdx, tFuelUsed} - - ,{lblTankIdx, tSpeed} // Tank - ,{lblTankIdx, tFuelEcon} - ,{lblTankIdx, tDistance} - ,{lblTankIdx, tFuelUsed} - -#ifdef trackIdleEOCdata - ,{lblEOCidleCurrentIdx, tDistance} // EOC / Idle - ,{lblEOCidleCurrentIdx, tFuelUsed} - ,{lblEOCidleTankIdx, tDistance} - ,{lblEOCidleTankIdx, tFuelUsed} - -#endif // trackIdleEOCdata - ,{lblCurrentIdx, tEngineRunTime} // Current data - ,{lblCurrentIdx, tFuelUsed} - ,{lblCurrentIdx, tMotionTime} - ,{lblCurrentIdx, tDistance} - - ,{lblTankIdx, tEngineRunTime} // Tank data - ,{lblTankIdx, tFuelUsed} - ,{lblTankIdx, tMotionTime} - ,{lblTankIdx, tDistance} - -#ifdef trackIdleEOCdata - ,{lblEOCidleCurrentIdx, tEngineRunTime} // Current EOC / Idle - ,{lblEOCidleCurrentIdx, tFuelUsed} - ,{lblEOCidleCurrentIdx, tMotionTime} - ,{lblEOCidleCurrentIdx, tDistance} - - ,{lblEOCidleTankIdx, tEngineRunTime} // Tank EOC / Idle - ,{lblEOCidleTankIdx, tFuelUsed} - ,{lblEOCidleTankIdx, tMotionTime} - ,{lblEOCidleTankIdx, tDistance} - -#endif // trackIdleEOCdata - ,{lblTankIdx, tFuelUsed} // Remaining - ,{lblTankIdx, tRemainingFuel} - ,{lblTankIdx, tTimeToEmpty} - ,{lblTankIdx, tDistanceToEmpty} -}; - -#ifdef trackIdleEOCdata -const uint8_t mainEOCscreenFormats[(unsigned int)(4)][2] PROGMEM = { - {lblInstantIdx, tSpeed} - ,{lblCurrentIdx, tFuelEcon} - ,{lblEOCidleCurrentIdx, tDistance} - ,{lblEOCidleTankIdx, tDistance} -}; - -const uint8_t mainIdleScreenFormats[(unsigned int)(4)][2] PROGMEM = { - {lblInstantIdx, tFuelRate} - ,{lblCurrentIdx, tFuelEcon} - ,{lblEOCidleCurrentIdx, tFuelUsed} - ,{lblEOCidleTankIdx, tFuelUsed} -}; - -#endif // trackIdleEOCdata -uint8_t mainScreenDisplayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged) -{ - -#ifdef useScreenEditor - uint8_t i; -#endif // useScreenEditor - uint8_t retVal = 0; - - switch (cmd) - { - - case menuExitIdx: - break; - - case menuEntryIdx: - topScreenLevel = menuLevel; // save current menu level for sub-function (param edit, trip load/save, etc) support - - case menuCursorUpdateIdx: - printStatusMessage(mainScreenFuncNames, cursorPos); // briefly display screen name - - case menuOutputDisplayIdx: - retVal = (activityFlags & afActivityCheckFlags); - switch (retVal) - { - - case (afVehicleStoppedFlag | afButtonFlag): -#ifdef trackIdleEOCdata -#ifdef useSpiffyTripLabels - displayMainScreenFunctions(mainIdleScreenFormats, 0, 136, 0, msTripBitPattern); -#else // useSpiffyTripLabels - displayMainScreenFunctions(mainIdleScreenFormats, 0); -#endif // useSpiffyTripLabels - break; - -#endif // trackIdleEOCdata - case (afEngineOffFlag | afButtonFlag): -#ifdef trackIdleEOCdata -#ifdef useSpiffyTripLabels - displayMainScreenFunctions(mainEOCscreenFormats, 0, 136, 0, msTripBitPattern); -#else // useSpiffyTripLabels - displayMainScreenFunctions(mainEOCscreenFormats, 0); -#endif // useSpiffyTripLabels - break; - -#endif // trackIdleEOCdata - default: -#ifdef useScreenEditor - i = cursorPos; - i <<= 2; - i += eePtrScreensStart; - -#ifdef useSpiffyTripLabels - for (uint8_t x = 0; x < 4; x++) displayFunction(x, EEPROM::readVal(i++), EEPROM::readVal(i++), 136, 0, msTripBitPattern); -#else // useSpiffyTripLabels - for (uint8_t x = 0; x < 4; x++) displayFunction(x, EEPROM::readVal(i++), EEPROM::readVal(i++)); -#endif // useSpiffyTripLabels - -#else // useScreenEditor -#ifdef useSpiffyTripLabels - displayMainScreenFunctions(mainDisplayScreenFormats, cursorPos, 136, 0, msTripBitPattern); -#else // useSpiffyTripLabels - displayMainScreenFunctions(mainDisplayScreenFormats, cursorPos); -#endif // useSpiffyTripLabels -#endif // useScreenEditor - break; - - } - retVal = 0; - break; - - default: - break; - - } - - return retVal; - -} - -void doReturnToMainScreen(void) -{ - - cursor::moveAbsolute(topScreenLevel, 255); - -} - -void doNextBright(void) -{ - - initStatusLine(); - text::stringOut(devLCD, PSTR("Backlight = ")); - text::stringOut(devLCD, brightString, brightnessIdx); - execStatusLine(); - -} - -#ifdef useDeepSleep // Deep Sleep support section -void doGoDeepSleep(void) -{ - - peripheral::shutdownMain(); - -#ifdef useTWIsupport - TWI::shutdown(); - -#endif // useTWIsupport - performSleepMode(SLEEP_MODE_PWR_DOWN); // go perform power-down sleep mode - - peripheral::initMain(); // restart all peripherals - -} - -#endif // useDeepSleep -#ifdef useScreenEditor // Programmable main display screen edit support section -uint8_t screenTripValue = 0; -uint8_t screenFunctionValue = 0; -uint8_t screenEditDirty = 0; - -const uint8_t screenEditFlag_dirty = 0x80; - -const char seFormatRevertedString[] PROGMEM = "Format reverted"; -const char seExitScreenEditString[] PROGMEM = "Screen Display"; - -void doCursorUpdateScreenEdit(void) -{ - - uint8_t b; - - b = screenCursor[(unsigned int)(screenEditIdx)]; - b &= ~screenEditFlag_dirty; - - if ((screenEditDirty & ~screenEditFlag_dirty) ^ b) // if cursor moved to a different screen function altogether - { - - screenTripValue = EEPROM::readVal(b + eePtrScreensStart); - screenFunctionValue = EEPROM::readVal(b + eePtrScreensStart + 1); - - if (screenEditDirty & screenEditFlag_dirty) // if previous screen function was changed but not saved - { - - printStatusMessage(seFormatRevertedString); - - } - - screenEditDirty = b; // save current cursor position of screen function being edited - screenEditDirty &= ~screenEditFlag_dirty; // mark screen function as not modified - - } - -} - -void doScreenEditDisplay(void) -{ - - uint8_t i; - uint8_t j; - uint8_t k; - - uint8_t tripIdx; - uint8_t calcIdx; - uint8_t calcBlink; - uint8_t tripBlink; - - i = screenCursor[(unsigned int)(screenEditIdx)]; - - j = i; // extract whether trip index or trip function is to be edited - j &= 0x01; - - i >>= 1; // figure out edited screen function placement on screen - k = i; - - i &= 0xFC; // figure out start of screen page - k &= 0x03; - - for (uint8_t x = 0; x < 4; x++) - { - - calcBlink = 0; - tripBlink = 0; - - if (x == k) // if at - { - - tripIdx = screenTripValue; - calcIdx = screenFunctionValue; - if (j == 1) calcBlink = 170; - else tripBlink = 170; - - } - else - { - - tripIdx = EEPROM::readVal(eePtrScreensStart + (i + x) * 2); - calcIdx = EEPROM::readVal(eePtrScreensStart + (i + x) * 2 + 1); - - } - -#ifdef useSpiffyTripLabels - displayFunction(x, tripIdx, calcIdx, tripBlink, calcBlink, msTripBitPattern); // call main screen function display routine -#else // useSpiffyTripLabels - displayFunction(x, tripIdx, calcIdx); // call main screen function display routine -#endif // useSpiffyTripLabels - - } - -} - -void doGoScreenEdit(void) -{ - - screenEditDirty = screenCursor[(unsigned int)(screenEditIdx)]; - screenEditDirty >>= 1; - screenEditDirty ^= 0x01; // force update of screen function - screenEditDirty &= ~screenEditFlag_dirty; - - cursor::moveAbsolute(screenEditIdx, screenCursor[(unsigned int)(mainScreenIdx)] << 3); - - printStatusMessage(PSTR("Screen Editor")); - -} - -void doScreenEditBump(void) -{ - - uint8_t b; - - b = (screenCursor[(unsigned int)(screenEditIdx)] & 0x01); // figure out whether trip variable or trip function is being modified - screenEditDirty |= screenEditFlag_dirty; // mark current screen function as modified - - if (b) // if trip function is being modified - { - - screenFunctionValue++; - if (screenFunctionValue == dfMaxValDisplayCount) screenFunctionValue = 0; - - } - else // otherwise, trip variable is being modified - { - - screenTripValue++; - if (screenTripValue == dfMaxTripCount) screenTripValue = 0; - - } - -} - -void doSaveScreen(void) -{ - - uint8_t b; - - b = screenCursor[(unsigned int)(screenEditIdx)]; - - // generate and save new screen function from trip variable and trip function - EEPROM::writeVal(eePtrScreensStart + b, (unsigned long)(screenTripValue)); - EEPROM::writeVal(eePtrScreensStart + b + 1, (unsigned long)(screenFunctionValue)); - screenEditDirty &= ~screenEditFlag_dirty; - - printStatusMessage(PSTR("Format saved")); - -} - -void doScreenReturnToMain(void) -{ - - const char * str; - - if (screenEditDirty & screenEditFlag_dirty) str = seFormatRevertedString; - else s = seExitScreenEditString; - - screenCursor[(unsigned int)(mainScreenIdx)] = (screenCursor[(unsigned int)(screenEditIdx)] >> 3); - cursor::screenLevelEntry(str, topScreenLevel); - -} - -#endif // useScreenEditor -/* human interface I/O peripheral device support section */ - -#ifdef useExpansionPins -/* - Modes - 0 Off - 1 instant fuel economy < current fuel economy (0 - false, 255 - true) - 2 instant fuel economy > current fuel economy (0 - false, 255 - true) - 3 instant fuel economy < tank fuel economy (0 - false, 255 - true) - 4 instant fuel economy > tank fuel economy (0 - false, 255 - true) - 5 estimated tank fuel consumed (0 (none) to 255 (all of the tank), based on tank size) - 6 estimated tank fuel remaining (0 (empty) to 255 (full), based on tank size) -*/ -static const uint8_t prgmCalculateOutputPinValue[] PROGMEM = { - instrCmpIndex, 2, // is a valid expansion output pin number being requested? - instrBranchIfGTorE, 13, // skip to output a zero if not - instrLxdIEEPROMoffset, pExpansionPin1Mode, // load the indexed stored parameter index for the expansion output pin setting - instrTestIndex, // test pin mode value for zero - instrBranchIfZero, 8, // exit out if pin mode is zero - instrCmpIndex, 4, // test if pin mode is "fuel economy comparison between instant and whatever" - instrBranchIfLTorE, 26, // if so, skip ahead - instrCmpIndex, 6, // test if pin mode is analog output tank quantity or quantity remaining - instrBranchIfLTorE, 4, // if so, skip ahead - -//zeroOutRet: - instrLdRegByte, 0x02, 0, // zero out result - instrDone, // exit to caller - -//analogOut: - instrCall, tCalculateRemainingTank, // fetch remaining fuel value in injector open cycles - instrCmpIndex, 6, // outputting remaining value? - instrBranchIfE, 7, // go do conversion if so - instrLdReg, 0x21, // shift contents to register 1 - instrLdRegMain, 0x02, mpTankSizeIdx, // fetch calculated tank size in injector open cycles - instrSubYfromX, 0x12, // subtract remaining fuel value from tank size - -//analogOut2: - instrMul2byByte, 255, // multiply tank quantity by 255 - instrDiv2byMain, mpTankSizeIdx, // divide by calculated tank size - instrDone, // return to caller - -// US (inst FE > accumulated FE) = /(inst FE <= accumulated FE) -// -// (inst distance) (accum distance) -// --------------- <= ---------------- >>> (inst distance) * (accum quantity) <= (inst quantity) * (accum distance) -// (inst quantity) (accum quantity) -// -// -// -// metric (inst FE > accumulated FE) = /(inst FE <= accumulated FE) -// -// (inst quantity) (accum quantity) -// --------------- => ---------------- >>> (inst quantity) * (accum distance) => (inst distance) * (accum quantity) -// (inst distance) (accum distance) or -// (inst distance) * (accum quantity) <= (inst quantity) * (accum distance) -// -// therefore, for (inst FE > accumulated FE) comparison, there is no need to check whether MPGuino is in metric mode or not -// (inst FE < accumulated FE) is treated in a similar way, but the left and right terms are swapped around -// - instrCmpIndex, 2, // comparing instant to current? - instrBranchIfLTorE, 10, // if so, skip ahead - instrLdRegTripVar, 0x03, tankIdx, rvInjCycleIdx, // fetch tank (accum quantity) - instrLdRegTripVar, 0x02, tankIdx, rvVSSpulseIdx, // fetch tank (accum distance) - instrSkip, 8, // skip ahead - instrLdRegTripVar, 0x03, currentIdx, rvInjCycleIdx, // fetch current (accum quantity) - instrLdRegTripVar, 0x02, currentIdx, rvVSSpulseIdx, // fetch current (accum distance) - instrLdRegTripVar, 0x01, instantIdx, rvInjCycleIdx, // fetch (inst quantity) - instrMul2by1, // calculate (inst quantity) * (accum distance) as right term - instrSwapReg, 0x23, // swap right term and (accum quantity) values - instrLdRegTripVar, 0x01, instantIdx, rvVSSpulseIdx, // fetch (inst distance) - instrMul2by1, // calculate (inst distance) * (accum quantity) as left term - instrCmpIndex, 2, // testing (inst distance) * (current quantity) <= (inst quantity) * (current distance)? - instrBranchIfE, 6, // if so, skip ahead - instrCmpIndex, 4, // testing (inst distance) * (tank quantity) <= (inst quantity) * (tank distance)? - instrBranchIfE, 2, // if so, skip ahead - instrSwapReg, 0x23, // swap left and right terms - instrCmpXtoY, 0x32, // compare left term to right term - instrBranchIfLTorE, 4, // if left term <= right term, go zero out and return - - instrLdRegByte, 0x02, 255, // max out result - instrDone, // return to caller - - instrLdRegByte, 0x02, 0, // zero out result - instrDone // exit to caller -}; - -#endif // useExpansionPins -static void peripheral::initMain(void) -{ - - uint8_t oldSREG; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts - - // timer initialization section - multiple peripherals may use the same timer -#ifdef useTimer1 -#if defined(__AVR_ATmega32U4__) - // turn on timer1 module - PRR0 &= ~(1 << PRTIM1); - - // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF - TCCR1A &= ~(1 << WGM11); - TCCR1A |= (1 << WGM10); - TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); - - // set timer 1 prescale factor to 1 - TCCR1B &= ~((1 << CS12) | (1 << CS11)); - TCCR1B |= (1 << CS10); - - // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture - TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); - - // set OC1A to disabled - TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); - - // set OC1B to disabled - TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); - - // set OC1C to disabled - TCCR1A &= ~((1 << COM1C1) | (1 << COM1C0)); - - // clear timer 1 output compare force bits for OC1A, OC1B, and OC1C - TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B) | (1 << FOC1C)); - -#ifdef useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A)); - - // enable timer1 overflow interrupt - TIMSK1 |= (1 << TOIE1); -#else // useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); -#endif // useTimer1Interrupt - - // clear timer 1 interrupt flags - TIFR1 |= ((1 << ICF1) | (1 << OCF1C) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); - -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - // turn on timer1 module - PRR0 &= ~(1 << PRTIM1); - - // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF - TCCR1A &= ~(1 << WGM11); - TCCR1A |= (1 << WGM10); - TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); - - // set timer 1 prescale factor to 1 - TCCR1B &= ~((1 << CS12) | (1 << CS11)); - TCCR1B |= (1 << CS10); - - // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture - TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); - - // set OC1A to disabled - TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); - - // set OC1B to disabled - TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); - - // clear timer 1 output compare force bits for OC1A, OC1B, and OC1C - TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B) | (1 << FOC1C)); - -#ifdef useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A)); - - // enable timer1 overflow interrupt - TIMSK1 |= (1 << TOIE1); -#else // useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1C) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); -#endif // useTimer1Interrupt - - // clear timer 1 interrupt flags - TIFR1 |= ((1 << ICF1) | (1 << OCF1C) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // turn on timer1 module - PRR &= ~(1 << PRTIM1); - - // set timer 1 to 8-bit phase correct PWM mode, TOP = 0xFF - TCCR1A &= ~(1 << WGM11); - TCCR1A |= (1 << WGM10); - TCCR1B &= ~((1 << WGM13) | (1 << WGM12)); - - // set timer 1 prescale factor to 1 - TCCR1B &= ~((1 << CS12) | (1 << CS11)); - TCCR1B |= (1 << CS10); - - // disable timer 1 input capture noise canceler, select timer 1 falling edge for input capture - TCCR1B &= ~((1 << ICNC1) | (1 << ICES1)); - - // set OC1A to disabled - TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); - - // set OC1B to disabled - TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); - - // clear timer 1 output compare force bits for OC1A and OC1B - TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B)); - -#ifdef useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A)); - - // enable timer1 overflow interrupt - TIMSK1 |= (1 << TOIE1); -#else // useTimer1Interrupt - // disable timer 1 interrupts - TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1)); -#endif // useTimer1Interrupt - - // clear timer 1 interrupt flags - TIFR1 |= ((1 << ICF1) | (1 << OCF1B) | (1 << OCF1A) | (1 << TOV1)); - -#endif // defined(__AVR_ATmega328P__) -#endif // useTimer1 -#ifdef useTimer2 -#if defined(__AVR_ATmega2560__) - // turn on timer2 module - PRR0 &= ~(1 << PRTIM2); - - // set timer 2 to 8-bit phase correct PWM mode, TOP = 0xFF - TCCR2A &= ~(1 << WGM21); - TCCR2A |= (1 << WGM20); - TCCR2B &= ~(1 << WGM22); - - // set timer 2 prescale factor to 64 - TCCR2B &= ~((1 << CS22)); - TCCR2B |= ((1 << CS21) | (1 << CS20)); - - // set OC2A to disabled - TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); - - // set OC2B to disabled - TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); - - // clear timer 2 output compare force bits for OC2A and OC2B - TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B)); - - // disable timer 2 interrupts - TIMSK2 &= ~((1 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2)); - - // clear timer 2 interrupt flags - TIFR2 |= ((1 << OCF2B) | (1 << OCF2A) | (1 << TOV2)); - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // turn on timer2 module - PRR &= ~(1 << PRTIM2); - - // set timer 2 to phase correct PWM mode, TOP = 0xFF - TCCR2A &= ~(1 << WGM21); - TCCR2A |= (1 << WGM20); - TCCR2B &= ~(1 << WGM22); - - // set timer 2 prescale factor to 64 - TCCR2B &= ~((1 << CS22)); - TCCR2B |= ((1 << CS21) | (1 << CS20)); - - // set OC2A to disabled - TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); - - // set OC2B to disabled - TCCR2A &= ~((1 << COM2B1) | (1 << COM2B0)); - - // clear force bits for OC2A and OC2B - TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B)); - - // disable timer 2 interrupts - TIMSK2 &= ~((1 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2)); - - // clear timer 2 interrupt flags - TIFR2 |= ((1 << OCF2B) | (1 << OCF2A) | (1 << TOV2)); - -#endif // defined(__AVR_ATmega328P__) -#endif // useTimer2 -#ifdef useTimer4 -#if defined(__AVR_ATmega32U4__) - // turn on timer4 module - PRR1 &= ~(1 << PRTIM4); - - // set timer 4 to phase and frequency correct mode - TCCR4D &= ~(1 << WGM41); - TCCR4D |= (1 << WGM40); - - // set timer 4 prescale factor to 64 - TCCR4B &= ~(1 << CS43); - TCCR4B |= ((1 << CS42) | (1 << CS41) | (1 << CS40)); - - // clear timer 4 fault protection - TCCR4D &= ~((1 << FPIE4) | (1 << FPEN4) | (1 << FPNC4) | (1 << FPES4) | (1 << FPAC4) | (1 << FPF4)); - - // set OC4A to disabled - TCCR4A &= ~((1 << COM4A1) | (1 << COM4A0) | (1 << PWM4A)); - - // set OC4B to disabled - TCCR4A &= ~((1 << COM4B1) | (1 << COM4B0) | (1 << PWM4B)); - - // set OC4D to disabled - TCCR4C &= ~((1 << COM4D1) | (1 << COM4D0) | (1 << PWM4D)); - - // clear timer 4 PWM inversion mode - TCCR4B &= ~(1 << PWM4X); - - // set timer 4 dead time prescaler to 1 - TCCR4B &= ~((1 << DTPS41) | (1 << DTPS40)); - - // clear timer 4 output compare force bits for OC4A and OC4B - TCCR4A &= ~((1 << FOC4A) | (1 << FOC4B)); - - // clear timer 4 output compare force bits for OC4D - TCCR4C &= ~(1 << FOC4D); - - // clear timer 4 update lock, disable timer 4 enhanced compare mode - TCCR4E &= ~((1 << TLOCK4) | (1 << ENHC4)); - - // disable timer 4 interrupts - TIMSK4 &= ~((1 < OCIE4D) | (1 < OCIE4A) | (1 < OCIE4B) | (1 < TOIE4)); - - // clear timer 4 interrupt flags - TIFR4 |= ((1 << OCF4D) | (1 << OCF4A) | (1 << OCF4B) | (1 << TOV4)); - - // set timer 4 dead time to 0 - DT4 = 0; - - // set timer 4 TOP value to 0x00FF, setting 8 bit mode - TC4H = 0; - OCR4C = 255; - -#endif // defined(__AVR_ATmega32U4__) -#endif // useTimer4 - SREG = oldSREG; // restore interrupt flag status - -#ifdef useTWIsupport - TWI::init(); -#ifdef useAdafruitRGBLCDshield - adafruitRGBLCDsupport::init(); // go init Adafruit RGB LCD shield -#endif // useAdafruitRGBLCDshield -#endif // useTWIsupport -#ifdef useSerial0Port - serial0::init(); -#endif // useSerial0Port -#ifdef useSerial1Port - serial1::init(); -#endif // useSerial1Port -#if defined(__AVR_ATmega32U4__) - initUSB(); -#endif // defined(__AVR_ATmega32U4__) - initButton(); - LCD::init(); -#ifdef useStatusLEDpins - initStatusLED(); -#endif // useStatusLEDpins -#ifdef useExpansionPins - initExpansionPin(); -#endif // useExpansionPins - -} - -static void peripheral::shutdownMain(void) -{ - -#ifdef useExpansionPins - shutdownExpansionPin(); -#endif // useExpansionPins -#ifdef useStatusLEDpins - shutdownStatusLED(); -#endif // useStatusLEDpins - changeBitFlags(timer0Command, t0cDisplayDelay, 0); // cancel any display delays in progress - LCD::shutdown(); // shut down the LCD display - shutdownButton(); -#if defined(__AVR_ATmega32U4__) - shutdownUSB(); -#endif // defined(__AVR_ATmega32U4__) -#ifdef useSerial1Port - serial1::shutdown(); -#endif // useSerial1Port -#ifdef useSerial0Port - serial0::shutdown(); -#endif // useSerial0Port - -#ifdef useTimer4 -#if defined(__AVR_ATmega32U4__) - PRR0 |= (1 << PRTIM4); // shut off timer4 module to reduce power consumption -#endif // defined(__AVR_ATmega32U4__) - -#endif // useTimer4 -#ifdef useTimer2 -#if defined(__AVR_ATmega2560__) - PRR0 |= (1 << PRTIM2); // shut off timer2 module to reduce power consumption -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - PRR |= (1 << PRTIM2); // shut off timer2 module to reduce power consumption -#endif // defined(__AVR_ATmega328P__) - -#endif // useTimer2 -#ifdef useTimer1Interrupt -#if defined(__AVR_ATmega32U4__) - // disable timer1 overflow interrupt - TIMSK1 &= ~(1 << TOIE1); -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - // disable timer1 overflow interrupt - TIMSK1 &= ~(1 << TOIE1); -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // disable timer1 overflow interrupt - TIMSK1 &= ~(1 << TOIE1); -#endif // defined(__AVR_ATmega328P__) - -#endif // useTimer1Interrupt -#ifdef useTimer1 -#if defined(__AVR_ATmega32U4__) - PRR0 |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - PRR0 |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - PRR |= (1 << PRTIM1); // shut off timer1 module to reduce power consumption -#endif // defined(__AVR_ATmega328P__) - -#endif // useTimer1 -} - -// this function is needed since there is no way to perform an atomic bit change of an SRAM byte value -// most MPGuino variables that are shared between main program and interrupt handlers should not need to -// be treated as atomic (!) because only one side or the other is supposed to change said variables -// however, status flag registers are obviously an exception, and status flag changes are common -// enough to warrant an explicit function definition -static void peripheral::changeBitFlags(volatile uint8_t &flagRegister, uint8_t maskAND, uint8_t maskOR) -{ - - uint8_t oldSREG; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts - - flagRegister = (flagRegister & ~(maskAND)) | (maskOR); // go perform atomic status flag change - - SREG = oldSREG; // restore interrupt flag status - -} - -#ifdef useExpansionPins -static void peripheral::initExpansionPin(void) -{ - -#if defined(__AVR_ATmega32U4__) - // set OC4A to clear-up/set-down PWM mode for EXP1 option pin - TCCR4A &= ~(1 << COM4A0); - TCCR4A |= ((1 << COM4A1) | (1 << PWM4A)); - - // set OC4D to clear-up/set-down PWM mode for EXP2 option pin - TCCR4C &= ~(1 << COM4D0); - TCCR4C |= ((1 << COM4D1) | (1 << PWM4D)); - - // enable EXP1 and EXP2 option pin outputs - DDRC |= (1 << DDC6); // set OC4A as output - DDRD |= (1 << DDD7); // set OC4D as output - -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - // set OC1B to clear-up/set-down for EXP1 option pin - TCCR1A &= ~(1 << COM1B0); - TCCR1A |= (1 << COM1B1); - - // set OC2A to clear-up/set-down for EXP2 option pin - TCCR2A &= ~(1 << COM2A0); - TCCR2A |= (1 << COM2A1); - - // enable EXP1 and EXP2 option pin outputs - DDRB |= ((1 << PB6) | (1 << PB4)); - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // set OC1B to non-inverting mode for EXP1 option pin - TCCR1A &= ~(1 << COM1B0); - TCCR1A |= (1 << COM1B1); - - // set OC2A to clear-up/set-down for EXP2 option pin - TCCR2A &= ~(1 << COM2A0); - TCCR2A |= (1 << COM2A1); - - // enable EXP1 and EXP2 option pin outputs - DDRB |= ((1 << PB3) | (1 << PB2)); - -#endif // defined(__AVR_ATmega328P__) - outputExpansionPin1(2); // initially set EXP1 option pin to 0 - outputExpansionPin2(2); // initially set EXP2 option pin to 0 - -} - -static void peripheral::shutdownExpansionPin(void) -{ - - outputExpansionPin1(2); // set EXP1 option pin to 0 - outputExpansionPin2(2); // set EXP2 option pin to 0 - -#if defined(__AVR_ATmega32U4__) - // disable expansion pin output - DDRC &= ~(1 << DDC6); - DDRD &= ~(1 << DDD7); - - // set OC4A to disabled for EXP1 option pin - TCCR4A &= ~((1 << COM4A1) | (1 << COM4A0) | (1 << PWM4A)); - - // set OC4D to disabled for EXP2 option pin - TCCR4C &= ~((1 << COM4D1) | (1 << COM4D0) | (1 << PWM4D)); - -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - // disable expansion pin output - DDRB &= ~((1 << PB6) | (1 << PB4)); - - // set OC1B to disabled for EXP1 option pin - TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); - - // set OC2A to disabled for EXP2 option pin - TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0)); - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // disable expansion pin output - DDRB &= ~((1 << PB3) | (1 << PB2)); - - // set OC1B to disabled for EXP1 option pin - TCCR1A &= ~((1 << COM1B1) | (1 << COM1B0)); - - // set OC2A to disabled for EXP2 option pin - TCCR2A &= ~(1 << COM2A0); - TCCR2A |= (1 << COM2A1); - -#endif // defined(__AVR_ATmega328P__) -} - -// sets EXP1 option pin PWM output from 0-100% -static void peripheral::outputExpansionPin1(uint8_t pin) -{ - - uint8_t val = SWEET64::runPrgm(prgmCalculateOutputPinValue, pin); - -#if defined(__AVR_ATmega32U4__) - OCR4A = val; -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - OCR1B = val; -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - OCR1B = val; -#endif // defined(__AVR_ATmega328P__) - -} - -// sets EXP2 option pin PWM output from 0-100% -static void peripheral::outputExpansionPin2(uint8_t pin) -{ - - uint8_t val = SWEET64::runPrgm(prgmCalculateOutputPinValue, pin); - -#if defined(__AVR_ATmega32U4__) - OCR4D = val; -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - OCR2A = val; -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - OCR2A = val; -#endif // defined(__AVR_ATmega328P__) - -} - -#endif // useExpansionPins -static void peripheral::initButton(void) -{ - -#ifdef useAdafruitRGBLCDshield - uint16_t MCP23017registers; -#endif // useAdafruitRGBLCDshield - uint8_t oldSREG; - -#ifdef useAdafruitRGBLCDshield -#if useTWIbuttons && useTWILCD - LCD::disableIntSample(); // disable TWI button sampling - -#endif // useTWIbuttons && useTWILCD - MCP23017registers = (uint16_t)(buttonMask); - - adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_IODIRx, (union_16 *)(&MCP23017registers)); // write out port direction (only buttons as input) - adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_GPPUx, (union_16 *)(&MCP23017registers)); // write out pull-up resistor config (only buttons as input) - adafruitRGBLCDsupport::writeRegister16Bit(MCP23017_B0_IPOLx, (union_16 *)(&MCP23017registers)); // write out input pin polarity config (only buttons as input) - - adafruitRGBLCDsupport::setTransferMode(adaTWIbyteMode); // ensure address mode is in byte mode - -#if useTWIbuttons && useTWILCD - LCD::enableIntSample(); // enable TWI button sampling - -#endif // useTWIbuttons && useTWILCD -#endif // useAdafruitRGBLCDshield - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts - -#ifdef useLegacyButtons -#if defined(__AVR_ATmega2560__) - DIDR2 &= ~((1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D)); // enable digital input on port K button pins - - PORTK |= ((1 << PORTK5) | (1 << PORTK4) | (1 << PORTK3)); // enable port K button pullup resistors - - PCMSK2 |= ((1 << PCINT21) | (1 << PCINT20) | (1 << PCINT19)); // enable port K button interrupts - - PCICR |= (1 << PCIE2); // enable selected interrupts on port K - - lastPINxState = PINK; // initialize last input pin state value so as to not erroneously detect a button press on start - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - DIDR0 &= ~((1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D)); // enable digital input on port C button pins - - PORTC |= ((1 << PORTC5) | (1 << PORTC4) | (1 << PORTC3)); // enable port C button pullup resistors - - PCMSK1 |= ((1 << PCINT13) | (1 << PCINT12) | (1 << PCINT11)); // enable port C button interrupts - - PCICR |= (1 << PCIE1); // enable selected interrupts on port C - - lastPINxState = PINC; // initialize last input pin state value so as to not erroneously detect a button press on start - -#endif // defined(__AVR_ATmega328P__) -#endif // useLegacyButtons - SREG = oldSREG; // restore interrupt flag status - -} - -static void peripheral::shutdownButton(void) -{ -} - -#if defined(useAnalogButtons) || defined(useDebugTerminal) -static void peripheral::injectButton(uint8_t buttonValue) -{ - - uint8_t oldSREG; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operations atomic - - thisButtonState = buttonValue; - timer0Command |= (t0cProcessButton); // send timer0 notification that a button was just read in - - SREG = oldSREG; // restore interrupt flag status - -} - -#endif // useAnalogButtons || useDebugTerminal -#if defined(__AVR_ATmega32U4__) -static void peripheral::initUSB(void) -{ - - uint8_t oldSREG; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts - - PRR1 &= ~(1 << PRUSB); // turn on USB hardware - - UHWCON = (1 << UVREGE); // enable USB pad regulator - - USBCON = ((1 << USBE) | (1 << FRZCLK)); // enable USB controller, disable clock inputs - -#if F_CPU == 16000000UL - PLLCSR = ((1 << PINDIV) | (1 << PLLE)); // set PLL input prescaler for 16 MHz clock source, and enable PLL -#elif F_CPU == 8000000UL - PLLCSR = (1 << PLLE); // set PLL input prescaler for 8 MHz clock source, and enable PLL -#else // F_CPU == 16000000UL -#error *** F_CPU clock rate not supported!!! *** -#endif // F_CPU == 16000000UL - - while (!(PLLCSR & (1 << PLOCK))); // wait for PLL lock - - USBCON = ((1 << USBE) | (1 << OTGPADE)); // keep USB controller enabled, enable clock inputs, enable VBUS pad - - UDCON = 0; // select USB high speed mode - - usbConfiguration = 0; - - UDIEN = ((1 << EORSTE) | (1 << SOFE)); // enable End-Of-Reset, Start-Of-Frame interrupts - - SREG = oldSREG; // restore interrupt flag status - -} - -static void peripheral::shutdownUSB(void) -{ - - uint8_t oldSREG; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts - - UDIEN = 0; // disable all USB interrupts - - USBCON = 0; // disable USB controller - - PLLCSR = 0; // disable PLL - - UHWCON = 0; // disable USB pad regulator - - PRR1 |= (1 << PRUSB); // turn off USB hardware - - SREG = oldSREG; // restore interrupt flag status - -} - -#endif // defined(__AVR_ATmega32U4__) -#ifdef useStatusLEDpins -static void peripheral::initStatusLED(void) -{ - -#if defined(__AVR_ATmega32U4__) -#ifdef useTinkerkitLCDmodule -// DDRB |= (1 << DDB0); // turn on digital output for RX LED - DDRC |= (1 << DDC7); // turn on digital output for LED L -// DDRD |= (1 << DDD5); // turn on digital output for TX LED -#else // useTinkerkitLCDmodule -// insert any other ATmega32U4 port information for initializing status LEDs here -#endif // useTinkerkitLCDmodule -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) -#ifdef useArduinoMega2560 - DDRB |= (1 << DDB7); // turn on digital output for LED L -#else // useArduinoMega2560 -// insert any other ATmega2560 port information for initializing status LEDs here -#endif // useArduinoMega2560 -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - DDRB |= (1 << DDB5); // turn on digital output for LED L -#endif // defined(__AVR_ATmega328P__) - - outputStatusLED(0); // initially turn off status LED - -} - -static void peripheral::shutdownStatusLED(void) -{ - - outputStatusLED(0); // turn off status LED - -#if defined(__AVR_ATmega32U4__) -#ifdef useTinkerkitLCDmodule -// DDRB &= ~(1 << DDB0); // turn off digital output for RX LED - DDRC &= ~(1 << DDC7); // turn off digital output for LED L -// DDRD &= ~(1 << DDD5); // turn off digital output for TX LED -#else // useTinkerkitLCDmodule -// insert any other ATmega32U4 port information for turning off status LEDs here -#endif // useTinkerkitLCDmodule -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) -#ifdef useArduinoMega2560 - DDRB &= ~(1 << DDB7); // turn off digital output for LED L -#else // useArduinoMega2560 -// insert any other ATmega2560 port information for turning off status LEDs here -#endif // useArduinoMega2560 -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - DDRB &= ~(1 << DDB5); // turn off digital output for LED L -#endif // defined(__AVR_ATmega328P__) - -} - -static void peripheral::outputStatusLED(uint8_t val) -{ - - if (val) - { - -#if defined(__AVR_ATmega32U4__) -#ifdef useTinkerkitLCDmodule -// PORTB &= ~(1 << PORTB0); // active low RX - PORTC |= (1 << PORTC7); // active high L -// PORTD &= ~(1 << PORTD5); // active low TX -#else // useTinkerkitLCDmodule -// insert any other ATmega32U4 port information for turning on status LEDs here -#endif // useTinkerkitLCDmodule -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) -#ifdef useArduinoMega2560 - PORTB |= (1 << PORTB7); // active high L -#else // useArduinoMega2560 -// insert any other ATmega2560 port information for turning on status LEDs here -#endif // useArduinoMega2560 -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - PORTB |= (1 << PORTB5); // active high L -#endif // defined(__AVR_ATmega328P__) - - } - else - { - -#if defined(__AVR_ATmega32U4__) -#ifdef useTinkerkitLCDmodule -// PORTB |= (1 << PORTB0); // active low RX - PORTC &= ~(1 << PORTC7); // active high L -// PORTD |= (1 << PORTD5); // active low TX -#else // useTinkerkitLCDmodule -// insert any other ATmega32U4 port information for turning off status LEDs here -#endif // useTinkerkitLCDmodule -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) -#ifdef useArduinoMega2560 - PORTB &= ~(1 << PORTB7); // active high L -#else // useArduinoMega2560 -// insert any other ATmega2560 port information for turning off status LEDs here -#endif // useArduinoMega2560 -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - PORTB &= ~(1 << PORTB5); // active high L -#endif // defined(__AVR_ATmega328P__) - - } - -} - -#endif // useStatusLEDpins -// this function is called whenever the main program has to wait for some external condition to occur -// when the main program performs some I/O activity, the target peripheral may take some time to acknowledge the activity -// and let the main program know that the peripheral is ready for more activity -// oftentimes, the main program has to wait for the peripheral in question, so instead of spinning its wheels, it will simply -// cause the processor to go to sleep by calling this function -// any interrupt will wake up the processor - this also means the primary timer0 -// this function is therefore ideal for placing all purely internal operations that do not require direct interaction with the outside world -// -// - fuel/vehicle speed data transfers -// - acceleration test state changes -// - debug sensor simulation counter updates -// - analog button read translations -// - Chrysler fuel correction factor calculations -// - any other operation not requiring interaction with peripherals that require waiting periods to finish -// -// said internal operations would hopelessly bog down interrupt handlers, were they loaded with these internal operations -// -static void idleProcess(void) -{ - - uint8_t oldSREG; - uint8_t i; - uint8_t j; - uint8_t k; - uint8_t m; -#ifdef useStatusLEDpins - uint8_t ledSleepVal = 0; -#endif // useStatusLEDpins -#ifdef useCPUreading - uint32_t idleStart; -#endif // useCPUreading - -#ifdef useStatusLEDpins - peripheral::outputStatusLED(ledSleepVal); - -#endif // useStatusLEDpins -#ifdef useCPUreading - idleStart = systemInfo::cycles0(); // record starting time - -#endif // useCPUreading - performSleepMode(SLEEP_MODE_IDLE); // go perform idle sleep mode - -#ifdef useCPUreading - idleTimerLength += systemInfo::findCycleLength(idleStart, systemInfo::cycles0()); -#ifdef useDebugCPUreading - idleStart = systemInfo::cycles0(); // record starting time -#endif // useDebugCPUreading - -#endif // useCPUreading -#ifdef useStatusLEDpins - peripheral::outputStatusLED(1 - ledSleepVal); - -#endif // useStatusLEDpins - // this is the part of the main loop that only executes twice a second (or what is defined by loopsPerSecond), to collect and process readings - if (timer0Status & t0sTakeSample) // if main timer has commanded a sample be taken - { - - peripheral::changeBitFlags(timer0Status, t0sTakeSample, 0); // acknowledge sample command - -#ifdef useCPUreading - mainProgramVariables[(uint16_t)(mpMainLoopAccumulatorIdx)] = systemInfo::findCycleLength(mainStart, systemInfo::cycles0()); - mainProgramVariables[(uint16_t)(mpIdleAccumulatorIdx)] = idleTimerLength; - - mainStart = systemInfo::cycles0(); - idleTimerLength = 0; - -#ifdef useDebugCPUreading - switch (monitorState) - { - - case 1: - idleProcessTimerLength = 0; - displayTimerLength = 0; - SWEET64timerLength = 0; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operations atomic - - volatileVariables[(uint16_t)(vInterruptAccumulatorIdx)] = 0; - - SREG = oldSREG; // restore interrupt flag status - - monitorState = 2; - break; - - case 2: - mainProgramVariables[(uint16_t)(mpDebugAccMainLoopIdx)] = mainProgramVariables[(uint16_t)(mpMainLoopAccumulatorIdx)]; - mainProgramVariables[(uint16_t)(mpDebugAccIdleIdx)] = mainProgramVariables[(uint16_t)(mpIdleAccumulatorIdx)]; - mainProgramVariables[(uint16_t)(mpDebugAccIdleProcessIdx)] = idleProcessTimerLength; - mainProgramVariables[(uint16_t)(mpDebugAccDisplayIdx)] = displayTimerLength; - mainProgramVariables[(uint16_t)(mpDebugAccSWEET64idx)] = SWEET64timerLength; - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operations atomic - - mainProgramVariables[(uint16_t)(mpDebugAccInterruptIdx)] = volatileVariables[(uint16_t)(vInterruptAccumulatorIdx)]; - - SREG = oldSREG; // restore interrupt flag status - - monitorState = 0; - break; - - default: - monitorState = 0; - break; - - } - -#endif // useDebugCPUreading -#endif // useCPUreading - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operations atomic - - i = rawTripIdx; // save old trip variable index - rawTripIdx ^= (raw0tripIdx ^ raw1tripIdx); // set new raw trip variable index - -#ifdef trackIdleEOCdata - j = rawEOCidleTripIdx; // save old EOC/idle trip variable index - rawEOCidleTripIdx ^= (raw0eocIdleTripIdx ^ raw1eocIdleTripIdx); // set new raw EOC/idle trip variable index - -#endif // trackIdleEOCdata - SREG = oldSREG; // restore interrupt flag status - - for (uint8_t x = 0; x < tUScount; x++) - { - - k = translateTripIndex(tripUpdateSrcList, x) & 0x7F; - m = translateTripIndex(tripUpdateDestList, x); - - if (m) - { - - if (m & 0x80) tripVar::transfer(k, m & 0x7F); - else tripVar::update(k, m); - - } - - } - - tripVar::reset(i); // reset old raw trip variable -#ifdef trackIdleEOCdata - tripVar::reset(j); // reset old EOC/idle raw trip variable -#endif // trackIdleEOCdata - - if (awakeFlags & aAwakeOnVehicle) - { - -#ifdef useWindowTripFilter - if (EEPROM::readVal(pWindowTripFilterIdx)) - { - - wtpCurrentIdx++; - if (wtpCurrentIdx == windowTripFilterIdx + windowTripFilterSize) wtpCurrentIdx = windowTripFilterIdx; - - } - -#endif // useWindowTripFilter - } - - } - -#if defined(useAnalogRead) -#ifdef useChryslerMAPCorrection - if (analogStatus & asReadMAPchannel) - { - - peripheral::changeBitFlags(analogStatus, asReadMAPchannel, 0); // acknowledge ADC read completion - - SWEET64::runPrgm(prgmCalculateMAPpressure, 0); - - } - -#endif // useChryslerMAPCorrection -#ifdef useChryslerBaroSensor - if (analogStatus & asReadBaroChannel) - { - - peripheral::changeBitFlags(analogStatus, asReadBaroChannel, 0); // acknowledge ADC read completion - - SWEET64::runPrgm(prgmCalculateBaroPressure, 0); - - } - -#endif // useChryslerBaroSensor -#ifdef useAnalogButtons - if (analogStatus & asReadButtonChannel) - { - - peripheral::changeBitFlags(analogStatus, asReadButtonChannel, 0); // acknowledge ADC read completion - - for (uint8_t x = analogButtonCount - 1; x < analogButtonCount; x--) - { - - if (analogValue[(unsigned int)(analogButtonChannelIdx)] >= pgm_read_word(&analogButtonThreshold[(unsigned int)(x)])) - { - -#ifdef useTestAnalogButtonIdx - thisButtonIdx = x; -#endif // useTestAnalogButtonIdx - peripheral::injectButton(pgm_read_byte(&analogTranslate[(unsigned int)(x)])); - break; - - } - - } - - } - -#endif // useAnalogButtons -#endif // useAnalogRead -#ifdef useDragRaceFunction - if (timer0Status & t0sAccelTestFlag) - { - - peripheral::changeBitFlags(timer0Status, t0sAccelTestFlag, 0); // acknowledge sample command - - oldSREG = SREG; // save interrupt flag status - cli(); // disable interrupts to make the next operations atomic - - accelTestStatus = lastAccelTestStatus; // copy last loop's accel test flag status to this loop - lastAccelTestStatus = accelerationFlags; // copy current accel test flag status for next loop - - SREG = oldSREG; // restore interrupt flag status - - accelTestStatus = (lastAccelTestStatus ^ accelTestStatus) & accelTestClearFlags; // detect any drag race flag changes - - if (accelTestStatus) - { - - accelTestState = accelerationFlags & accelTestClearFlags; - - switch (accelTestState) - { - - case (accelTestTriggered | accelTestFullSpeed | accelTestHalfSpeed | accelTestDistance): - accelTestState = 1; - break; - - case (accelTestActive | accelTestFullSpeed | accelTestHalfSpeed | accelTestDistance): - accelTestState = 2; - break; - - case (accelTestFinished): - if (SWEET64::runPrgm(prgmAccelTestCompareFullSpeeds, 0)) - { - - tripVar::transfer(dragRawHalfSpeedIdx, dragHalfSpeedIdx); - tripVar::transfer(dragRawFullSpeedIdx, dragFullSpeedIdx); - tripVar::transfer(dragRawDistanceIdx, dragDistanceIdx); - - } - - accelTestState = 3; - break; - - case (accelTestFinished | accelTestCancelled): - accelTestState = 4; - break; - - case (accelTestActive | accelTestFullSpeed | accelTestHalfSpeed): - accelTestState = 5; - break; - - case (accelTestActive | accelTestFullSpeed | accelTestDistance): - accelTestState = 6; - break; - - case (accelTestActive | accelTestFullSpeed): - accelTestState = 7; - break; - - case (accelTestActive | accelTestHalfSpeed | accelTestDistance): - accelTestState = 8; - break; - - case (accelTestActive | accelTestHalfSpeed): - accelTestState = 9; - break; - - case (accelTestActive | accelTestDistance): - accelTestState = 10; - break; - - case (accelTestActive): - accelTestState = 11; - break; - - default: - accelTestState = 12; - break; - - } - - } - else - { - - accelTestState = 0; - - if (accelerationFlags & accelTestFinished) - { - - if (EEPROM::readVal(pDragAutoFlagIdx)) - { - - if (accelerationTest::triggerTest() == 0) accelTestState = 1; - - } - - } - - } - - } - -#endif // useDragRaceFunction -#ifdef useSimulatedFIandVSS - if (timer1Status & t1sDebugUpdateFIP) // if debug fuel injector pulse period needs adjustment - { - - peripheral::changeBitFlags(timer1Status, t1sDebugUpdateFIP, 0); // acknowledge debug update request - - debugFIPidx++; - if (debugFIPidx >= debugFIPlength) - { - - debugFIPidx = 0; - debugFIPstate++; - debugFIPstate &= 3; - - } - - switch (debugFIPstate) - { - - case 0: - debugFIPtickLength = pgm_read_word(&debugFIPvalues[(unsigned int)(debugFIPidx)]); - debugFIPWreadTickLength = pgm_read_word(&debugFIPWvalues[(unsigned int)(debugFIPidx)]); - debugFIPWgoodTickLength = debugFIPtickLength - 63; - peripheral::changeBitFlags(debugFlags, 0, debugFIPready); - break; - - case 1: - break; - - case 2: - debugFIPtickLength = pgm_read_word(&debugFIPvalues[(unsigned int)(debugFIPlength - debugFIPidx - 1)]); - debugFIPWreadTickLength = pgm_read_word(&debugFIPWvalues[(unsigned int)(debugFIPlength - debugFIPidx - 1)]); - debugFIPWgoodTickLength = debugFIPtickLength - 63; - peripheral::changeBitFlags(debugFlags, 0, debugFIPready); - break; - - case 3: - break; - - default: - break; - - } - - if (debugFIPWreadTickLength > debugFIPWgoodTickLength) debugFIPWreadTickLength = debugFIPWgoodTickLength; - else debugFIPWtickLength = debugFIPWreadTickLength; - - } - - if (timer1Status & t1sDebugUpdateVSS) // if VSS pulse period needs adjustment - { - - peripheral::changeBitFlags(timer1Status, t1sDebugUpdateVSS, 0); // acknowledge debug update request - - debugVSSidx++; - if (debugVSSidx >= debugVSSlength) - { - - debugVSSidx = 0; - debugVSSstate++; - debugVSSstate &= 3; - - } - - switch (debugVSSstate) - { - - case 0: - debugVSStickLength = pgm_read_word(&debugVSSvalues[(unsigned int)(debugVSSidx)]); - peripheral::changeBitFlags(debugFlags, 0, debugVSSready); - break; - - case 1: - break; - - case 2: - debugVSStickLength = pgm_read_word(&debugVSSvalues[(unsigned int)(debugVSSlength - debugVSSidx - 1)]); - peripheral::changeBitFlags(debugFlags, 0, debugVSSready); - break; - - case 3: - break; - - default: - break; - - } - - } - -#endif // useSimulatedFIandVSS -#ifdef useDebugCPUreading - idleProcessTimerLength += systemInfo::findCycleLength(idleStart, systemInfo::cycles0()); - -#endif // useDebugCPUreading -} - -static void performSleepMode(uint8_t sleepMode) -{ - - set_sleep_mode(sleepMode); // set for specified sleep mode - sleep_enable(); // enable sleep mode - sleep_mode(); // go sleep for a bit - sleep_disable(); // disable sleep mode - -} - -// primary MPGuino processing routine - overwrites Arduino sketch main if compiled in Arduino IDE - -int main(void) -{ - - uint8_t i; - uint8_t j; -#ifdef useDebugCPUreading - uint32_t displayStart; -#endif // useDebugCPUreading - - const buttonVariable * bpPtr; - - cli(); // disable interrupts while interrupts are being fiddled with - - // timer0 is the taskmaster driving MPGuino's measurement functionality -#if defined(__AVR_ATmega32U4__) - // turn on timer0 module - PRR0 &= ~(1 << PRTIM0); - - // set timer 0 to fast PWM mode, TOP = 0xFF - TCCR0A |= ((1 << WGM01) | (1 << WGM00)); - TCCR0B &= ~(1 << WGM02); - - // set timer 0 prescale factor to 64 - TCCR0B &= ~(1 << CS02); - TCCR0B |= ((1 << CS01) | (1 << CS00)); - - // set OC0A to disabled - TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); - - // set OC0B to disabled - TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); - - // clear timer 0 output compare force bits for OC0A and OC0B - TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); - - // disable timer 0 output compare interrupts - TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); - - // enable timer 0 overflow interrupt to generate ~1 ms tick - TIMSK0 |= (1 << TOIE0); - - // clear timer 0 interrupt flags - TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); - - // disable digital inputs for all ADC capable pins to reduce power consumption - DIDR0 |= ((ADC7D) | (1 << ADC6D) | (1 << ADC5D) | (1 << ADC4D) | (1 << ADC1D) | (1 << ADC0D)); - DIDR1 |= (1 << AIN0D); - DIDR2 |= ((1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D) | (1 << ADC10D) | (1 << ADC9D) | (1 << ADC8D)); - - // shut off on-board peripherals to reduce power consumption - PRR0 |= ((1 << PRTWI) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRADC)); - PRR1 |= ((1 << PRUSB) | (1 << PRTIM4) | (1 << PRTIM3) | (1 << PRUSART1)); - -#endif // defined(__AVR_ATmega32U4__) -#if defined(__AVR_ATmega2560__) - // turn on timer0 module - PRR0 &= ~(1 << PRTIM0); - - // set timer 0 to fast PWM mode, TOP = 0xFF - TCCR0A |= ((1 << WGM01) | (1 << WGM00)); - TCCR0B &= ~(1 << WGM02); - - // set timer 0 prescale factor to 64 - TCCR0B &= ~(1 << CS02); - TCCR0B |= ((1 << CS01) | (1 << CS00)); - - // set OC0A to disabled - TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); - - // set OC0B to disabled - TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); - - // clear timer 0 output compare force bits for OC0A and OC0B - TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); - - // disable timer 0 output compare interrupts - TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); - - // enable timer 0 overflow interrupt to generate ~1 ms tick - TIMSK0 |= (1 << TOIE0); - - // clear timer 0 interrupt flags - TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); - - // disable digital inputs for all ADC capable pins to reduce power consumption - DIDR0 |= ((1 << ADC7D) | (1 << ADC6D) | (1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D)); - DIDR1 |= ((1 << AIN1D) | (1 << AIN0D)); - DIDR2 |= ((1 << ADC15D) | (1 << ADC14D) | (1 << ADC13D) | (1 << ADC12D) | (1 << ADC11D) | (1 << ADC10D) | (1 << ADC9D) | (1 << ADC8D)); - - // shut off on-board peripherals to reduce power consumption - PRR0 |= ((1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRUSART0) | (1 << PRADC)); - PRR1 |= ((1 << PRTIM5) | (1 << PRTIM4) | (1 << PRTIM3) | (1 << PRUSART3) | (1 << PRUSART2) | (1 << PRUSART1)); - -#endif // defined(__AVR_ATmega2560__) -#if defined(__AVR_ATmega328P__) - // turn on timer0 module - PRR &= ~(1 << PRTIM0); - - // set timer 0 to fast PWM mode, TOP = 0xFF - TCCR0A |= ((1 << WGM01) | (1 << WGM00)); - TCCR0B &= ~(1 << WGM02); - - // set timer 0 prescale factor to 64 - TCCR0B &= ~(1 << CS02); - TCCR0B |= ((1 << CS01) | (1 << CS00)); - - // set OC0A to disabled - TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); - - // set OC0B to disabled - TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); - - // clear timer 0 output compare force bits for OC0A and OC0B - TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B)); - - // disable timer 0 output compare interrupts - TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A)); - - // enable timer 0 overflow interrupt to generate ~1 ms tick - TIMSK0 |= (1 << TOIE0); - - // clear timer 0 interrupt flags - TIFR0 |= ((1 << OCF0B) | (1 << OCF0A) | (1 << TOV0)); - - // disable digital inputs for all ADC capable pins to reduce power consumption - DIDR0 |= ((1 << ADC5D) | (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D)); - DIDR1 |= ((1 << AIN1D) | (1 << AIN0D)); - - // shut off on-board peripherals to reduce power consumption - PRR |= ((1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRUSART0) | (1 << PRADC)); - -#endif // defined(__AVR_ATmega328P__) - ACSR &= ~(1 << ACIE); // disable analog comparator interrupt - ACSR |= (1 << ACD); // disable analog comparator module - ADCSRB &= ~(1 << ACME); // disable analog comparator multiplexer - - timer0Command = t0cResetTimer; -#ifdef useTimer1Interrupt - timer1Command = t1cResetTimer; -#endif // useTimer1Interrupt - -#ifdef useSimulatedFIandVSS - debugFlags = (debugVSSflag | debugInjectorFlag); - debugReading::configurePorts(); - -#endif // useSimulatedFIandVSS - rawTripIdx = raw0tripIdx; -#ifdef trackIdleEOCdata - rawEOCidleTripIdx = raw0eocIdleTripIdx; -#endif // trackIdleEOCdata - - for (uint8_t x = 0; x < tripSlotCount; x++) tripVar::reset(x); - -#ifdef useDragRaceFunction - accelerationFlags &= ~accelTestClearFlags; - lastAccelTestStatus = accelerationFlags; - accelTestStatus = accelerationFlags; +#endif // useSimulatedFIandVSS +#ifdef useDragRaceFunction + accelerationFlags &= ~accelTestClearFlags; + lastAccelTestStatus = accelerationFlags; + accelTestStatus = accelerationFlags; #endif // useDragRaceFunction menuLevel = 255; topScreenLevel = 0; - j = EEPROM::powerUpCheck(); - timer0DelayCount = delay1500msTick; // request a set number of timer tick delays equivalent to 1.5 seconds timer0Command |= (t0cDoDelay); // signal request to timer -#ifdef useWindowTripFilter - windowTripFilterReset(); - -#endif // useWindowTripFilter sei(); - peripheral::initMain(); // initialize all human interface peripherals + initHardware(); // initialize all human interface peripherals #ifdef useSavedTrips i = tripSupport::doAutoAction(1); @@ -3691,7 +1800,7 @@ int main(void) terminalState = 0; #endif // outputDebugTerminalSplash - while (timer0Command & t0cDoDelay) idleProcess(); // show splash screen for 1.5 seconds + delay0(0); // show splash screen for 1.5 seconds #ifdef useTestButtonValues cursor::moveAbsolute(buttonViewIdx, 0); @@ -3733,7 +1842,7 @@ int main(void) if (activityChangeFlags & afActivityTimeoutFlag) { - peripheral::changeBitFlags(activityChangeFlags, afActivityTimeoutFlag, 0); // clear activity change activity timeout flag + changeBitFlags(activityChangeFlags, afActivityTimeoutFlag, 0); // clear activity change activity timeout flag if (activityFlags & afActivityTimeoutFlag) // if MPGuino is commanded to go asleep { @@ -3765,7 +1874,7 @@ int main(void) if (activityChangeFlags & afEngineOffFlag) { - peripheral::changeBitFlags(activityChangeFlags, afEngineOffFlag, 0); // clear activity change engine off flag + changeBitFlags(activityChangeFlags, afEngineOffFlag, 0); // clear activity change engine off flag if (((activityFlags & afEngineOffFlag) == 0) && (EEPROM::readVal(pWakeupResetCurrentOnEngineIdx))) tripSupport::resetCurrent(); // if engine start is detected @@ -3774,7 +1883,7 @@ int main(void) if (activityChangeFlags & afVehicleStoppedFlag) { - peripheral::changeBitFlags(activityChangeFlags, afVehicleStoppedFlag, 0); // clear activity change vehicle stopped flag + changeBitFlags(activityChangeFlags, afVehicleStoppedFlag, 0); // clear activity change vehicle stopped flag if (((activityFlags & afVehicleStoppedFlag) == 0) && (EEPROM::readVal(pWakeupResetCurrentOnMoveIdx))) tripSupport::resetCurrent(); // if vehicle movement is detected @@ -3784,13 +1893,13 @@ int main(void) if (activityChangeFlags & afParkFlag) { - peripheral::changeBitFlags(activityChangeFlags, afParkFlag, 0); // clear activity change park flag + changeBitFlags(activityChangeFlags, afParkFlag, 0); // clear activity change park flag if (activityFlags & afParkFlag) // if MPGuino is commanded to go park { #ifdef useWindowTripFilter - windowTripFilterReset(); // reset the window trip filter + tripSupport::resetWindowFilter(); // reset the window trip filter #endif // useWindowTripFilter #ifdef useSavedTrips @@ -3810,7 +1919,7 @@ int main(void) { j = buttonPress; // capture button state - peripheral::changeBitFlags(timer0Status, t0sReadButton, 0); // acknowledge sample command + changeBitFlags(timer0Status, t0sReadButton, 0); // acknowledge sample command bpPtr = (const buttonVariable *)(pgm_read_word(&(screenParameters[(unsigned int)(menuLevel)].modeButtonList))); @@ -3834,7 +1943,7 @@ int main(void) if (timer0Status & t0sOutputLogging) { - peripheral::changeBitFlags(timer0Status, t0sOutputLogging, 0); // acknowledge output serial command + changeBitFlags(timer0Status, t0sOutputLogging, 0); // acknowledge output serial command #ifdef useDataLoggingOutput if (EEPROM::readVal(pSerialDataLoggingIdx)) doOutputDataLog(); @@ -3852,13 +1961,13 @@ int main(void) if (timer0Status & t0sUpdateDisplay) { - peripheral::changeBitFlags(timer0Status, t0sUpdateDisplay, 0); // acknowledge update display command + changeBitFlags(timer0Status, t0sUpdateDisplay, 0); // acknowledge update display command -#ifdef useExpansionPins - peripheral::outputExpansionPin1(0); - peripheral::outputExpansionPin2(1); +#if defined(useOutputPins) + outputPin::setOutputPin1(0); + outputPin::setOutputPin2(1); -#endif // useExpansionPins +#endif // defined(useOutputPins) #ifdef useBarFuelEconVsSpeed FEvSpdTripIdx = (uint8_t)(SWEET64::runPrgm(prgmFEvsSpeed, instantIdx)); diff --git a/mpguino_tav/parameters.h b/mpguino_tav/parameters.h index 21edc3e..0208699 100644 --- a/mpguino_tav/parameters.h +++ b/mpguino_tav/parameters.h @@ -36,10 +36,10 @@ const uint8_t pSizeAlternateFE = 1; #ifdef useFuelCost const uint8_t pSizeFuelUnitCost = 24; #endif // useFuelCost -#ifdef useExpansionPins -const uint8_t pSizeExpansionPin1Mode = 3; -const uint8_t pSizeExpansionPin2Mode = 3; -#endif // useExpansionPins +#if defined(useOutputPins) +const uint8_t pSizeOutputPin1Mode = 3; +const uint8_t pSizeOutputPin2Mode = 3; +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput const uint8_t pSizeVoltageOffset = 12; #endif // useCarVoltageOutput @@ -198,11 +198,11 @@ const unsigned int pAddressAlternateFE = pAddressMetricMode + byteSize(pSizeM const unsigned int pAddressFuelUnitCost = nextAllowedValue; #define nextAllowedValue pAddressFuelUnitCost + byteSize(pSizeFuelUnitCost) #endif // useFuelCost -#ifdef useExpansionPins -const uint8_t pAddressExpansionPin1Mode = nextAllowedValue; -const uint8_t pAddressExpansionPin2Mode = pAddressExpansionPin1Mode + byteSize(pSizeExpansionPin1Mode); -#define nextAllowedValue pAddressExpansionPin2Mode + byteSize(pSizeExpansionPin2Mode) -#endif // useExpansionPins +#if defined(useOutputPins) +const uint8_t pAddressOutputPin1Mode = nextAllowedValue; +const uint8_t pAddressOutputPin2Mode = pAddressOutputPin1Mode + byteSize(pSizeOutputPin1Mode); +#define nextAllowedValue pAddressOutputPin2Mode + byteSize(pSizeOutputPin2Mode) +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput const unsigned int pAddressVoltageOffset = nextAllowedValue; #define nextAllowedValue pAddressVoltageOffset + byteSize(pSizeVoltageOffset) @@ -399,11 +399,11 @@ const uint8_t pAlternateFEidx = pMetricModeIdx + 1; const uint8_t pCostPerQuantity = nextAllowedValue; #define nextAllowedValue pCostPerQuantity + 1 #endif // useFuelCost -#ifdef useExpansionPins -const uint8_t pExpansionPin1Mode = nextAllowedValue; -const uint8_t pExpansionPin2Mode = pExpansionPin1Mode + 1; -#define nextAllowedValue pExpansionPin2Mode + 1 -#endif // useExpansionPins +#if defined(useOutputPins) +const uint8_t pOutputPin1Mode = nextAllowedValue; +const uint8_t pOutputPin2Mode = pOutputPin1Mode + 1; +#define nextAllowedValue pOutputPin2Mode + 1 +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput const uint8_t pVoltageOffset = nextAllowedValue; #define nextAllowedValue pVoltageOffset + 1 @@ -640,10 +640,10 @@ const char parmLabels[] PROGMEM = { "Price*1000/" "\xEB" "USgal" "\xEC" "\xED" "\r" #endif // useImperialGallon #endif // useFuelCost -#ifdef useExpansionPins +#if defined(useOutputPins) "OutPtPin 1 Mode\r" "OutPtPin 2 Mode\r" -#endif // useExpansionPins +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput "V(diode)*1000\r" #endif // useCarVoltageOutput @@ -818,10 +818,10 @@ const uint8_t paramsLength[] PROGMEM = { #ifdef useFuelCost ,(pSizeFuelUnitCost & 0x07) // Price per unit volume of fuel #endif // useFuelCost -#ifdef useExpansionPins - ,(pSizeExpansionPin1Mode & 0x07) // Output Pin 1 mode - ,(pSizeExpansionPin2Mode & 0x07) // Output Pin 2 mode -#endif // useExpansionPins +#if defined(useOutputPins) + ,(pSizeOutputPin1Mode & 0x07) // Output Pin 1 mode + ,(pSizeOutputPin2Mode & 0x07) // Output Pin 2 mode +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput ,(pSizeVoltageOffset & 0x07) // diode offset from V(alternator) #endif // useCarVoltageOutput @@ -976,10 +976,10 @@ const uint8_t paramAddrs[] PROGMEM = { #ifdef useFuelCost ,(uint8_t)(pAddressFuelUnitCost) // Price per unit volume of fuel #endif // useFuelCost -#ifdef useExpansionPins - ,(uint8_t)(pAddressExpansionPin1Mode) // Output Pin 1 mode - ,(uint8_t)(pAddressExpansionPin2Mode) // Output Pin 2 mode -#endif // useExpansionPins +#if defined(useOutputPins) + ,(uint8_t)(pAddressOutputPin1Mode) // Output Pin 1 mode + ,(uint8_t)(pAddressOutputPin2Mode) // Output Pin 2 mode +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput ,(uint8_t)(pAddressVoltageOffset) // diode offset from V(alternator) #endif // useCarVoltageOutput @@ -1135,10 +1135,10 @@ const uint32_t params[] PROGMEM = { #ifdef useFuelCost ,2710259 // Price per unit volume of fuel (this prices is for a liter of diesel at 717 HUF / liter) #endif // useFuelCost -#ifdef useExpansionPins +#if defined(useOutputPins) ,0 // Output pin 1 mode ,0 // Output pin 2 mode -#endif // useExpansionPins +#endif // defined(useOutputPins) #ifdef useCarVoltageOutput ,700 // diode offset from V(alternator) (via meelis11) #endif // useCarVoltageOutput diff --git a/mpguino_tav/parameters.ino b/mpguino_tav/parameters.ino index ec099d5..e624091 100644 --- a/mpguino_tav/parameters.ino +++ b/mpguino_tav/parameters.ino @@ -364,7 +364,7 @@ static void EEPROM::initGuinoSoftware(void) #endif // useBarFuelEconVsSpeed #ifdef useWindowTripFilter - windowTripFilterReset(); + tripSupport::resetWindowFilter(); #endif // useWindowTripFilter } diff --git a/mpguino_tav/sweet64.h b/mpguino_tav/sweet64.h index bd92417..7bdcc8d 100644 --- a/mpguino_tav/sweet64.h +++ b/mpguino_tav/sweet64.h @@ -1,6 +1,3 @@ -#ifdef useIsqrt -static unsigned int iSqrt(unsigned int n); -#endif // useIsqrt /* SWEET64 is a low-level pseudocode interpreter, meant to save a lot of space in program memory for 64-bit calculations @@ -13,6 +10,14 @@ static unsigned int iSqrt(unsigned int n); */ +#ifdef useIsqrt +static unsigned int iSqrt(unsigned int n); +#endif // useIsqrt +static unsigned long str2ull(char * strBuffer); +static void storeDigit(uint8_t value, char * strBuffer, uint8_t &strPos, uint8_t &decPos, char &zeroChar, uint8_t &digCnt, uint8_t flg); +static char * ull2str(char * strBuffer, uint8_t decimalPlaces, uint8_t prgmIdx); +static char * ull2str(char * strBuffer, uint8_t decimalPlaces, uint8_t windowLength, uint8_t decimalFlag); + namespace SWEET64 /* 64-bit pseudo-processor section prototype */ { @@ -814,8 +819,7 @@ const uint8_t idxMicroSecondsPerSecond = idxTicksPerSecond + 1; const uint8_t idxDecimalPoint = idxMicroSecondsPerSecond + 1; const uint8_t idxMetricFE = idxDecimalPoint + 1; const uint8_t idxSecondsPerHour = idxMetricFE + 1; -const uint8_t idxNumber500 = idxSecondsPerHour + 1; -const uint8_t idxBCDdivisor = idxNumber500 + 1; +const uint8_t idxBCDdivisor = idxSecondsPerHour + 1; #define nextAllowedValue idxBCDdivisor + 1 #ifdef useIsqrt const uint8_t idxNumerPressure = nextAllowedValue; @@ -879,7 +883,6 @@ static const char terminalConstIdxNames[] PROGMEM = { "idxDecimalPoint\r" "idxMetricFE\r" "idxSecondsPerHour\r" - "idxNumber500\r" "idxBCDdivisor\r" #ifdef useIsqrt "idxNumerPressure\r" @@ -973,7 +976,6 @@ const uint32_t convNumbers[] PROGMEM = { ,1000ul // idxDecimalPoint - decimal point format (the basis for all of those '* 1000' parameters) ,100000ul // idxMetricFE - decimal point format * 100 for metric FE (L / 100km) ,3600ul // idxSecondsPerHour - seconds per hour - ,500ul // idxNumber500 - round to nearest whole number, for numeric formatting ,100000000ul // idxBCDdivisor - divisor to separate lower 4 BCD bytes from 5th byte #ifdef useIsqrt ,68947573ul // idxNumerPressure - numerator to convert psig to kPa @@ -1039,3 +1041,10 @@ const uint8_t s64BCDformatList[] PROGMEM = { ,0x00 // total entry length == 0 for end of list }; + +const char overFlowStr[] PROGMEM = "----------"; +const char overFlow9Str[] PROGMEM = "9999999999"; + +const uint8_t dfIgnoreDecimalPoint = 0b00000001; +const uint8_t dfOverflow9s = 0b10000000; + diff --git a/mpguino_tav/sweet64.ino b/mpguino_tav/sweet64.ino index c6f42cf..680b163 100644 --- a/mpguino_tav/sweet64.ino +++ b/mpguino_tav/sweet64.ino @@ -1864,3 +1864,263 @@ static unsigned int iSqrt(unsigned int n) } #endif // useIsqrt +static const uint8_t prgmMultiplyBy100[] PROGMEM = { + instrMul2byByte, 100, // multiply result by 100 + instrAddIndexToX, 0x02 , // add whatever's in the trip variable index to result + instrDone // exit to caller +}; + +static const uint8_t prgmMultiplyBy10[] PROGMEM = { + instrMul2byByte, 10, // multiply result by 10 + instrAddIndexToX, 0x02 , // add whatever's in the trip variable index to result + instrDone // exit to caller +}; + +static unsigned long str2ull(char * strBuffer) +{ + + uint8_t c; + uint8_t n; + + uint8_t x; + uint8_t f; + uint8_t loopFlag; + + x = 0; + n = 0; + f = 1; + loopFlag = 1; + + SWEET64::init64byt((union union_64 *)(&s64reg[s64reg2]), 0); // initialize 64-bit number to zero + + while ((loopFlag) && (x < 17)) + { + + if ((c = strBuffer[(unsigned int)(x++)])) // if a non-NULL character is read in + { + + n *= 10; // shift accumulator left one digit + if (c != ' ') n += (uint8_t)(c) - 48; // if character is not a leading space, go add it to accumulator + f= 1 - f; // flip-flop the SWEET64 addition flag + + if (f) + { + + SWEET64::runPrgm(prgmMultiplyBy100, n); // call SWEET64 routine to perform (accumulated 64-bit number) * 100 + n + n = 0; + + } + + } + else loopFlag = 0; // otherwise, terminate loop upon receipt of a NULL character + + } + + if (f == 0) SWEET64::runPrgm(prgmMultiplyBy10, n); // call SWEET64 routine to perform (accumulated 64-bit number) * 10 + n + + return ((union union_64 *)(&s64reg[s64reg2]))->ul[0]; + +} + +static void storeDigit(uint8_t value, char * strBuffer, uint8_t &strPos, uint8_t &decPos, char &zeroChar, uint8_t &digCnt, uint8_t flg) +{ + + decPos--; // bump down decimal position + + if ((value) || (decPos == 1)) // if either this digit is not zero, or at 1s position + { + + value += '0'; // shift value into character 0-9 range + zeroChar = '0'; // turn leading zero character into a 0 + + } + else value = zeroChar; // otherwise, use previously defined leading zero character + + if (value != ' ') digCnt++; + + if ((decPos == 0) && (flg)) strBuffer[(uint16_t)(strPos++)] = '.'; // if at 1/10ths position, store a decimal point + strBuffer[(uint16_t)(strPos++)] = value; // store converted character value + +} + +// converts the 64-digit number stored in SWEET64 register 2 into an up-to 10-digit decimal number string +// a SWEET64 indexed program is called to do the initial processing of the number from 64-bit to an initial BCD string +// the SWEET64 program must specify the leading zero character and the number of BCD bytes +// +// the returned string will always have at least one digit at the rightmost string position +// the string is terminated with a NULL character +// +// this routine can handle numbers up to 9999999999 +// +// if called with prgmIdx = tRoundOffNumber, also inserts the decimal point in the string specified by the value in decimalPlaces +// +static char * ull2str(char * strBuffer, uint8_t decimalPlaces, uint8_t prgmIdx) +{ + + union union_64 * tmpPtr2 = (union union_64 *)(&s64reg[s64reg2]); + + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t l; + uint8_t n; + uint8_t y; + char z; + + SWEET64::doCalculate(decimalPlaces, prgmIdx); // call SWEET64 routine to perform decimal point rounding to next nearest decimal place + + l = tmpPtr2->u8[6]; // load total length of binary-coded decimal bytes of converted number + + if (l == 255) strcpy_P(strBuffer, overFlowStr); // if length is 255, this number overflowed + else + { + + if (prgmIdx == tRoundOffNumber) c = 1; // if using tRoundOffNumber to process number, do decimal conversion + else c = 0; + + if (c) d = 11 - decimalPlaces; // if using tRoundOffNumber, compute decimal position + else d = 11; + + z = (char)(tmpPtr2->u8[7]); // load leading zero character + y = 0; // set initial string buffer position + n = 0; // set initial digit count + + for (uint8_t x = 0; x < l; x++) // go through all of the binary-coded decimal bytes of converted number + { + + b = tmpPtr2->u8[(uint16_t)(x)]; // load a binary-coded decimal byte of number + + storeDigit(b / 10, strBuffer, y, d, z, n, c); // store 10's place digit in string buffer + storeDigit(b % 10, strBuffer, y, d, z, n, c); // store 1's place digit in string buffer + + } + + strBuffer[(unsigned int)(y++)] = 0; // mark end of string buffer with a NULL character + strBuffer[(unsigned int)(y++)] = n; // store digit count at 1 past the string buffer end + + } + + return strBuffer; // return pointer to string buffer containing the number + +} + +// converts the 64-digit number stored in SWEET64 register 2 into an up-to 10-digit decimal number string +// ull2str( ..tRoundOffNumber) is called to perform initial conversion into a 10 character long string containing +// the up-to 10 digit number with inserted decimal point as appropriate, and leading spaces +// +// if no window length is specified, this routine just removes all leading spaces +// +// decimalFlag currently has two bits defined: +// 1xxx xxxx - fill overflow string from all 9s instead of all '-' characters +// xxxx xxx1 - ignore decimal point character in window length consideration +// +// sample debug monitor outputs: +// +// ]0<6.2u (overflow='-', do not ignore decimal point) ]81<6.2u (overflow='9', ignore decimal point) +// 00: 0.01 - 00: 0.01 - +// 01: 0.06 - 01: 0.06 - +// 02: 0.56 - 02: 0.56 - +// 03: 5.56 - 03: 5.56 - +// 04: 55.56 - 04: 55.56 - +// 05: 555.56 - 05: 555.56 - +// 06: 5555.5 - 06: 5555.56 - +// 07: 55555 - 07: 55555.5 - +// 08: 555555 - 08: 555555 - +// 09: ------ - 09: 999999 - +// 0A: ------ - 0A: 999999 - +// +static char * ull2str(char * strBuffer, uint8_t decimalPlaces, uint8_t windowLength, uint8_t decimalFlag) // format number for output +{ + + uint8_t d; + uint8_t e; + uint8_t f; + + ull2str(strBuffer, decimalPlaces, tRoundOffNumber); // perform rounding of number to nearest decimal place, then format for ASCII output and insert a decimal point + + if ((windowLength > 10) || (windowLength < 2)) windowLength = 0; // validity check for window length + + if (strBuffer[2] == '-') f = 1; // if number overflowed + else + { + + f = 0; // initially signal no overflow occurred + + if (windowLength) // if there is a valid windowLength + { + + e = strBuffer[12] - decimalPlaces; // get whole digit count + d = 9 - decimalPlaces; // compute position of decimal 1s position + + if (windowLength == e) // if window length == whole digit count + { + + strBuffer[(uint16_t)(++d)] = 0; // replace the decimal point with a null + d -= windowLength; // set up for left adjust string copy + + } + else if (windowLength < e) // if window length < whole digit count + { + + f = 1; // signal that number overflowed + d = 0; // signal 'do not perform string copy' + + } + else // window length > whole digit count + { + + d -= (e - 1); // point to largest whole digit stored + + // adjust window length if instructed to ignore the decimal point for length consideration + f = windowLength; + if ((decimalFlag & dfIgnoreDecimalPoint) && (decimalPlaces)) f++; + + // find the string end position minus adjusted window length + e = ((decimalPlaces) ? 11 : 10) - f; + + // if string end position minus window length is less than the position for the largest whole digit, use it instead + if (e < d) d = e; + + // catch the special case where the string has decimal point but no decimals + if (strBuffer[(uint16_t)(d + f - 1)] == '.') d--; + + strBuffer[(uint16_t)(d + f)] = 0; // mark end of string + + f = 0; + + } + + } + else // no windowLength specified, just eliminate leading spaces + { + + d = 0; + + while (strBuffer[(uint16_t)(d)] == ' ' && (d < 11)) d++; // find position of first non-blank character + + } + + if (d) // move string buffer left to remove extra spaces, and to move number into window if required + { + + e = 0; + + while (d < 12) strBuffer[(uint16_t)(e++)] = strBuffer[(uint16_t)(d++)]; + + } + + } + + if (f) // if an overflow occurred + { + + strcpy_P(strBuffer, ((decimalFlag & dfOverflow9s) ? overFlow9Str : overFlowStr)); // copy overflow string into buffer + + if (windowLength) strBuffer[(unsigned int)(windowLength)] = 0; // mark new end of string buffer + + } + + return strBuffer; + +} + diff --git a/mpguino_tav/trip_measurement.h b/mpguino_tav/trip_measurement.h index 2c9d547..916f0eb 100644 --- a/mpguino_tav/trip_measurement.h +++ b/mpguino_tav/trip_measurement.h @@ -1,8 +1,3 @@ -#ifdef useWindowTripFilter -void windowTripFilterReset(void); -#endif // useWindowTripFilter -static uint8_t translateTripIndex(const uint8_t tripTranslateList[], uint8_t tripListPos); - namespace tripVar /* trip data collection basic function prototype */ { @@ -21,6 +16,9 @@ namespace tripVar /* trip data collection basic function prototype */ namespace tripSupport /* Trip save/restore/reset support section prototype */ { + static void init(void); + static void idleProcess(void); + static uint8_t translateTripIndex(const uint8_t tripTranslateList[], uint8_t tripListPos); #ifdef useSavedTrips static uint8_t displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged); static void goSaveCurrent(void); @@ -34,6 +32,9 @@ namespace tripSupport /* Trip save/restore/reset support section prototype */ static void doResetTrip(uint8_t tripSlot); static void resetCurrent(void); static void resetTank(void); +#ifdef useWindowTripFilter + static void resetWindowFilter(void); +#endif // useWindowTripFilter }; @@ -45,6 +46,10 @@ namespace pressureCorrect /* Chrysler returnless fuel pressure correction displa } +const char pressureCorrectScreenFuncNames[] PROGMEM = { + "Pressures\r" +}; + #endif // useChryslerMAPCorrection const uint8_t rvVSSpulseIdx = 0; // distance pulse count const uint8_t rvVSScycleIdx = 1; // time that the vehicle has spent moving @@ -377,9 +382,3 @@ const char tripSaveFuncNames[] PROGMEM = { }; #endif // useSavedTrips -#ifdef useChryslerMAPCorrection -const char pressureCorrectScreenFuncNames[] PROGMEM = { - "Pressures\r" -}; - -#endif // useChryslerMAPCorrection diff --git a/mpguino_tav/trip_measurement.ino b/mpguino_tav/trip_measurement.ino index 6325a56..647b5c1 100644 --- a/mpguino_tav/trip_measurement.ino +++ b/mpguino_tav/trip_measurement.ino @@ -1,42 +1,3 @@ -#ifdef useEEPROMtripStorage -static uint8_t tripVar::getBaseEEPROMaddress(uint8_t tripIdx, uint8_t dataIdx) -{ - - uint8_t retVal; - - if (dataIdx < rvMeasuredCount) switch (tripIdx) - { - - case EEPROMcurrentIdx: - retVal = pCurrTripVSSpulseIdx + dataIdx; - break; - - case EEPROMtankIdx: - retVal = pTankTripVSSpulseIdx + dataIdx; - break; - -#ifdef trackIdleEOCdata - case EEPROMeocIdleCurrentIdx: - retVal = pCurrIEOCvssPulseIdx + dataIdx; - break; - - case EEPROMeocIdleTankIdx: - retVal = pTankIEOCvssPulseIdx + dataIdx; - break; - -#endif // trackIdleEOCdata - default: - retVal = 0; - break; - - } - else retVal = 0; - - return retVal; - -} - -#endif // useEEPROMtripStorage static void tripVar::reset(uint8_t tripIdx) { @@ -240,18 +201,120 @@ static void tripVar::add64(uint64_t collectedArray[], uint8_t srcTripIdx, uint8_ } -#ifdef useWindowTripFilter -void windowTripFilterReset(void) +#ifdef useEEPROMtripStorage +static uint8_t tripVar::getBaseEEPROMaddress(uint8_t tripIdx, uint8_t dataIdx) { - wtpCurrentIdx = windowTripFilterIdx; + uint8_t retVal; - for (uint8_t x = 0; x < windowTripFilterSize; x++) tripVar::reset(windowTripFilterIdx + x); + if (dataIdx < rvMeasuredCount) switch (tripIdx) + { + + case EEPROMcurrentIdx: + retVal = pCurrTripVSSpulseIdx + dataIdx; + break; + + case EEPROMtankIdx: + retVal = pTankTripVSSpulseIdx + dataIdx; + break; + +#ifdef trackIdleEOCdata + case EEPROMeocIdleCurrentIdx: + retVal = pCurrIEOCvssPulseIdx + dataIdx; + break; + + case EEPROMeocIdleTankIdx: + retVal = pTankIEOCvssPulseIdx + dataIdx; + break; + +#endif // trackIdleEOCdata + default: + retVal = 0; + break; + + } + else retVal = 0; + + return retVal; + +} + +#endif // useEEPROMtripStorage +/* Trip save/restore/reset support section */ + +static void tripSupport::init(void) +{ + + rawTripIdx = raw0tripIdx; +#ifdef trackIdleEOCdata + rawEOCidleTripIdx = raw0eocIdleTripIdx; +#endif // trackIdleEOCdata + + for (uint8_t x = 0; x < tripSlotCount; x++) tripVar::reset(x); } +static void tripSupport::idleProcess(void) +{ + + uint8_t oldSREG; + uint8_t i; + uint8_t j; + uint8_t k; + uint8_t m; + + oldSREG = SREG; // save interrupt flag status + cli(); // disable interrupts to make the next operations atomic + + i = rawTripIdx; // save old trip variable index + rawTripIdx ^= (raw0tripIdx ^ raw1tripIdx); // set new raw trip variable index + +#ifdef trackIdleEOCdata + j = rawEOCidleTripIdx; // save old EOC/idle trip variable index + rawEOCidleTripIdx ^= (raw0eocIdleTripIdx ^ raw1eocIdleTripIdx); // set new raw EOC/idle trip variable index + +#endif // trackIdleEOCdata + SREG = oldSREG; // restore interrupt flag status + + for (uint8_t x = 0; x < tUScount; x++) + { + + k = translateTripIndex(tripUpdateSrcList, x) & 0x7F; + m = translateTripIndex(tripUpdateDestList, x); + + if (m) + { + + if (m & 0x80) tripVar::transfer(k, m & 0x7F); + else tripVar::update(k, m); + + } + + } + + tripVar::reset(i); // reset old raw trip variable +#ifdef trackIdleEOCdata + tripVar::reset(j); // reset old EOC/idle raw trip variable +#endif // trackIdleEOCdata + +#ifdef useWindowTripFilter + if (awakeFlags & aAwakeOnVehicle) + { + + if (EEPROM::readVal(pWindowTripFilterIdx)) + { + + wtpCurrentIdx++; + if (wtpCurrentIdx == windowTripFilterIdx + windowTripFilterSize) wtpCurrentIdx = windowTripFilterIdx; + + } + + } + #endif // useWindowTripFilter -static uint8_t translateTripIndex(const uint8_t tripTranslateList[], uint8_t tripListPos) +} + +static uint8_t tripSupport::translateTripIndex(const uint8_t tripTranslateList[], uint8_t tripListPos) { #ifdef useBarFuelEconVsTime @@ -315,8 +378,6 @@ static uint8_t translateTripIndex(const uint8_t tripTranslateList[], uint8_t tri } -/* Trip save/restore/reset support section */ - #ifdef useSavedTrips static uint8_t tripSupport::displayHandler(uint8_t cmd, uint8_t cursorPos, uint8_t cursorChanged) { @@ -502,9 +563,65 @@ static void tripSupport::resetCurrent(void) } +#ifdef useWindowTripFilter +static void tripSupport::resetWindowFilter(void) +{ + + wtpCurrentIdx = windowTripFilterIdx; + + for (uint8_t x = 0; x < windowTripFilterSize; x++) tripVar::reset(windowTripFilterIdx + x); + +} + +#endif // useWindowTripFilter #ifdef useChryslerMAPCorrection /* Chrysler returnless fuel pressure correction display section */ +static const uint8_t prgmCalculateMAPpressure[] PROGMEM = { + instrLdRegVoltage, 0x02, analogMAPchannelIdx, // load analog channel ADC step value + instrSubMainFromX, 0x02, mpAnalogMAPfloorIdx, // is reading below MAP sensor voltage floor? + instrBranchIfLT, 3, // if not, continue + instrLdRegByte, 0x02, 0, // zero out result in register 2 + +//cont1: + instrMul2byMain, mpAnalogMAPnumerIdx, // perform conversion to get pressure units per volts value + instrDiv2byMain, mpAnalogMAPdenomIdx, // divide by pressure units per volts value + instrAddEEPROMtoX, 0x02, pMAPsensorOffsetIdx, // add pressure offset value from EEPROM + instrStRegMain, 0x02, mpMAPpressureIdx, // store resulting MAP sensor reading +#ifdef useChryslerBaroSensor + instrDone // exit to caller +}; + +static const uint8_t prgmCalculateBaroPressure[] PROGMEM = { + instrLdRegVoltage, 0x02, analogBaroChannelIdx, // load analog channel ADC step value + instrSubMainFromX, 0x02, mpAnalogBaroFloorIdx, // is reading below barometric sensor voltage floor? + instrBranchIfLT, 3, // if not, continue + instrLdRegByte, 0x02, 0, // zero out result in register 2 + +//cont1: + instrMul2byMain, mpAnalogBaroNumerIdx, // convert to obtain pressure units per volts value + instrDiv2byMain, mpAnalogBaroDenomIdx, // divide by pressure units per volts value + instrAddEEPROMtoX, 0x02, pBaroSensorOffsetIdx, // add pressure offset value from EEPROM + instrStRegMain, 0x02, mpBaroPressureIdx, // store resulting barometric sensor reading +#endif // useChryslerBaroSensor + instrLdRegMain, 0x02, mpFuelPressureIdx, // get fuel system differential pressure + instrAddMainToX, 0x02, mpBaroPressureIdx, // add to reference barometric pressure to get fuel system absolute pressure + instrSubMainFromX, 0x02, mpMAPpressureIdx, // subtract MAP to get differential pressure across the fuel injector + instrStRegMain, 0x02, mpInjPressureIdx, // store differential pressure across the fuel injector + instrMul2byConst, idxCorrectionFactor, // set up for iSqrt + instrDiv2byMain, mpFuelPressureIdx, // divide by the fuel system differential pressure + instrTestReg, 0x02, // test whether overflow occurred + instrBranchIfOverflow, 6, // if overflow occurred, go handle it + instrIsqrt, 0x02, // perform square root on result + instrStRegVolatile, 0x02, vInjectorCorrectionIdx, // save square root of presssure differential ratio as fuel injector correction factor + instrDone, // return to caller + +//cont3: + instrLdRegConst, 0x02, idxCorrectionFactor, + instrStRegVolatile, 0x02, vInjectorCorrectionIdx, // save initial injector correction index for pressure differential calculation + instrDone // return to caller +}; + const uint8_t pressureCorrectScreenFormats[4][2] PROGMEM = { {(mpMAPpressureIdx - mpMAPpressureIdx), 0x80 | tPressureChannel} // Pressures ,{(mpBaroPressureIdx - mpMAPpressureIdx), 0x80 | tPressureChannel}