diff --git a/firmware/Makefile b/firmware/Makefile index 3fcf139b46..ccf2bc06e4 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -119,7 +119,6 @@ CSRC = $(PORTSRC) \ $(UTILSRC) \ $(ENGINES_SRC) \ $(CONSOLESRC) \ - $(TUNERSTUDIOSRC) \ $(CONSOLEUTILSRC) \ $(HALSRC) \ $(EMULATIONSRC) \ @@ -145,6 +144,7 @@ CPPSRC = $(CHCPPSRC) \ $(SYSTEMSRC_CPP) \ $(ENGINES_SRC_CPP) \ $(HW_LAYER_SRC_CPP) \ + $(TUNERSTUDIO_SRC_CPP) \ $(CONSOLE_SRC_CPP) \ $(CONTROLLERS_SENSORS_SRC_CPP) \ $(CONTROLLERS_SRC_CPP) \ diff --git a/firmware/config/boards/arro_board.h b/firmware/config/boards/arro_board.h index 2d480c0859..55e7c0327f 100644 --- a/firmware/config/boards/arro_board.h +++ b/firmware/config/boards/arro_board.h @@ -49,7 +49,7 @@ #define STM32_PWM_USE_TIM8 TRUE // slow adc #define STM32_PWM_USE_TIM9 FALSE -#define STM32_SPI_USE_SPI1 FALSE +#define STM32_SPI_USE_SPI1 TRUE #define STM32_SPI_USE_SPI2 FALSE // external ADC #define STM32_SPI_USE_SPI3 TRUE // potentiometer @@ -80,6 +80,16 @@ //#define SPI_CS4_PIN 10 //#define SPI_SD_MODULE_PORT GPIOD //#define SPI_SD_MODULE_PIN 11 + +#define EFI_SPI1_SCK_PORT GPIOB +#define EFI_SPI1_SCK_PIN 3 +#define EFI_SPI1_MISO_PORT GPIOB +#define EFI_SPI1_MISO_PIN 4 +#define EFI_SPI1_MOSI_PORT GPIOB +#define EFI_SPI1_MOSI_PIN 5 +#define EFI_SPI1_AF 5 + + #define EFI_SPI2_SCK_PORT GPIOB #define EFI_SPI2_SCK_PIN 13 #define EFI_SPI2_MISO_PORT GPIOB @@ -88,17 +98,14 @@ #define EFI_SPI2_MOSI_PIN 15 #define EFI_SPI2_AF 5 + /** * This section is for right-side center SPI */ -#define SPI_CS1_PORT GPIOD -#define SPI_CS1_PIN 7 // this is pointing into the sky for now - conflict with I2C #define SPI_CS2_PORT GPIOH // this is pointing into the sky for now - conflict with I2C #define SPI_CS2_PIN 0 -#define SPI_CS3_PORT GPIOD -#define SPI_CS3_PIN 5 #define SPI_CS4_PORT GPIOD #define SPI_CS4_PIN 3 #define SPI_SD_MODULE_PORT GPIOD diff --git a/firmware/config/efifeatures.h b/firmware/config/efifeatures.h index 0bb4526766..0ba4b9e9bf 100644 --- a/firmware/config/efifeatures.h +++ b/firmware/config/efifeatures.h @@ -62,8 +62,8 @@ * MCP42010 digital potentiometer support. This could be useful if you are stimulating some * stock ECU */ -#define EFI_POTENTIOMETER FALSE -//#define EFI_POTENTIOMETER TRUE +//#define EFI_POTENTIOMETER FALSE +#define EFI_POTENTIOMETER TRUE #define EFI_INTERNAL_ADC TRUE diff --git a/firmware/config/engines/GY6_139QMB.cpp b/firmware/config/engines/GY6_139QMB.cpp index 82257d2bdf..a7cafe0f6e 100644 --- a/firmware/config/engines/GY6_139QMB.cpp +++ b/firmware/config/engines/GY6_139QMB.cpp @@ -25,8 +25,9 @@ void setGy6139qmbDefaultEngineConfiguration(engine_configuration_s *engineConfig /** * We treat the trigger as 1/0 toothed wheel */ - engineConfiguration->triggerConfig.totalToothCount = 1; - engineConfiguration->triggerConfig.skippedToothCount = 0; - engineConfiguration->triggerConfig.isSynchronizationNeeded = false; - engineConfiguration->needSecondTriggerInput = false; + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL; + engineConfiguration->triggerConfig.customTotalToothCount = 1; + engineConfiguration->triggerConfig.customSkippedToothCount = 0; + engineConfiguration->triggerConfig.customIsSynchronizationNeeded = false; +//todo engineConfiguration2->triggerShape.needSecondTriggerInput = false; } diff --git a/firmware/config/engines/citroenBerlingoTU3JP.cpp b/firmware/config/engines/citroenBerlingoTU3JP.cpp index ff28d5f41a..c8cffc5444 100644 --- a/firmware/config/engines/citroenBerlingoTU3JP.cpp +++ b/firmware/config/engines/citroenBerlingoTU3JP.cpp @@ -15,12 +15,7 @@ void setCitroenBerlingoTU3JPConfiguration(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration) { engineConfiguration->engineType = CITROEN_TU3JP; - //engineConfiguration->triggerConfig.triggerType = todo 60_2 - - setToothedWheelConfiguration(engineConfiguration, 60, 2); - - setTriggerSynchronizationGap(&engineConfiguration->triggerConfig, 2.5); - + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL_60_2; // set_cranking_injection_mode 0 engineConfiguration->crankingInjectionMode = IM_SIMULTANEOUS; diff --git a/firmware/config/engines/dodge_neon.cpp b/firmware/config/engines/dodge_neon.cpp index 7a8b918ee6..f3893caa76 100644 --- a/firmware/config/engines/dodge_neon.cpp +++ b/firmware/config/engines/dodge_neon.cpp @@ -42,11 +42,6 @@ void setDodgeNeonEngineConfiguration(engine_configuration_s *engineConfiguration // set_whole_fuel_map 3 setWholeFuelMap(engineConfiguration, 3); - setTriggerSynchronizationGap(&engineConfiguration->triggerConfig, 0.72); - - engineConfiguration->triggerConfig.useRiseEdge = false; - engineConfiguration->needSecondTriggerInput = true; - // set_cranking_injection_mode 0 engineConfiguration->crankingInjectionMode = IM_SIMULTANEOUS; // set_injection_mode 1 diff --git a/firmware/config/engines/ford_1995_inline_6.cpp b/firmware/config/engines/ford_1995_inline_6.cpp index 29c5106f45..aa70e30818 100644 --- a/firmware/config/engines/ford_1995_inline_6.cpp +++ b/firmware/config/engines/ford_1995_inline_6.cpp @@ -40,14 +40,14 @@ void setFordInline6(engine_configuration_s *engineConfiguration, board_configura /** * We treat the trigger as 6/0 toothed wheel */ - setToothedWheelConfiguration(engineConfiguration, 6, 0); - engineConfiguration->triggerConfig.useRiseEdge = TRUE; - engineConfiguration->needSecondTriggerInput = false; + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL; + engineConfiguration->triggerConfig.customTotalToothCount = 6; + engineConfiguration->triggerConfig.customSkippedToothCount = 0; + engineConfiguration->triggerConfig.customIsSynchronizationNeeded = false; engineConfiguration->globalTriggerAngleOffset = 0; engineConfiguration->ignitionOffset = 13; - setThermistorConfiguration(&engineConfiguration->cltThermistorConf, -10, 160310, 60, 7700, 120.00, 1180); engineConfiguration->cltThermistorConf.bias_resistor = 2700; diff --git a/firmware/config/engines/ford_aspire.cpp b/firmware/config/engines/ford_aspire.cpp index 85994be13e..1bfee66739 100644 --- a/firmware/config/engines/ford_aspire.cpp +++ b/firmware/config/engines/ford_aspire.cpp @@ -119,7 +119,6 @@ void setFordAspireEngineConfiguration(engine_configuration_s *engineConfiguratio setSingleCoilDwell(engineConfiguration); engineConfiguration->ignitionMode = IM_ONE_COIL; engineConfiguration->triggerConfig.triggerType = TT_FORD_ASPIRE; - engineConfiguration->triggerConfig.isSynchronizationNeeded = false; boardConfiguration->injectionPins[4] = GPIO_NONE; boardConfiguration->injectionPins[5] = GPIO_NONE; diff --git a/firmware/config/engines/ford_escort_gt.cpp b/firmware/config/engines/ford_escort_gt.cpp index 0c905feb3d..531b033f46 100644 --- a/firmware/config/engines/ford_escort_gt.cpp +++ b/firmware/config/engines/ford_escort_gt.cpp @@ -12,7 +12,6 @@ void setFordEscortGt(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration) { engineConfiguration->triggerConfig.triggerType = TT_FORD_ESCORT_GT; - engineConfiguration->needSecondTriggerInput = FALSE; engineConfiguration->cylindersCount = 4; engineConfiguration->firingOrder = FO_1_THEN_3_THEN_4_THEN2; diff --git a/firmware/config/engines/ford_fiesta.cpp b/firmware/config/engines/ford_fiesta.cpp index 47132ac390..1fb2b3b109 100644 --- a/firmware/config/engines/ford_fiesta.cpp +++ b/firmware/config/engines/ford_fiesta.cpp @@ -20,7 +20,7 @@ void setFordFiestaDefaultEngineConfiguration(engine_configuration_s *engineConfi engineConfiguration->rpmHardLimit = 7000; setOperationMode(engineConfiguration, FOUR_STROKE_CRANK_SENSOR); - setToothedWheelConfiguration(engineConfiguration, 36, 1); + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL_36_1; engineConfiguration->ignitionMode = IM_WASTED_SPARK; engineConfiguration->firingOrder = FO_1_THEN_3_THEN_4_THEN2; diff --git a/firmware/config/engines/honda_accord.cpp b/firmware/config/engines/honda_accord.cpp index cd38d3e251..7e3979a0d8 100644 --- a/firmware/config/engines/honda_accord.cpp +++ b/firmware/config/engines/honda_accord.cpp @@ -1,6 +1,12 @@ /** * @file honda_accord.cpp * + * 1995 Honda Accord EX + * http://rusefi.com/wiki/index.php?title=Vehicle:Honda_Accord_1995 + * http://rusefi.com/forum/viewtopic.php?f=3&t=621 + * + * engine_type 6 + * * @date Jan 12, 2014 * @author Andrey Belomutskiy, (c) 2012-2014 */ @@ -9,8 +15,45 @@ #include "engine_configuration.h" #include "trigger_decoder.h" -void setHondaAccordConfiguration(engine_configuration_s *engineConfiguration) { - engineConfiguration->triggerConfig.totalToothCount = 24; - engineConfiguration->triggerConfig.skippedToothCount = 2; +void setHondaAccordConfiguration(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration) { + engineConfiguration->engineType = HONDA_ACCORD; + + engineConfiguration->map.sensor.sensorType = MT_HONDA3BAR; + + engineConfiguration->cylindersCount = 4; + engineConfiguration->displacement = 2.156; + + // Keihin 06164-P0A-A00 + engineConfiguration->injectorFlow = 248; + + + engineConfiguration->algorithm = LM_SPEED_DENSITY; + + + engineConfiguration->crankingSettings.coolantTempMaxC = 65; // 8ms at 65C + engineConfiguration->crankingSettings.fuelAtMaxTempMs = 8; + + engineConfiguration->crankingSettings.coolantTempMinC = 0; // 20ms at 0C + engineConfiguration->crankingSettings.fuelAtMinTempMs = 15; + + + memset(boardConfiguration->adcHwChannelEnabled, 0, sizeof(boardConfiguration->adcHwChannelEnabled)); + boardConfiguration->adcHwChannelEnabled[0] = ADC_FAST; // ADC0 - PA0 - MAP + boardConfiguration->adcHwChannelEnabled[1] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[2] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[3] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[4] = ADC_SLOW; + + boardConfiguration->adcHwChannelEnabled[6] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[7] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[11] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[12] = ADC_SLOW; + boardConfiguration->adcHwChannelEnabled[13] = ADC_SLOW; + + + engineConfiguration->map.sensor.sensorType = MT_MPX4250; + engineConfiguration->map.sensor.hwChannel = 0; + + } diff --git a/firmware/config/engines/honda_accord.h b/firmware/config/engines/honda_accord.h index 98f42fa006..9fa9da863c 100644 --- a/firmware/config/engines/honda_accord.h +++ b/firmware/config/engines/honda_accord.h @@ -10,6 +10,6 @@ #include "engine_configuration.h" -void setHondaAccordConfiguration(engine_configuration_s *engineConfiguration); +void setHondaAccordConfiguration(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration); #endif /* HONDA_ACCORD_H_ */ diff --git a/firmware/config/engines/mazda_323.cpp b/firmware/config/engines/mazda_323.cpp index cce9d64e9a..571f9bc446 100644 --- a/firmware/config/engines/mazda_323.cpp +++ b/firmware/config/engines/mazda_323.cpp @@ -16,5 +16,5 @@ void setMazda323EngineConfiguration(engine_configuration_s *engineConfiguration) /** * We treat the trigger as 4/0 toothed wheel */ - setToothedWheelConfiguration(engineConfiguration, 4, 0); +// setToothedWheelConfiguration(engineConfiguration, 4, 0); } diff --git a/firmware/config/engines/mazda_miata_nb.cpp b/firmware/config/engines/mazda_miata_nb.cpp index ef9478f1a0..207b995086 100644 --- a/firmware/config/engines/mazda_miata_nb.cpp +++ b/firmware/config/engines/mazda_miata_nb.cpp @@ -17,8 +17,6 @@ void setMazdaMiataNbEngineConfiguration(engine_configuration_s *engineConfigurat engineConfiguration->triggerConfig.triggerType = TT_MAZDA_MIATA_NB; - setTriggerSynchronizationGap(&engineConfiguration->triggerConfig, 0.11); - engineConfiguration->triggerConfig.useRiseEdge = false; engineConfiguration->globalTriggerAngleOffset = 276; // set_cranking_injection_mode 0 diff --git a/firmware/config/engines/nissan_primera.cpp b/firmware/config/engines/nissan_primera.cpp index 460d559d1e..b16e29ea26 100644 --- a/firmware/config/engines/nissan_primera.cpp +++ b/firmware/config/engines/nissan_primera.cpp @@ -13,7 +13,7 @@ #include "nissan_primera.h" void setNissanPrimeraEngineConfiguration(engine_configuration_s *engineConfiguration) { - setToothedWheelConfiguration(engineConfiguration, 60, 2); + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL_60_2; } #endif /* EFI_SUPPORT_NISSAN_PRIMERA */ diff --git a/firmware/config/engines/rover_v8.cpp b/firmware/config/engines/rover_v8.cpp index 10f8665cb6..e1cab7645f 100644 --- a/firmware/config/engines/rover_v8.cpp +++ b/firmware/config/engines/rover_v8.cpp @@ -18,7 +18,7 @@ void setRoverv8(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration) { setOperationMode(engineConfiguration, FOUR_STROKE_CRANK_SENSOR); - setToothedWheelConfiguration(engineConfiguration, 36, 1); + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL_36_1; engineConfiguration->displacement = 3.528; engineConfiguration->cylindersCount = 8; diff --git a/firmware/console/eficonsole.c b/firmware/console/eficonsole.c index a4599b00ab..61861c1eee 100644 --- a/firmware/console/eficonsole.c +++ b/firmware/console/eficonsole.c @@ -52,7 +52,7 @@ static void myerror(void) { static void sayHello(void) { printMsg(&logger, "*** rusEFI (c) Andrey Belomutskiy, 2012-2014. All rights reserved."); - printMsg(&logger, "rusEFI v%d@%d", getRusEfiVersion(), SVN_VERSION); + printMsg(&logger, "rusEFI v%d@%s", getRusEfiVersion(), VCS_VERSION); printMsg(&logger, "*** Chibios Kernel: %s", CH_KERNEL_VERSION); printMsg(&logger, "*** Compiled: " __DATE__ " - " __TIME__ ""); printMsg(&logger, "COMPILER=%s", __VERSION__); diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index d71b48fb1b..3d4bd8997e 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -129,7 +129,7 @@ void printSensors(void) { reportSensorI("rpm", getRpm()); reportSensorF("maf", getMaf(), 2); - if (engineConfiguration2->hasMapSensor) { + if (engineConfiguration->hasMapSensor) { reportSensorF(getCaption(LP_MAP), getMap(), 2); reportSensorF("map_r", getRawMap(), 2); } @@ -141,7 +141,7 @@ void printSensors(void) { reportSensorF(getCaption(LP_THROTTLE), getTPS(), 2); - if (engineConfiguration2->hasCltSensor) { + if (engineConfiguration->hasCltSensor) { reportSensorF(getCaption(LP_ECT), getCoolantTemperature(), 2); } @@ -167,11 +167,12 @@ void printState(int currentCkpEventCounter) { // debugFloat(&logger, "table_spark", getAdvance(rpm, getMaf()), 2); float engineLoad = getEngineLoad(); - debugFloat(&logger, "fuel_base", getBaseFuel(rpm, engineLoad), 2); + float baseFuel = getBaseFuel(&engine, rpm); + debugFloat(&logger, "fuel_base", baseFuel, 2); // debugFloat(&logger, "fuel_iat", getIatCorrection(getIntakeAirTemperature()), 2); // debugFloat(&logger, "fuel_clt", getCltCorrection(getCoolantTemperature()), 2); debugFloat(&logger, "fuel_lag", getInjectorLag(getVBatt()), 2); - debugFloat(&logger, "fuel", getRunningFuel(rpm, engineLoad), 2); + debugFloat(&logger, "fuel", getRunningFuel(baseFuel, &engine, rpm), 2); debugFloat(&logger, "timing", getAdvance(rpm, engineLoad), 2); @@ -187,8 +188,6 @@ void printState(int currentCkpEventCounter) { static char LOGGING_BUFFER[500]; -#if EFI_PROD_CODE - volatile int needToReportStatus = FALSE; static int prevCkpEventCounter = -1; @@ -198,38 +197,6 @@ static void printStatus(void) { needToReportStatus = TRUE; } -//float getTCharge1(float tps) { -// float cltK = tempCtoKelvin(getCoolantTemperature()); -// float iatK = tempCtoKelvin(getIntakeAirTemperature()); -// return getTCharge(getCurrentRpm(), tps, cltK, iatK); -//} - -//#if EFI_CUSTOM_PANIC_METHOD -//extern char *dbg_panic_file; -//extern int dbg_panic_line; -//#endif - -//static void checkIfShouldHalt(void) { -//#if CH_DBG_ENABLED -// if (hasFatalError()) { -// /** -// * low-level function is used here to reduce stack usage -// */ -// palWritePad(LED_ERROR_PORT, LED_ERROR_PIN, 1); -//#if EFI_CUSTOM_PANIC_METHOD -// print("my FATAL [%s] at %s:%d\r\n", dbg_panic_msg, dbg_panic_file, dbg_panic_line); -//#else -// print("my FATAL [%s] at %s:%d\r\n", dbg_panic_msg); -//#endif -// chThdSleepSeconds(1); -// // todo: figure out how we halt exactly -// while (TRUE) { -// } -// chSysHalt(); -// } -//#endif -//} - /** * Time when the firmware version was reported last time, in seconds * TODO: implement a request/response instead of just constantly sending this out @@ -240,7 +207,7 @@ static void printVersion(systime_t nowSeconds) { if (overflowDiff(nowSeconds, timeOfPreviousPrintVersion) < 4) return; timeOfPreviousPrintVersion = nowSeconds; - appendPrintf(&logger, "rusEfiVersion%s%d@%d %s%s", DELIMETER, getRusEfiVersion(), SVN_VERSION, + appendPrintf(&logger, "rusEfiVersion%s%d@%s %s%s", DELIMETER, getRusEfiVersion(), VCS_VERSION, getConfigurationName(engineConfiguration), DELIMETER); } @@ -259,14 +226,19 @@ void updateDevConsoleState(void) { // checkIfShouldHalt(); printPending(); +#if EFI_PROD_CODE + // todo: unify with simulator! if (hasFirmwareError()) { printMsg(&logger, "firmware error: %s", errorMessageBuffer); warningEnabled = FALSE; chThdSleepMilliseconds(200); return; } +#endif +#if EFI_PROD_CODE pokeAdcInputs(); +#endif if (!fullLog) return; @@ -291,6 +263,8 @@ void updateDevConsoleState(void) { finishStatusLine(); } +#if EFI_PROD_CODE + /* * command example: * sfm 3500 400 @@ -298,7 +272,7 @@ void updateDevConsoleState(void) { */ static void showFuelMap2(float rpm, float engineLoad) { - float baseFuel = getBaseFuel(rpm, engineLoad); + float baseFuel = getBaseTableFuel(rpm, engineLoad); float iatCorrection = getIatCorrection(getIntakeAirTemperature()); float cltCorrection = getCltCorrection(getCoolantTemperature()); @@ -309,7 +283,7 @@ static void showFuelMap2(float rpm, float engineLoad) { scheduleMsg(&logger2, "iatCorrection=%f cltCorrection=%f injectorLag=%f", iatCorrection, cltCorrection, injectorLag); - float value = getRunningFuel(rpm, engineLoad); + float value = getRunningFuel(baseFuel, &engine, rpm); scheduleMsg(&logger2, "injection pulse width: %f", value); } diff --git a/firmware/console/status_loop.h b/firmware/console/status_loop.h index 5fecb76093..a0bb5f1798 100644 --- a/firmware/console/status_loop.h +++ b/firmware/console/status_loop.h @@ -19,7 +19,6 @@ void initStatusLoop(void); void updateDevConsoleState(void); int getFullLog(void); void printSensors(void); -void finishStatusLine(void); void setFullLog(int value); void startStatusThreads(void); void sayOsHello(void); diff --git a/firmware/console/tunerstudio/tunerstudio.c b/firmware/console/tunerstudio/tunerstudio.cpp similarity index 82% rename from firmware/console/tunerstudio/tunerstudio.c rename to firmware/console/tunerstudio/tunerstudio.cpp index af6edc1ee5..0d47803aa0 100644 --- a/firmware/console/tunerstudio/tunerstudio.c +++ b/firmware/console/tunerstudio/tunerstudio.cpp @@ -1,518 +1,508 @@ -/** - * @file tunerstudio.c - * @brief Integration with EFI Analytics Tuner Studio software - * - * todo: merge this file with tunerstudio_algo.c? - * - * @date Aug 26, 2013 - * @author Andrey Belomutskiy, (c) 2012-2014 - * - * This file is part of rusEfi - see http://rusefi.com - * - * rusEfi is free software; you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . - * - */ - -#include "main.h" - -#include "engine_state.h" -#include "tunerstudio.h" - -#include "main_trigger_callback.h" -#include "flash_main.h" - -#include "tunerstudio_algo.h" -#include "tunerstudio_configuration.h" -#include "malfunction_central.h" -#include "wave_math.h" -#include "console_io.h" -#include "crc.h" - -#if EFI_TUNER_STUDIO - -#if EFI_PROD_CODE -#include "pin_repository.h" -#include "usbconsole.h" -#include "map_averaging.h" -extern SerialUSBDriver SDU1; -#define CONSOLE_DEVICE &SDU1 - -#define TS_SERIAL_UART_DEVICE &SD3 -//#define TS_SERIAL_SPEED 115200 -#define TS_SERIAL_SPEED 38400 - -static SerialConfig tsSerialConfig = { TS_SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 }; -#endif /* EFI_PROD_CODE */ - -#define MAX_PAGE_ID 0 -#define PAGE_0_SIZE 5804 - -// in MS, that's 10 seconds -#define TS_READ_TIMEOUT 10000 - -#define PROTOCOL "001" - - -BaseChannel * getTsSerialDevice(void) { -#if EFI_PROD_CODE - if (isSerialOverUart()) { - // if console uses UART then TS uses USB - return (BaseChannel *) &SDU1; - } else { - return (BaseChannel *) TS_SERIAL_UART_DEVICE; - } -#else - return (BaseChannel *) TS_SIMULATOR_PORT; -#endif -} - -static Logging logger; - -extern engine_configuration_s *engineConfiguration; -extern persistent_config_s configWorkingCopy; -extern persistent_config_container_s persistentState; - -static efitimems_t previousWriteReportMs = 0; - -static int ts_serail_ready(void) { -#if EFI_PROD_CODE - if (isSerialOverUart()) { - // TS uses USB when console uses serial - return is_usb_serial_ready(); - } else { - // TS uses serial when console uses USB - return TRUE; - } -#else - return TRUE; -#endif -} - -static THD_WORKING_AREA(TS_WORKING_AREA, UTILITY_THREAD_STACK_SIZE); - -static int tsCounter = 0; - -//static TunerStudioWriteValueRequest writeValueRequest; -//static TunerStudioWriteChunkRequest writeChunkRequest; - -extern TunerStudioOutputChannels tsOutputChannels; - -extern TunerStudioState tsState; - -static void printStats(void) { -#if EFI_PROD_CODE - if (!isSerialOverUart()) { - scheduleMsg(&logger, "TS RX on %s%d", portname(TS_SERIAL_RX_PORT), TS_SERIAL_RX_PIN); - scheduleMsg(&logger, "TS TX on %s%d", portname(TS_SERIAL_TX_PORT), TS_SERIAL_TX_PIN); - } -#endif /* EFI_PROD_CODE */ - scheduleMsg(&logger, "TunerStudio total/error counter=%d/%d", tsCounter, tsState.errorCounter); - scheduleMsg(&logger, "TunerStudio H counter=%d", tsState.queryCommandCounter); - scheduleMsg(&logger, "TunerStudio O counter=%d size=%d", tsState.outputChannelsCommandCounter, - sizeof(tsOutputChannels)); - scheduleMsg(&logger, "TunerStudio P counter=%d", tsState.readPageCommandsCounter); - scheduleMsg(&logger, "TunerStudio B counter=%d", tsState.burnCommandCounter); - scheduleMsg(&logger, "TunerStudio W counter=%d", tsState.writeValueCommandCounter); - scheduleMsg(&logger, "TunerStudio C counter=%d", tsState.writeChunkCommandCounter); - scheduleMsg(&logger, "TunerStudio P counter=%d current page %d", tsState.pageCommandCounter, tsState.currentPageId); - scheduleMsg(&logger, "pages total size=%d", sizeof(engine_configuration_s)); - scheduleMsg(&logger, "page 0 size=%d", getTunerStudioPageSize(0)); - scheduleMsg(&logger, "page 1 size=%d", getTunerStudioPageSize(1)); - -// scheduleMsg(&logger, "timingMode %d", (int)(&engineConfiguration->timingMode) - (int)engineConfiguration); -// scheduleMsg(&logger, "cylindersCount %d", (int)(&engineConfiguration->cylindersCount) - (int)engineConfiguration); - scheduleMsg(&logger, "analogChartFrequency %d", - (int) (&engineConfiguration->analogChartFrequency) - (int) engineConfiguration); - - int fuelMapOffset = (int) (&engineConfiguration->fuelTable) - (int) engineConfiguration; - scheduleMsg(&logger, "fuelTable %d", fuelMapOffset); - - int offset = (int) (&engineConfiguration->bc.injectionPinMode) - (int) engineConfiguration; - scheduleMsg(&logger, "injectionPinMode %d", offset); - - offset = (int) (&engineConfiguration->bc.idleThreadPeriod) - (int) engineConfiguration; - scheduleMsg(&logger, "idleThreadPeriod %d", offset); - - - if (sizeof(engine_configuration_s) != getTunerStudioPageSize(0)) - firmwareError("TS page size mismatch"); -} - -void tunerStudioWriteData(const uint8_t * buffer, int size) { - chSequentialStreamWrite(getTsSerialDevice(), buffer, size); -} - -void tunerStudioDebug(const char *msg) { -#if EFI_TUNER_STUDIO_VERBOSE - scheduleMsg(&logger, "%s", msg); - printStats(); -#endif -} - -char *getWorkingPageAddr(int pageIndex) { - switch (pageIndex) { - case 0: - return (char*) &configWorkingCopy.engineConfiguration; -// case 1: -// return (char*) &configWorkingCopy.boardConfiguration; -// case 2: // fuelTable -// case 3: // ignitionTable -// case 4: // veTable -// case 5: // afrTable -// return (char*) &configWorkingCopy.engineConfiguration + PAGE_0_SIZE + (pageIndex - 2) * 1024; - } - return NULL; -} - -int getTunerStudioPageSize(int pageIndex) { - switch (pageIndex) { - case 0: - return PAGE_0_SIZE; -// case 1: -// return sizeof(configWorkingCopy.boardConfiguration); -// case 2: -// case 3: -// case 4: -// return 1024; - } - return 0; -} - -void handlePageSelectCommand(ts_response_format_e mode, uint16_t pageId) { - tsState.pageCommandCounter++; - - tsState.currentPageId = pageId; - scheduleMsg(&logger, "page %d selected", tsState.currentPageId); - tsSendResponse(mode, NULL, 0); -} - -/** - * This command is needed to make the whole transfer a bit faster - * @note See also handleWriteValueCommand - */ -void handleWriteChunkCommand(ts_response_format_e mode, short offset, short count, void *content) { - tsState.writeChunkCommandCounter++; - - scheduleMsg(&logger, "receiving page %d chunk offset %d size %d", tsState.currentPageId, offset, count); - - if (offset > getTunerStudioPageSize(tsState.currentPageId)) { - scheduleMsg(&logger, "ERROR offset %d", offset); - tunerStudioError("ERROR: out of range"); - offset = 0; - } - - if (count > getTunerStudioPageSize(tsState.currentPageId)) { - tunerStudioError("ERROR: unexpected count"); - scheduleMsg(&logger, "ERROR count %d", count); - count = 0; - } - - uint8_t * addr = (uint8_t *) (getWorkingPageAddr(tsState.currentPageId) + offset); - memcpy(addr, content, count); - - tsSendResponse(mode, NULL, 0); -} - -/** - * 'Write' command receives a single value at a given offset - * @note Writing values one by one is pretty slow - */ -void handleWriteValueCommand(ts_response_format_e mode, uint16_t page, uint16_t offset, uint8_t value) { - tsState.writeValueCommandCounter++; - - tsState.currentPageId = page; - -//tunerStudioDebug("got W (Write)"); // we can get a lot of these - -#if EFI_TUNER_STUDIO_VERBOSE -// scheduleMsg(&logger, "Page number %d\r\n", pageId); // we can get a lot of these -#endif - - int size = sizeof(TunerStudioWriteValueRequest); -// scheduleMsg(&logger, "Reading %d\r\n", size); - - if (offset > getTunerStudioPageSize(tsState.currentPageId)) { - tunerStudioError("ERROR: out of range2"); - scheduleMsg(&logger, "ERROR offset %d", offset); - offset = 0; - return; - } - - efitimems_t nowMs = currentTimeMillis(); - if (nowMs - previousWriteReportMs > 5) { - previousWriteReportMs = nowMs; - scheduleMsg(&logger, "page %d offset %d: value=%d", tsState.currentPageId, offset, value); - } - - getWorkingPageAddr(tsState.currentPageId)[offset] = value; - -// scheduleMsg(&logger, "va=%d", configWorkingCopy.boardConfiguration.idleValvePin); -} - -static void sendErrorCode(void) { - tunerStudioWriteCrcPacket(TS_RESPONSE_CRC_FAILURE, NULL, 0); -} - -void handlePageReadCommand(ts_response_format_e mode, uint16_t pageId, uint16_t offset, uint16_t count) { - tsState.readPageCommandsCounter++; - tunerStudioDebug("got R (Read page)"); - tsState.currentPageId = pageId; - -#if EFI_TUNER_STUDIO_VERBOSE - scheduleMsg(&logger, "Page requested: page %d offset=%d count=%d", tsState.currentPageId, offset, count); -#endif - - if (tsState.currentPageId > MAX_PAGE_ID) { - scheduleMsg(&logger, "invalid Page number %x", tsState.currentPageId); - - // something is not right here - tsState.currentPageId = 0; - tunerStudioError("ERROR: invalid page"); - return; - } - - int size = getTunerStudioPageSize(tsState.currentPageId); - - if (size < offset + count) { - scheduleMsg(&logger, "invalid offset/count %d/%d", offset, count); - sendErrorCode(); - return; - } - - const uint8_t *addr = (const uint8_t *) (getWorkingPageAddr(tsState.currentPageId) + offset); - tsSendResponse(mode, addr, count); -#if EFI_TUNER_STUDIO_VERBOSE - scheduleMsg(&logger, "Sending %d done", count); -#endif -} - -/** - * 'Burn' command is a command to commit the changes - */ -void handleBurnCommand(ts_response_format_e mode, uint16_t page) { - tsState.burnCommandCounter++; - - tunerStudioDebug("got B (Burn)"); - - tsState.currentPageId = page; - -#if EFI_TUNER_STUDIO_VERBOSE - scheduleMsg(&logger, "Page number %d\r\n", tsState.currentPageId); -#endif - -// todo: how about some multi-threading? - memcpy(&persistentState.persistentConfiguration, &configWorkingCopy, sizeof(persistent_config_s)); - - scheduleMsg(&logger, "va1=%d", configWorkingCopy.engineConfiguration.bc.idleValvePin); - scheduleMsg(&logger, "va2=%d", persistentState.persistentConfiguration.engineConfiguration.bc.idleValvePin); - -#if EFI_INTERNAL_FLASH - writeToFlash(); -#endif - incrementGlobalConfigurationVersion(); - tunerStudioWriteCrcPacket(TS_RESPONSE_BURN_OK, NULL, 0); -} - -static TunerStudioReadRequest readRequest; -static short int pageIn; - -static bool handlePlainCommand(uint8_t command) { - if (command == TS_HELLO_COMMAND) { - scheduleMsg(&logger, "Got naked Query command"); - handleQueryCommand(TS_PLAIN); - return true; - } else if (command == 't' || command == 'T') { - handleTestCommand(); - return true; - } else if (command == TS_PAGE_COMMAND) { - int recieved = chSequentialStreamRead(getTsSerialDevice(), (uint8_t *)&pageIn, sizeof(pageIn)); - handlePageSelectCommand(TS_PLAIN, pageIn); - return true; - } else if (command == TS_READ_COMMAND) { - //scheduleMsg(&logger, "Got naked READ PAGE???"); - int recieved = chSequentialStreamRead(getTsSerialDevice(), (uint8_t *)&readRequest, sizeof(readRequest)); - if (recieved != sizeof(readRequest)) { - // todo: handler error - return true; - } - handlePageReadCommand(TS_PLAIN, readRequest.page, readRequest.offset, readRequest.count); - return true; - } else if (command == TS_OUTPUT_COMMAND) { - //scheduleMsg(&logger, "Got naked Channels???"); - handleOutputChannelsCommand(TS_PLAIN); - return true; - } else if (command == 'F') { - tunerStudioDebug("not ignoring F"); - tunerStudioWriteData((const uint8_t *) PROTOCOL, strlen(PROTOCOL)); - return true; - } else { - return false; - } -} - -static bool isKnownCommand(char command) { - return command == TS_HELLO_COMMAND || command == TS_READ_COMMAND || command == TS_OUTPUT_COMMAND - || command == TS_PAGE_COMMAND || command == TS_BURN_COMMAND || command == TS_SINGLE_WRITE_COMMAND - || command == TS_CHUNK_WRITE_COMMAND; -} - -static uint8_t firstByte; -static uint8_t secondByte; - -// todo: reduce TS page size so that we can reduce buffer size -static char crcIoBuffer[4096]; - -static msg_t tsThreadEntryPoint(void *arg) { - (void) arg; - chRegSetThreadName("tunerstudio thread"); - - int wasReady = false; - while (true) { - int isReady = ts_serail_ready(); - if (!isReady) { - chThdSleepMilliseconds(10); - wasReady = false; - continue; - } - - if (!wasReady) { - wasReady = TRUE; -// scheduleSimpleMsg(&logger, "ts channel is now ready ", hTimeNow()); - } - - tsCounter++; - - int recieved = chSequentialStreamRead(getTsSerialDevice(), &firstByte, 1); - if (recieved != 1) { - tunerStudioError("ERROR: no command"); - continue; - } -// scheduleMsg(&logger, "Got first=%x=[%c]", firstByte, firstByte); - if (handlePlainCommand(firstByte)) - continue; - - recieved = chSequentialStreamRead(getTsSerialDevice(), &secondByte, 1); - if (recieved != 1) { - tunerStudioError("ERROR: no second"); - continue; - } -// scheduleMsg(&logger, "Got secondByte=%x=[%c]", secondByte, secondByte); - - int incomingPacketSize = firstByte * 256 + secondByte; - - if (incomingPacketSize == 0 || incomingPacketSize > sizeof(crcIoBuffer)) { - scheduleMsg(&logger, "TunerStudio: invalid size: %d", incomingPacketSize); - tunerStudioError("ERROR: size"); - sendErrorCode(); - continue; - } - - recieved = chnReadTimeout(getTsSerialDevice(), crcIoBuffer, 1, MS2ST(TS_READ_TIMEOUT)); - if (recieved != 1) { - tunerStudioError("ERROR: did not receive command"); - continue; - } - - char command = crcIoBuffer[0]; - if (!isKnownCommand(command)) { - scheduleMsg(&logger, "unexpected command %x", command); - sendErrorCode(); - continue; - } - -// scheduleMsg(&logger, "TunerStudio: reading %d+4 bytes(s)", incomingPacketSize); - - recieved = chnReadTimeout(getTsSerialDevice(), (void * ) (crcIoBuffer + 1), incomingPacketSize + 4 - 1, - MS2ST(TS_READ_TIMEOUT)); - int expectedSize = incomingPacketSize + 4 - 1; - if (recieved != expectedSize) { - scheduleMsg(&logger, "got ONLY %d for packet size %d/%d for command %c", recieved, incomingPacketSize, - expectedSize, command); - tunerStudioError("ERROR: not enough"); - continue; - } - - uint32_t expectedCrc = *(uint32_t*) (crcIoBuffer + incomingPacketSize); - - expectedCrc = SWAP_UINT32(expectedCrc); - - int actualCrc = crc32(crcIoBuffer, incomingPacketSize); - if (actualCrc != expectedCrc) { - scheduleMsg(&logger, "TunerStudio: CRC %x %x %x %x", crcIoBuffer[incomingPacketSize + 0], - crcIoBuffer[incomingPacketSize + 1], crcIoBuffer[incomingPacketSize + 2], - crcIoBuffer[incomingPacketSize + 3]); - - scheduleMsg(&logger, "TunerStudio: command %c actual CRC %x/expected %x", crcIoBuffer[0], actualCrc, - expectedCrc); - tunerStudioError("ERROR: CRC issue"); - continue; - } - -// scheduleMsg(&logger, "TunerStudio: P00-07 %x %x %x %x %x %x %x %x", crcIoBuffer[0], crcIoBuffer[1], -// crcIoBuffer[2], crcIoBuffer[3], crcIoBuffer[4], crcIoBuffer[5], crcIoBuffer[6], crcIoBuffer[7]); - - int success = tunerStudioHandleCrcCommand(crcIoBuffer, incomingPacketSize); - if (!success) - print("got unexpected TunerStudio command %x:%c\r\n", command, command); - - } -#if defined __GNUC__ - return 0; -#endif -} - -void syncTunerStudioCopy(void) { - memcpy(&configWorkingCopy, &persistentState.persistentConfiguration, sizeof(persistent_config_s)); -} - -void startTunerStudioConnectivity(void) { - initLogging(&logger, "tuner studio"); - memset(&tsState, 0, sizeof(tsState)); -#if EFI_PROD_CODE - if (isSerialOverUart()) { - print("TunerStudio over USB serial"); - usb_serial_start(); - } else { - - print("TunerStudio over USART"); - mySetPadMode("tunerstudio rx", TS_SERIAL_RX_PORT, TS_SERIAL_RX_PIN, PAL_MODE_ALTERNATE(TS_SERIAL_AF)); - mySetPadMode("tunerstudio tx", TS_SERIAL_TX_PORT, TS_SERIAL_TX_PIN, PAL_MODE_ALTERNATE(TS_SERIAL_AF)); - - sdStart(TS_SERIAL_UART_DEVICE, &tsSerialConfig); - } -#endif /* EFI_PROD_CODE */ - syncTunerStudioCopy(); - - addConsoleAction("tsinfo", printStats); - - chThdCreateStatic(TS_WORKING_AREA, sizeof(TS_WORKING_AREA), NORMALPRIO, tsThreadEntryPoint, NULL); -} - -/** - * Adds size to the beginning of a packet and a crc32 at the end. Then send the packet. - */ -void tunerStudioWriteCrcPacket(const uint8_t command, const void *buf, const uint16_t size) { - // todo: max size validation - *(uint16_t *) crcIoBuffer = SWAP_UINT16(size + 1); // packet size including command - *(uint8_t *) (crcIoBuffer + 2) = command; - if (size != 0) - memcpy(crcIoBuffer + 3, buf, size); - // CRC on whole packet - uint32_t crc = crc32((void *) (crcIoBuffer + 2), (uint32_t) (size + 1)); - *(uint32_t *) (crcIoBuffer + 2 + 1 + size) = SWAP_UINT32(crc); - -// scheduleMsg(&logger, "TunerStudio: CRC command %x size %d", command, size); - - tunerStudioWriteData(crcIoBuffer, size + 2 + 1 + 4); // with size, command and CRC -} - -#endif /* EFI_TUNER_STUDIO */ +/** + * @file tunerstudio.cpp + * @brief Integration with EFI Analytics Tuner Studio software + * + * todo: merge this file with tunerstudio_algo.c? + * + * @date Aug 26, 2013 + * @author Andrey Belomutskiy, (c) 2012-2014 + * + * This file is part of rusEfi - see http://rusefi.com + * + * rusEfi is free software; you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + * + */ + +#include "main.h" + +#include "engine_state.h" +#include "tunerstudio.h" + +#include "main_trigger_callback.h" +#include "flash_main.h" + +#include "tunerstudio_algo.h" +#include "tunerstudio_configuration.h" +#include "malfunction_central.h" +#include "wave_math.h" +#include "console_io.h" +#include "crc.h" + +#if EFI_TUNER_STUDIO + +#if EFI_PROD_CODE +#include "pin_repository.h" +#include "usbconsole.h" +#include "map_averaging.h" +extern SerialUSBDriver SDU1; +#define CONSOLE_DEVICE &SDU1 + +#define TS_SERIAL_UART_DEVICE &SD3 +//#define TS_SERIAL_SPEED 115200 +#define TS_SERIAL_SPEED 38400 + +static SerialConfig tsSerialConfig = { TS_SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 }; +#endif /* EFI_PROD_CODE */ + +#define MAX_PAGE_ID 0 +#define PAGE_0_SIZE 5824 + +// in MS, that's 10 seconds +#define TS_READ_TIMEOUT 10000 + +#define PROTOCOL "001" + + +BaseChannel * getTsSerialDevice(void) { +#if EFI_PROD_CODE + if (isSerialOverUart()) { + // if console uses UART then TS uses USB + return (BaseChannel *) &SDU1; + } else { + return (BaseChannel *) TS_SERIAL_UART_DEVICE; + } +#else + return (BaseChannel *) TS_SIMULATOR_PORT; +#endif +} + +static Logging logger; + +extern engine_configuration_s *engineConfiguration; +extern persistent_config_s configWorkingCopy; +extern persistent_config_container_s persistentState; + +static efitimems_t previousWriteReportMs = 0; + +static int ts_serail_ready(void) { +#if EFI_PROD_CODE + if (isSerialOverUart()) { + // TS uses USB when console uses serial + return is_usb_serial_ready(); + } else { + // TS uses serial when console uses USB + return TRUE; + } +#else + return TRUE; +#endif +} + +static THD_WORKING_AREA(TS_WORKING_AREA, UTILITY_THREAD_STACK_SIZE); + +static int tsCounter = 0; + +//static TunerStudioWriteValueRequest writeValueRequest; +//static TunerStudioWriteChunkRequest writeChunkRequest; + +extern TunerStudioOutputChannels tsOutputChannels; + +extern TunerStudioState tsState; + +static void printStats(void) { +#if EFI_PROD_CODE + if (!isSerialOverUart()) { + scheduleMsg(&logger, "TS RX on %s%d/TX on %s%d", portname(TS_SERIAL_RX_PORT), TS_SERIAL_RX_PIN, + portname(TS_SERIAL_TX_PORT), TS_SERIAL_TX_PIN); + } +#endif /* EFI_PROD_CODE */ + scheduleMsg(&logger, "TunerStudio total/error counter=%d/%d H=%d / O counter=%d size=%d / P=%d / B=%d", tsCounter, tsState.errorCounter, tsState.queryCommandCounter, tsState.outputChannelsCommandCounter, + sizeof(tsOutputChannels), tsState.readPageCommandsCounter, tsState.burnCommandCounter); + scheduleMsg(&logger, "TunerStudio W counter=%d / C = %d / P = %d / current page %d", tsState.writeValueCommandCounter, tsState.writeChunkCommandCounter, + tsState.pageCommandCounter, tsState.currentPageId); + scheduleMsg(&logger, "page size=%d", sizeof(engine_configuration_s)); + +// scheduleMsg(&logger, "analogChartFrequency %d", +// (int) (&engineConfiguration->analogChartFrequency) - (int) engineConfiguration); +// +// int fuelMapOffset = (int) (&engineConfiguration->fuelTable) - (int) engineConfiguration; +// scheduleMsg(&logger, "fuelTable %d", fuelMapOffset); +// +// int offset = (int) (&engineConfiguration->bc.injectionPinMode) - (int) engineConfiguration; +// scheduleMsg(&logger, "injectionPinMode %d", offset); +// +// offset = (int) (&engineConfiguration->bc.idleThreadPeriod) - (int) engineConfiguration; +// scheduleMsg(&logger, "idleThreadPeriod %d", offset); + + if (sizeof(engine_configuration_s) != getTunerStudioPageSize(0)) + firmwareError("TS page size mismatch"); +} + +void tunerStudioWriteData(const uint8_t * buffer, int size) { + chSequentialStreamWrite(getTsSerialDevice(), buffer, size); +} + +void tunerStudioDebug(const char *msg) { +#if EFI_TUNER_STUDIO_VERBOSE + scheduleMsg(&logger, "%s", msg); + printStats(); +#endif +} + +char *getWorkingPageAddr(int pageIndex) { + switch (pageIndex) { + case 0: + return (char*) &configWorkingCopy.engineConfiguration; +// case 1: +// return (char*) &configWorkingCopy.boardConfiguration; +// case 2: // fuelTable +// case 3: // ignitionTable +// case 4: // veTable +// case 5: // afrTable +// return (char*) &configWorkingCopy.engineConfiguration + PAGE_0_SIZE + (pageIndex - 2) * 1024; + } + return NULL; +} + +int getTunerStudioPageSize(int pageIndex) { + switch (pageIndex) { + case 0: + return PAGE_0_SIZE; +// case 1: +// return sizeof(configWorkingCopy.boardConfiguration); +// case 2: +// case 3: +// case 4: +// return 1024; + } + return 0; +} + +void handlePageSelectCommand(ts_response_format_e mode, uint16_t pageId) { + tsState.pageCommandCounter++; + + tsState.currentPageId = pageId; + scheduleMsg(&logger, "page %d selected", tsState.currentPageId); + tsSendResponse(mode, NULL, 0); +} + +/** + * This command is needed to make the whole transfer a bit faster + * @note See also handleWriteValueCommand + */ +void handleWriteChunkCommand(ts_response_format_e mode, short offset, short count, void *content) { + tsState.writeChunkCommandCounter++; + + scheduleMsg(&logger, "receiving page %d chunk offset %d size %d", tsState.currentPageId, offset, count); + + if (offset > getTunerStudioPageSize(tsState.currentPageId)) { + scheduleMsg(&logger, "ERROR offset %d", offset); + tunerStudioError("ERROR: out of range"); + offset = 0; + } + + if (count > getTunerStudioPageSize(tsState.currentPageId)) { + tunerStudioError("ERROR: unexpected count"); + scheduleMsg(&logger, "ERROR count %d", count); + count = 0; + } + + uint8_t * addr = (uint8_t *) (getWorkingPageAddr(tsState.currentPageId) + offset); + memcpy(addr, content, count); + + tsSendResponse(mode, NULL, 0); +} + +/** + * 'Write' command receives a single value at a given offset + * @note Writing values one by one is pretty slow + */ +void handleWriteValueCommand(ts_response_format_e mode, uint16_t page, uint16_t offset, uint8_t value) { + tsState.writeValueCommandCounter++; + + tsState.currentPageId = page; + +//tunerStudioDebug("got W (Write)"); // we can get a lot of these + +#if EFI_TUNER_STUDIO_VERBOSE +// scheduleMsg(&logger, "Page number %d\r\n", pageId); // we can get a lot of these +#endif + + int size = sizeof(TunerStudioWriteValueRequest); +// scheduleMsg(&logger, "Reading %d\r\n", size); + + if (offset > getTunerStudioPageSize(tsState.currentPageId)) { + tunerStudioError("ERROR: out of range2"); + scheduleMsg(&logger, "ERROR offset %d", offset); + offset = 0; + return; + } + + efitimems_t nowMs = currentTimeMillis(); + if (nowMs - previousWriteReportMs > 5) { + previousWriteReportMs = nowMs; + scheduleMsg(&logger, "page %d offset %d: value=%d", tsState.currentPageId, offset, value); + } + + getWorkingPageAddr(tsState.currentPageId)[offset] = value; + +// scheduleMsg(&logger, "va=%d", configWorkingCopy.boardConfiguration.idleValvePin); +} + +static void sendErrorCode(void) { + tunerStudioWriteCrcPacket(TS_RESPONSE_CRC_FAILURE, NULL, 0); +} + +void handlePageReadCommand(ts_response_format_e mode, uint16_t pageId, uint16_t offset, uint16_t count) { + tsState.readPageCommandsCounter++; + tunerStudioDebug("got R (Read page)"); + tsState.currentPageId = pageId; + +#if EFI_TUNER_STUDIO_VERBOSE + scheduleMsg(&logger, "Page requested: page %d offset=%d count=%d", tsState.currentPageId, offset, count); +#endif + + if (tsState.currentPageId > MAX_PAGE_ID) { + scheduleMsg(&logger, "invalid Page number %x", tsState.currentPageId); + + // something is not right here + tsState.currentPageId = 0; + tunerStudioError("ERROR: invalid page"); + return; + } + + int size = getTunerStudioPageSize(tsState.currentPageId); + + if (size < offset + count) { + scheduleMsg(&logger, "invalid offset/count %d/%d", offset, count); + sendErrorCode(); + return; + } + + const uint8_t *addr = (const uint8_t *) (getWorkingPageAddr(tsState.currentPageId) + offset); + tsSendResponse(mode, addr, count); +#if EFI_TUNER_STUDIO_VERBOSE + scheduleMsg(&logger, "Sending %d done", count); +#endif +} + +/** + * 'Burn' command is a command to commit the changes + */ +void handleBurnCommand(ts_response_format_e mode, uint16_t page) { + efitimems_t nowMs = currentTimeMillis(); + tsState.burnCommandCounter++; + + tunerStudioDebug("got B (Burn)"); + + tsState.currentPageId = page; + +#if EFI_TUNER_STUDIO_VERBOSE + // pointless since we only have one page now +// scheduleMsg(&logger, "Page number %d", tsState.currentPageId); +#endif + +// todo: how about some multi-threading? + memcpy(&persistentState.persistentConfiguration, &configWorkingCopy, sizeof(persistent_config_s)); + +#if EFI_INTERNAL_FLASH + writeToFlash(); +#endif + incrementGlobalConfigurationVersion(); + tunerStudioWriteCrcPacket(TS_RESPONSE_BURN_OK, NULL, 0); + scheduleMsg(&logger, "burned in (ms): %d", currentTimeMillis() - nowMs); +} + +static TunerStudioReadRequest readRequest; +static short int pageIn; + +static bool handlePlainCommand(uint8_t command) { + if (command == TS_HELLO_COMMAND) { + scheduleMsg(&logger, "Got naked Query command"); + handleQueryCommand(TS_PLAIN); + return true; + } else if (command == 't' || command == 'T') { + handleTestCommand(); + return true; + } else if (command == TS_PAGE_COMMAND) { + int recieved = chSequentialStreamRead(getTsSerialDevice(), (uint8_t *)&pageIn, sizeof(pageIn)); + handlePageSelectCommand(TS_PLAIN, pageIn); + return true; + } else if (command == TS_READ_COMMAND) { + //scheduleMsg(&logger, "Got naked READ PAGE???"); + int recieved = chSequentialStreamRead(getTsSerialDevice(), (uint8_t *)&readRequest, sizeof(readRequest)); + if (recieved != sizeof(readRequest)) { + // todo: handler error + return true; + } + handlePageReadCommand(TS_PLAIN, readRequest.page, readRequest.offset, readRequest.count); + return true; + } else if (command == TS_OUTPUT_COMMAND) { + //scheduleMsg(&logger, "Got naked Channels???"); + handleOutputChannelsCommand(TS_PLAIN); + return true; + } else if (command == 'F') { + tunerStudioDebug("not ignoring F"); + tunerStudioWriteData((const uint8_t *) PROTOCOL, strlen(PROTOCOL)); + return true; + } else { + return false; + } +} + +static bool isKnownCommand(char command) { + return command == TS_HELLO_COMMAND || command == TS_READ_COMMAND || command == TS_OUTPUT_COMMAND + || command == TS_PAGE_COMMAND || command == TS_BURN_COMMAND || command == TS_SINGLE_WRITE_COMMAND + || command == TS_CHUNK_WRITE_COMMAND; +} + +static uint8_t firstByte; +static uint8_t secondByte; + +// todo: reduce TS page size so that we can reduce buffer size +static uint8_t crcIoBuffer[4096]; + +static msg_t tsThreadEntryPoint(void *arg) { + (void) arg; + chRegSetThreadName("tunerstudio thread"); + + int wasReady = false; + while (true) { + int isReady = ts_serail_ready(); + if (!isReady) { + chThdSleepMilliseconds(10); + wasReady = false; + continue; + } + + if (!wasReady) { + wasReady = TRUE; +// scheduleSimpleMsg(&logger, "ts channel is now ready ", hTimeNow()); + } + + tsCounter++; + + int recieved = chSequentialStreamRead(getTsSerialDevice(), &firstByte, 1); + if (recieved != 1) { + tunerStudioError("ERROR: no command"); + continue; + } +// scheduleMsg(&logger, "Got first=%x=[%c]", firstByte, firstByte); + if (handlePlainCommand(firstByte)) + continue; + + recieved = chSequentialStreamRead(getTsSerialDevice(), &secondByte, 1); + if (recieved != 1) { + tunerStudioError("ERROR: no second"); + continue; + } +// scheduleMsg(&logger, "Got secondByte=%x=[%c]", secondByte, secondByte); + + int incomingPacketSize = firstByte * 256 + secondByte; + + if (incomingPacketSize == 0 || incomingPacketSize > sizeof(crcIoBuffer)) { + scheduleMsg(&logger, "TunerStudio: invalid size: %d", incomingPacketSize); + tunerStudioError("ERROR: size"); + sendErrorCode(); + continue; + } + + recieved = chnReadTimeout(getTsSerialDevice(), crcIoBuffer, 1, MS2ST(TS_READ_TIMEOUT)); + if (recieved != 1) { + tunerStudioError("ERROR: did not receive command"); + continue; + } + + char command = crcIoBuffer[0]; + if (!isKnownCommand(command)) { + scheduleMsg(&logger, "unexpected command %x", command); + sendErrorCode(); + continue; + } + +// scheduleMsg(&logger, "TunerStudio: reading %d+4 bytes(s)", incomingPacketSize); + + recieved = chnReadTimeout(getTsSerialDevice(), (uint8_t * ) (crcIoBuffer + 1), incomingPacketSize + 4 - 1, + MS2ST(TS_READ_TIMEOUT)); + int expectedSize = incomingPacketSize + 4 - 1; + if (recieved != expectedSize) { + scheduleMsg(&logger, "got ONLY %d for packet size %d/%d for command %c", recieved, incomingPacketSize, + expectedSize, command); + tunerStudioError("ERROR: not enough"); + continue; + } + + uint32_t expectedCrc = *(uint32_t*) (crcIoBuffer + incomingPacketSize); + + expectedCrc = SWAP_UINT32(expectedCrc); + + int actualCrc = crc32(crcIoBuffer, incomingPacketSize); + if (actualCrc != expectedCrc) { + scheduleMsg(&logger, "TunerStudio: CRC %x %x %x %x", crcIoBuffer[incomingPacketSize + 0], + crcIoBuffer[incomingPacketSize + 1], crcIoBuffer[incomingPacketSize + 2], + crcIoBuffer[incomingPacketSize + 3]); + + scheduleMsg(&logger, "TunerStudio: command %c actual CRC %x/expected %x", crcIoBuffer[0], actualCrc, + expectedCrc); + tunerStudioError("ERROR: CRC issue"); + continue; + } + +// scheduleMsg(&logger, "TunerStudio: P00-07 %x %x %x %x %x %x %x %x", crcIoBuffer[0], crcIoBuffer[1], +// crcIoBuffer[2], crcIoBuffer[3], crcIoBuffer[4], crcIoBuffer[5], crcIoBuffer[6], crcIoBuffer[7]); + + int success = tunerStudioHandleCrcCommand(crcIoBuffer, incomingPacketSize); + if (!success) + print("got unexpected TunerStudio command %x:%c\r\n", command, command); + + } +#if defined __GNUC__ + return 0; +#endif +} + +void syncTunerStudioCopy(void) { + memcpy(&configWorkingCopy, &persistentState.persistentConfiguration, sizeof(persistent_config_s)); +} + +void startTunerStudioConnectivity(void) { + initLogging(&logger, "tuner studio"); + memset(&tsState, 0, sizeof(tsState)); +#if EFI_PROD_CODE + if (isSerialOverUart()) { + print("TunerStudio over USB serial"); + usb_serial_start(); + } else { + + print("TunerStudio over USART"); + mySetPadMode("tunerstudio rx", TS_SERIAL_RX_PORT, TS_SERIAL_RX_PIN, PAL_MODE_ALTERNATE(TS_SERIAL_AF)); + mySetPadMode("tunerstudio tx", TS_SERIAL_TX_PORT, TS_SERIAL_TX_PIN, PAL_MODE_ALTERNATE(TS_SERIAL_AF)); + + sdStart(TS_SERIAL_UART_DEVICE, &tsSerialConfig); + } +#endif /* EFI_PROD_CODE */ + syncTunerStudioCopy(); + + addConsoleAction("tsinfo", printStats); + + chThdCreateStatic(TS_WORKING_AREA, sizeof(TS_WORKING_AREA), NORMALPRIO, tsThreadEntryPoint, NULL); +} + +/** + * Adds size to the beginning of a packet and a crc32 at the end. Then send the packet. + */ +void tunerStudioWriteCrcPacket(const uint8_t command, const void *buf, const uint16_t size) { + // todo: max size validation + *(uint16_t *) crcIoBuffer = SWAP_UINT16(size + 1); // packet size including command + *(uint8_t *) (crcIoBuffer + 2) = command; + if (size != 0) + memcpy(crcIoBuffer + 3, buf, size); + // CRC on whole packet + uint32_t crc = crc32((void *) (crcIoBuffer + 2), (uint32_t) (size + 1)); + *(uint32_t *) (crcIoBuffer + 2 + 1 + size) = SWAP_UINT32(crc); + +// scheduleMsg(&logger, "TunerStudio: CRC command %x size %d", command, size); + + tunerStudioWriteData(crcIoBuffer, size + 2 + 1 + 4); // with size, command and CRC +} + +#endif /* EFI_TUNER_STUDIO */ diff --git a/firmware/console/tunerstudio/tunerstudio.mk b/firmware/console/tunerstudio/tunerstudio.mk index 03cc87deda..a0c5d66d6c 100644 --- a/firmware/console/tunerstudio/tunerstudio.mk +++ b/firmware/console/tunerstudio/tunerstudio.mk @@ -1,3 +1,3 @@ -TUNERSTUDIOSRC = $(PROJECT_DIR)/console/tunerstudio/tunerstudio_algo.c \ - $(PROJECT_DIR)/console/tunerstudio/tunerstudio.c +TUNERSTUDIO_SRC_CPP = $(PROJECT_DIR)/console/tunerstudio/tunerstudio_algo.cpp \ + $(PROJECT_DIR)/console/tunerstudio/tunerstudio.cpp diff --git a/firmware/console/tunerstudio/tunerstudio_algo.c b/firmware/console/tunerstudio/tunerstudio_algo.cpp similarity index 95% rename from firmware/console/tunerstudio/tunerstudio_algo.c rename to firmware/console/tunerstudio/tunerstudio_algo.cpp index a6e018f66b..27ab46a87c 100644 --- a/firmware/console/tunerstudio/tunerstudio_algo.c +++ b/firmware/console/tunerstudio/tunerstudio_algo.cpp @@ -1,154 +1,154 @@ -/** - * @file tunerstudio_algo.c - * @brief Tuner Studio plain protocol implementation - * - * This implementation would not happen without the documentation - * provided by Jon Zeeff (jon@zeeff.com) - * - * Tuner Studio has a really simple protocol, a minimal implementation - * capable of displaying current engine state on the gauges would - * require only two commands: queryCommand and ochGetCommand - * - * queryCommand: - * Communication initialization command. TunerStudio sends a single byte H - * ECU response: - * One of the known ECU id strings. We are using "MShift v0.01" id string. - * - * ochGetCommand: - * Request for output channels state.TunerStudio sends a single byte O - * ECU response: - * A snapshot of output channels as described in [OutputChannels] section of the .ini file - * The length of this block is 'ochBlockSize' property of the .ini file - * - * These two commands are enough to get working gauges. In order to start configuring the ECU using - * tuner studio, three more commands should be implemented: - * - * todo: merge this file with tunerstudio.c? - * - * - * @date Oct 22, 2013 - * @author Andrey Belomutskiy, (c) 2012-2014 - * - * This file is part of rusEfi - see http://rusefi.com - * - * rusEfi is free software; you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . - */ - -#include -#include "tunerstudio_algo.h" -#include "tunerstudio_configuration.h" -#include "engine_configuration.h" -#include "tunerstudio.h" - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -TunerStudioState tsState; -TunerStudioOutputChannels tsOutputChannels; -/** - * this is a local copy of the configuration. Any changes to this copy - * have no effect until this copy is explicitly propagated to the main working copy - */ -persistent_config_s configWorkingCopy; - -void tunerStudioError(const char *msg) { - tunerStudioDebug(msg); - tsState.errorCounter++; -} - -int tunerStudioHandleCrcCommand(char *data, int incomingPacketSize) { - char command = data[0]; - data++; - if (command == TS_HELLO_COMMAND) { - tunerStudioDebug("got CRC Query"); - handleQueryCommand(TS_CRC); - } else if (command == TS_OUTPUT_COMMAND) { - handleOutputChannelsCommand(TS_CRC); - } else if (command == TS_PAGE_COMMAND) { - uint16_t page = *(uint16_t *) data; - handlePageSelectCommand(TS_CRC, page); - } else if (command == TS_CHUNK_WRITE_COMMAND) { - uint16_t offset = *(uint16_t *) data; - uint16_t count = *(uint16_t *) (data + 2); - handleWriteChunkCommand(TS_CRC, offset, count, data + 4); - } else if (command == TS_SINGLE_WRITE_COMMAND) { - uint16_t page = *(uint16_t *) data; - uint16_t offset = *(uint16_t *) (data + 2); - uint8_t value = data[4]; - handleWriteValueCommand(TS_CRC, page, offset, value); - } else if (command == TS_BURN_COMMAND) { - uint16_t page = *(uint16_t *) data; - handleBurnCommand(TS_CRC, page); - } else if (command == TS_READ_COMMAND) { - uint16_t page = *(uint16_t *) data; - uint16_t offset = *(uint16_t *) (data + 2); - uint16_t count = *(uint16_t *) (data + 4); - handlePageReadCommand(TS_CRC, page, offset, count); - } else if (command == 't' || command == 'T') { - handleTestCommand(); - } else if (command == 'F') { - tunerStudioDebug("ignoring F"); - /** - * http://www.msextra.com/forums/viewtopic.php?f=122&t=48327 - * Response from TS support: This is an optional command * - * "The F command is used to find what ini. file needs to be loaded in TunerStudio to match the controller. - * If you are able to just make your firmware ignore the command that would work. - * Currently on some firmware versions the F command is not used and is just ignored by the firmware as a unknown command." - */ - } else { - tunerStudioError("ERROR: ignoring unexpected command"); - return FALSE; - } - return TRUE; -} - -void tsSendResponse(ts_response_format_e mode, const uint8_t * buffer, int size) { - if (mode == TS_CRC) { - tunerStudioWriteCrcPacket(TS_RESPONSE_OK, buffer, size); - } else { - if (size > 0) - tunerStudioWriteData(buffer, size); - } -} - -/** - * Query with CRC takes place while re-establishing connection - * Query without CRC takes place on TunerStudio startup - */ -void handleQueryCommand(ts_response_format_e mode) { - tsState.queryCommandCounter++; - tunerStudioDebug("got H (queryCommand)"); - tsSendResponse(mode, (const uint8_t *) TS_SIGNATURE, strlen(TS_SIGNATURE) + 1); -} - -/** - * @brief 'Output' command sends out a snapshot of current values - */ -void handleOutputChannelsCommand(ts_response_format_e mode) { - tsState.outputChannelsCommandCounter++; - // this method is invoked too often to print any debug information - tsSendResponse(mode, (const uint8_t *) &tsOutputChannels, sizeof(TunerStudioOutputChannels)); -} - -void handleTestCommand(void) { - /** - * this is NOT a standard TunerStudio command, this is my own - * extension of the protocol to simplify troubleshooting - */ - tunerStudioDebug("got T (Test)"); - tunerStudioWriteData((const uint8_t *) "alive\r\n", 7); -} +/** + * @file tunerstudio_algo.cpp + * @brief Tuner Studio plain protocol implementation + * + * This implementation would not happen without the documentation + * provided by Jon Zeeff (jon@zeeff.com) + * + * Tuner Studio has a really simple protocol, a minimal implementation + * capable of displaying current engine state on the gauges would + * require only two commands: queryCommand and ochGetCommand + * + * queryCommand: + * Communication initialization command. TunerStudio sends a single byte H + * ECU response: + * One of the known ECU id strings. We are using "MShift v0.01" id string. + * + * ochGetCommand: + * Request for output channels state.TunerStudio sends a single byte O + * ECU response: + * A snapshot of output channels as described in [OutputChannels] section of the .ini file + * The length of this block is 'ochBlockSize' property of the .ini file + * + * These two commands are enough to get working gauges. In order to start configuring the ECU using + * tuner studio, three more commands should be implemented: + * + * todo: merge this file with tunerstudio.c? + * + * + * @date Oct 22, 2013 + * @author Andrey Belomutskiy, (c) 2012-2014 + * + * This file is part of rusEfi - see http://rusefi.com + * + * rusEfi is free software; you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include +#include "tunerstudio_algo.h" +#include "tunerstudio_configuration.h" +#include "engine_configuration.h" +#include "tunerstudio.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +TunerStudioState tsState; +TunerStudioOutputChannels tsOutputChannels; +/** + * this is a local copy of the configuration. Any changes to this copy + * have no effect until this copy is explicitly propagated to the main working copy + */ +persistent_config_s configWorkingCopy; + +void tunerStudioError(const char *msg) { + tunerStudioDebug(msg); + tsState.errorCounter++; +} + +int tunerStudioHandleCrcCommand(uint8_t *data, int incomingPacketSize) { + char command = data[0]; + data++; + if (command == TS_HELLO_COMMAND) { + tunerStudioDebug("got CRC Query"); + handleQueryCommand(TS_CRC); + } else if (command == TS_OUTPUT_COMMAND) { + handleOutputChannelsCommand(TS_CRC); + } else if (command == TS_PAGE_COMMAND) { + uint16_t page = *(uint16_t *) data; + handlePageSelectCommand(TS_CRC, page); + } else if (command == TS_CHUNK_WRITE_COMMAND) { + uint16_t offset = *(uint16_t *) data; + uint16_t count = *(uint16_t *) (data + 2); + handleWriteChunkCommand(TS_CRC, offset, count, data + 4); + } else if (command == TS_SINGLE_WRITE_COMMAND) { + uint16_t page = *(uint16_t *) data; + uint16_t offset = *(uint16_t *) (data + 2); + uint8_t value = data[4]; + handleWriteValueCommand(TS_CRC, page, offset, value); + } else if (command == TS_BURN_COMMAND) { + uint16_t page = *(uint16_t *) data; + handleBurnCommand(TS_CRC, page); + } else if (command == TS_READ_COMMAND) { + uint16_t page = *(uint16_t *) data; + uint16_t offset = *(uint16_t *) (data + 2); + uint16_t count = *(uint16_t *) (data + 4); + handlePageReadCommand(TS_CRC, page, offset, count); + } else if (command == 't' || command == 'T') { + handleTestCommand(); + } else if (command == 'F') { + tunerStudioDebug("ignoring F"); + /** + * http://www.msextra.com/forums/viewtopic.php?f=122&t=48327 + * Response from TS support: This is an optional command * + * "The F command is used to find what ini. file needs to be loaded in TunerStudio to match the controller. + * If you are able to just make your firmware ignore the command that would work. + * Currently on some firmware versions the F command is not used and is just ignored by the firmware as a unknown command." + */ + } else { + tunerStudioError("ERROR: ignoring unexpected command"); + return FALSE; + } + return TRUE; +} + +void tsSendResponse(ts_response_format_e mode, const uint8_t * buffer, int size) { + if (mode == TS_CRC) { + tunerStudioWriteCrcPacket(TS_RESPONSE_OK, buffer, size); + } else { + if (size > 0) + tunerStudioWriteData(buffer, size); + } +} + +/** + * Query with CRC takes place while re-establishing connection + * Query without CRC takes place on TunerStudio startup + */ +void handleQueryCommand(ts_response_format_e mode) { + tsState.queryCommandCounter++; + tunerStudioDebug("got H (queryCommand)"); + tsSendResponse(mode, (const uint8_t *) TS_SIGNATURE, strlen(TS_SIGNATURE) + 1); +} + +/** + * @brief 'Output' command sends out a snapshot of current values + */ +void handleOutputChannelsCommand(ts_response_format_e mode) { + tsState.outputChannelsCommandCounter++; + // this method is invoked too often to print any debug information + tsSendResponse(mode, (const uint8_t *) &tsOutputChannels, sizeof(TunerStudioOutputChannels)); +} + +void handleTestCommand(void) { + /** + * this is NOT a standard TunerStudio command, this is my own + * extension of the protocol to simplify troubleshooting + */ + tunerStudioDebug("got T (Test)"); + tunerStudioWriteData((const uint8_t *) "alive\r\n", 7); +} diff --git a/firmware/console/tunerstudio/tunerstudio_algo.h b/firmware/console/tunerstudio/tunerstudio_algo.h index 1b57c2f9dd..934f4ca4fb 100644 --- a/firmware/console/tunerstudio/tunerstudio_algo.h +++ b/firmware/console/tunerstudio/tunerstudio_algo.h @@ -42,7 +42,7 @@ typedef struct { short currentPageId; } TunerStudioState; -int tunerStudioHandleCrcCommand(char *data, int incomingPacketSize); +int tunerStudioHandleCrcCommand(uint8_t *data, int incomingPacketSize); void handleTestCommand(void); void handleQueryCommand(ts_response_format_e mode); diff --git a/firmware/controllers/algo/accel_enrichment.cpp b/firmware/controllers/algo/accel_enrichment.cpp index c680fdd64a..1d28d5c578 100644 --- a/firmware/controllers/algo/accel_enrichment.cpp +++ b/firmware/controllers/algo/accel_enrichment.cpp @@ -14,6 +14,7 @@ #include "engine_math.h" #include "signal_executor.h" +extern Engine engine; extern engine_configuration_s *engineConfiguration; static AccelEnrichmemnt instance; diff --git a/firmware/controllers/algo/ec2.h b/firmware/controllers/algo/ec2.h index deb6723208..cc3f46e06b 100644 --- a/firmware/controllers/algo/ec2.h +++ b/firmware/controllers/algo/ec2.h @@ -42,13 +42,11 @@ extern "C" class engine_configuration2_s { public: engine_configuration2_s(); - int hasMapSensor; - int hasCltSensor; Thermistor iat; Thermistor clt; - int crankAngleRange; +// int crankAngleRange; trigger_shape_s triggerShape; @@ -83,7 +81,7 @@ void resetConfigurationExt(Logging * logger, engine_type_e engineType, engine_configuration2_s *engineConfiguration2, board_configuration_s *boardConfiguration); void applyNonPersistentConfiguration(Logging * logger, engine_configuration_s *engineConfiguration, - engine_configuration2_s *engineConfiguration2, engine_type_e engineType); + engine_configuration2_s *engineConfiguration2); void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2); diff --git a/firmware/controllers/algo/engine_configuration.cpp b/firmware/controllers/algo/engine_configuration.cpp index cd3ba56611..00fe7668fb 100644 --- a/firmware/controllers/algo/engine_configuration.cpp +++ b/firmware/controllers/algo/engine_configuration.cpp @@ -80,6 +80,7 @@ void initBpsxD1Sensor(afr_sensor_s *sensor) { } void setWholeVEMap(engine_configuration_s *engineConfiguration, float value) { + // todo: table helper? // for (int l = 0; l < VE_LOAD_COUNT; l++) { // for (int r = 0; r < VE_RPM_COUNT; r++) { // engineConfiguration->veTable[l][r] = value; @@ -88,6 +89,7 @@ void setWholeVEMap(engine_configuration_s *engineConfiguration, float value) { } void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value) { + // todo: table helper? for (int l = 0; l < FUEL_LOAD_COUNT; l++) { for (int r = 0; r < FUEL_RPM_COUNT; r++) { engineConfiguration->fuelTable[l][r] = value; @@ -95,20 +97,6 @@ void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value) { } } -void setToothedWheelConfiguration(engine_configuration_s *engineConfiguration, int total, int skipped) { - engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL; - engineConfiguration->triggerConfig.isSynchronizationNeeded = (skipped != 0); - - engineConfiguration->triggerConfig.totalToothCount = total; - engineConfiguration->triggerConfig.skippedToothCount = skipped; -} - -void setTriggerSynchronizationGap(trigger_config_s *triggerConfig, float synchGap) { - triggerConfig->isSynchronizationNeeded = TRUE; - triggerConfig->syncRatioFrom = synchGap * 0.75; - triggerConfig->syncRatioTo = synchGap * 1.25; -} - /** * @brief Global default engine configuration * This method sets the default global engine configuration. These values are later overridden by engine-specific defaults @@ -158,7 +146,9 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ setTimingRpmBin(engineConfiguration, 800, 7000); setTableBin2(engineConfiguration->map.samplingAngleBins, MAP_ANGLE_SIZE, 800, 7000, 1); + setTableBin2(engineConfiguration->map.samplingAngle, MAP_ANGLE_SIZE, 100, 130, 1); setTableBin2(engineConfiguration->map.samplingWindowBins, MAP_ANGLE_SIZE, 800, 7000, 1); + setTableBin2(engineConfiguration->map.samplingWindow, MAP_ANGLE_SIZE, 50, 50, 1); // set_whole_timing_map 3 setWholeFuelMap(engineConfiguration, 3); @@ -230,9 +220,7 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ engineConfiguration->logFormat = LF_NATIVE; - engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL; - setTriggerSynchronizationGap(&engineConfiguration->triggerConfig, 2); - engineConfiguration->triggerConfig.useRiseEdge = TRUE; + engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL_60_2; engineConfiguration->HD44780width = 16; engineConfiguration->HD44780height = 2; @@ -248,8 +236,6 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ engineConfiguration->globalFuelCorrection = 1; - engineConfiguration->needSecondTriggerInput = TRUE; - engineConfiguration->map.sensor.sensorType = MT_MPX4250; engineConfiguration->baroSensor.sensorType = MT_CUSTOM; @@ -258,6 +244,10 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ engineConfiguration->diffLoadEnrichmentCoef = 1; + engineConfiguration->hasMapSensor = TRUE; + engineConfiguration->hasCltSensor = TRUE; + + boardConfiguration->idleValvePin = GPIOE_2; boardConfiguration->idleValvePinMode = OM_DEFAULT; boardConfiguration->fuelPumpPin = GPIOC_13; @@ -335,7 +325,7 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ boardConfiguration->consoleLoopPeriod = 200; boardConfiguration->lcdThreadPeriod = 300; boardConfiguration->tunerStudioThreadPeriod = 300; - boardConfiguration->generalPeriodicThreadPeriod = 200; + boardConfiguration->generalPeriodicThreadPeriod = 50; boardConfiguration->tunerStudioSerialSpeed = 38400; @@ -344,16 +334,20 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_ boardConfiguration->canDeviceMode = CD_USE_CAN2; boardConfiguration->canTxPin = GPIOB_0; boardConfiguration->canRxPin = GPIOB_12; + + boardConfiguration->digitalPotentiometerSpiDevice = SPI_NONE; + boardConfiguration->digitalPotentiometerChipSelect[0] = GPIOD_7; + boardConfiguration->digitalPotentiometerChipSelect[1] = GPIO_NONE; + boardConfiguration->digitalPotentiometerChipSelect[2] = GPIOD_5; + boardConfiguration->digitalPotentiometerChipSelect[3] = GPIO_NONE; } void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2) { /** * 720 is the range for four stroke */ - engineConfiguration2->crankAngleRange = 720; +// engineConfiguration2->crankAngleRange = 720; - engineConfiguration2->hasMapSensor = TRUE; - engineConfiguration2->hasCltSensor = TRUE; } void resetConfigurationExt(Logging * logger, engine_type_e engineType, engine_configuration_s *engineConfiguration, @@ -388,7 +382,7 @@ void resetConfigurationExt(Logging * logger, engine_type_e engineType, engine_co break; #endif case HONDA_ACCORD: - setHondaAccordConfiguration(engineConfiguration); + setHondaAccordConfiguration(engineConfiguration, boardConfiguration); break; #if EFI_SUPPORT_1995_FORD_INLINE_6 || defined(__DOXYGEN__) case FORD_INLINE_6_1995: @@ -424,7 +418,7 @@ void resetConfigurationExt(Logging * logger, engine_type_e engineType, engine_co firmwareError("Unexpected engine type: %d", engineType); } - applyNonPersistentConfiguration(logger, engineConfiguration, engineConfiguration2, engineType); + applyNonPersistentConfiguration(logger, engineConfiguration, engineConfiguration2); #if EFI_TUNER_STUDIO syncTunerStudioCopy(); @@ -435,17 +429,17 @@ engine_configuration2_s::engine_configuration2_s() { } void applyNonPersistentConfiguration(Logging * logger, engine_configuration_s *engineConfiguration, - engine_configuration2_s *engineConfiguration2, engine_type_e engineType) { + engine_configuration2_s *engineConfiguration2) { // todo: this would require 'initThermistors() to re-establish a reference, todo: fix // memset(engineConfiguration2, 0, sizeof(engine_configuration2_s)); #if EFI_PROD_CODE - printMsg(logger, "applyNonPersistentConfiguration()"); + scheduleMsg(logger, "applyNonPersistentConfiguration()"); #endif engineConfiguration2->isInjectionEnabledFlag = TRUE; initializeTriggerShape(logger, engineConfiguration, engineConfiguration2); if (engineConfiguration2->triggerShape.getSize() == 0) { - firmwareError("size is zero"); + firmwareError("triggerShape size is zero"); return; } if (engineConfiguration2->triggerShape.shaftPositionEventCount == 0) { diff --git a/firmware/controllers/algo/engine_configuration.h b/firmware/controllers/algo/engine_configuration.h index e4e249a836..86b5b2dcef 100644 --- a/firmware/controllers/algo/engine_configuration.h +++ b/firmware/controllers/algo/engine_configuration.h @@ -92,15 +92,15 @@ typedef struct { typedef struct { trigger_type_e triggerType; - int isSynchronizationNeeded; + int customIsSynchronizationNeeded; - int totalToothCount; - int skippedToothCount; + int customTotalToothCount; + int customSkippedToothCount; - float syncRatioFrom; - float syncRatioTo; + float customSyncRatioFrom; + float customSyncRatioTo; - int useRiseEdge; + int customUseRiseEdge; } trigger_config_s; @@ -150,7 +150,7 @@ typedef struct { * Digital Potentiometer is used by stock ECU stimulation code */ spi_device_e digitalPotentiometerSpiDevice; - brain_pin_e digitalPotentiometerChipSelect[4]; + brain_pin_e digitalPotentiometerChipSelect[DIGIPOT_COUNT]; adc_channel_mode_e adcHwChannelEnabled[HW_MAX_ADC_INDEX]; @@ -335,7 +335,7 @@ typedef struct { trigger_config_s triggerConfig; - int needSecondTriggerInput; + int space; int vBattAdcChannel; float globalFuelCorrection; @@ -370,6 +370,10 @@ typedef struct { board_configuration_s bc; + int hasMapSensor; + int hasCltSensor; + + } engine_configuration_s; void setOperationMode(engine_configuration_s *engineConfiguration, operation_mode_e mode); @@ -396,9 +400,6 @@ void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value); void setConstantDwell(engine_configuration_s *engineConfiguration, float dwellMs); void printFloatArray(const char *prefix, float array[], int size); -void setTriggerSynchronizationGap(trigger_config_s *triggerConfig, float synchGap); -void setToothedWheelConfiguration(engine_configuration_s *engineConfiguration, int total, int skipped); - void incrementGlobalConfigurationVersion(void); int getGlobalConfigurationVersion(void); diff --git a/firmware/controllers/algo/fuel_math.cpp b/firmware/controllers/algo/fuel_math.cpp index d0d3c78688..33270acb93 100644 --- a/firmware/controllers/algo/fuel_math.cpp +++ b/firmware/controllers/algo/fuel_math.cpp @@ -36,10 +36,12 @@ #include "allsensors.h" #include "engine_math.h" #include "rpm_calculator.h" +#include "speed_density.h" #if EFI_ACCEL_ENRICHMENT #include "accel_enrichment.h" #endif /* EFI_ACCEL_ENRICHMENT */ +extern Engine engine; extern engine_configuration_s *engineConfiguration; static Map3D1616 fuelMap; @@ -83,7 +85,16 @@ float getInjectorLag(float vBatt) { return engineConfiguration->injectorLag + vBattCorrection; } -float getBaseFuel(int rpm, float engineLoad) { +float getBaseFuel(Engine *engine, int rpm) { + if (engine->engineConfiguration->algorithm == LM_SPEED_DENSITY) { + return getSpeedDensityFuel(engine, rpm); + } else { + float engineLoad = getEngineLoadT(engine); + return getBaseTableFuel(rpm, engineLoad); + } +} + +float getBaseTableFuel(int rpm, float engineLoad) { efiAssert(!cisnan(engineLoad), "invalid el", NAN); return fuelMap.getValue(engineLoad, engineConfiguration->fuelLoadBins, rpm, engineConfiguration->fuelRpmBins); @@ -96,22 +107,17 @@ float getCrankingFuel(void) { /** * @returns Length of fuel injection, in milliseconds */ -float getFuelMs(int rpm) { +float getFuelMs(int rpm, Engine *engine) { if (isCranking()) { return getCrankingFuel(); } else { - float fuel = getRunningFuel(rpm, getEngineLoad()); + float baseFuel = getBaseFuel(engine, rpm); + float fuel = getRunningFuel(baseFuel, engine, rpm); return fuel; } } -float getRunningFuel(int rpm, float engineLoad) { - if (cisnan(engineLoad)) { - // the warning message should be already produced by the sensor decoder - return NAN; - } - float baseFuel = getBaseFuel(rpm, engineLoad); - +float getRunningFuel(float baseFuel, Engine *engine, int rpm) { float iatCorrection = getIatCorrection(getIntakeAirTemperature()); float cltCorrection = getCltCorrection(getCoolantTemperature()); float injectorLag = getInjectorLag(getVBatt()); diff --git a/firmware/controllers/algo/fuel_math.h b/firmware/controllers/algo/fuel_math.h index fa877e9560..80b5a8ecf9 100644 --- a/firmware/controllers/algo/fuel_math.h +++ b/firmware/controllers/algo/fuel_math.h @@ -13,15 +13,18 @@ extern "C" { #endif /* __cplusplus */ +#include "engine.h" + void prepareFuelMap(void); -float getBaseFuel(int rpm, float engineLoad); +float getBaseFuel(Engine *engine, int rpm); +float getBaseTableFuel(int rpm, float engineLoad); float getIatCorrection(float iat); float getInjectorLag(float vBatt); float getCltCorrection(float clt); -float getRunningFuel(int rpm, float engineLoad); +float getRunningFuel(float baseFuel, Engine *engine, int rpm); float getStartingFuel(float coolantTemperature); -float getFuelMs(int rpm); +float getFuelMs(int rpm, Engine *engine); #ifdef __cplusplus } diff --git a/firmware/controllers/algo/main_trigger_callback.h b/firmware/controllers/algo/main_trigger_callback.h index 3e63f35eb5..bb9949e6dc 100644 --- a/firmware/controllers/algo/main_trigger_callback.h +++ b/firmware/controllers/algo/main_trigger_callback.h @@ -19,16 +19,19 @@ #include "engine_configuration.h" #include "ec2.h" #include "event_registry.h" +#include "engine.h" + class MainTriggerCallback { public: // MainTriggerCallback(); - void init(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2); + void init(Engine *engine, engine_configuration2_s *engineConfiguration2); + Engine *engine; engine_configuration_s *engineConfiguration; engine_configuration2_s *engineConfiguration2; }; -void initMainEventListener(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2); +void initMainEventListener(Engine *engine, engine_configuration2_s *engineConfiguration2); void onTriggerEvent(trigger_event_e ckpSignalType, int eventIndex, MainTriggerCallback *mainTriggerCallback); #endif diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 45fd936bd3..07d469be49 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -17,6 +17,8 @@ // this is about offsets and sizes in TunerStudio #define ENUM_SIZE_HACK 2000000000 +#define DIGIPOT_COUNT 4 + typedef enum { AUDI_AAN = 1, #if EFI_SUPPORT_DODGE_NEON @@ -80,7 +82,8 @@ typedef enum { TT_GM_7X = 5, TT_MINI_COOPER_R50 = 6, TT_FORD_ESCORT_GT = 7, - TT_TT_TOOTHED_WHEEL_60_2 = 8, + TT_TOOTHED_WHEEL_60_2 = 8, + TT_TOOTHED_WHEEL_36_1 = 9, Internal_ForceMyEnumIntSize_trigger_type = ENUM_SIZE_HACK, } trigger_type_e; @@ -228,6 +231,8 @@ typedef enum { SPI_NONE = 0, SPI_DEVICE_1 = 1, SPI_DEVICE_2 = 2, + SPI_DEVICE_3 = 3, + SPI_DEVICE_4 = 4, Internal_ForceMyEnumIntSize_spi_device = ENUM_SIZE_HACK, } spi_device_e; @@ -337,6 +342,7 @@ typedef enum { MT_CUSTOM = 0, MT_DENSO183 = 1, MT_MPX4250 = 2, + MT_HONDA3BAR = 3, Internal_ForceMyEnumIntSize_cranking_map_type = ENUM_SIZE_HACK, } air_pressure_sensor_type_e; diff --git a/firmware/controllers/algo/signal_executor.c b/firmware/controllers/algo/signal_executor.c index 9adc1b8814..eb966bba0f 100644 --- a/firmware/controllers/algo/signal_executor.c +++ b/firmware/controllers/algo/signal_executor.c @@ -115,8 +115,8 @@ void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs) { scheduling_s * sUp = &signal->signalTimerUp[index]; scheduling_s * sDown = &signal->signalTimerDown[index]; - scheduleTask(sUp, (int)MS2US(delayMs), (schfunc_t) &turnPinHigh, (void *) signal->io_pin); - scheduleTask(sDown, (int)MS2US(delayMs + durationMs), (schfunc_t) &turnPinLow, (void*) signal->io_pin); + scheduleTask("out up", sUp, (int)MS2US(delayMs), (schfunc_t) &turnPinHigh, (void *) signal->io_pin); + scheduleTask("out down", sDown, (int)MS2US(delayMs + durationMs), (schfunc_t) &turnPinLow, (void*) signal->io_pin); } const char *getPinName(io_pin_e io_pin) { diff --git a/firmware/controllers/core/table_helper.h b/firmware/controllers/core/table_helper.h index 5eee3266d1..58998ac7e0 100644 --- a/firmware/controllers/core/table_helper.h +++ b/firmware/controllers/core/table_helper.h @@ -33,13 +33,13 @@ void Map3D::init(float table[RPM_BIN_SIZE][LOAD_BIN template float Map3D::getValue(float x, float xBin[], float y, float yBin[]) { - efiAssert(initialized == MAGIC_TRUE_VALUE, "map initialized", NAN); + efiAssert(initialized == MAGIC_TRUE_VALUE, "map not initialized", NAN); return interpolate3d(x, xBin, LOAD_BIN_SIZE, y, yBin, RPM_BIN_SIZE, pointers); } template void Map3D::setAll(float value) { - efiAssertVoid(initialized == MAGIC_TRUE_VALUE, "map initialized"); + efiAssertVoid(initialized == MAGIC_TRUE_VALUE, "map not initialized"); for (int l = 0; l < LOAD_BIN_SIZE; l++) { for (int r = 0; r < RPM_BIN_SIZE; r++) { pointers[l][r] = value; diff --git a/firmware/controllers/engine_controller.cpp b/firmware/controllers/engine_controller.cpp index fe964b26c8..7e591904df 100644 --- a/firmware/controllers/engine_controller.cpp +++ b/firmware/controllers/engine_controller.cpp @@ -156,6 +156,8 @@ static void onEvenyGeneralMilliseconds(void *arg) { */ halTime.get(hal_lld_get_counter_value(), true); + engine.updateSlowSensors(); + updateErrorCodes(); fanRelayControl(); @@ -236,6 +238,8 @@ void initEngineContoller(void) { return; initLogging(&logger, "Engine Controller"); + engine.engineConfiguration = engineConfiguration; + initSensors(); initPwmGenerator(); @@ -289,7 +293,7 @@ void initEngineContoller(void) { /** * This method initialized the main listener which actually runs injectors & ignition */ - initMainEventListener(engineConfiguration, engineConfiguration2); + initMainEventListener(&engine, engineConfiguration2); #endif /* EFI_ENGINE_CONTROL */ #if EFI_IDLE_CONTROL diff --git a/firmware/controllers/flash_main.cpp b/firmware/controllers/flash_main.cpp index 6af3a630bc..b286fa6dd1 100644 --- a/firmware/controllers/flash_main.cpp +++ b/firmware/controllers/flash_main.cpp @@ -57,13 +57,13 @@ void writeToFlash(void) { scheduleMsg(&logger, "flash compatible with %d", persistentState.version); crc_t result = flashStateCrc(&persistentState); persistentState.value = result; - scheduleMsg(&logger, "Reseting flash, size=%d", PERSISTENT_SIZE); + scheduleMsg(&logger, "Reseting flash: size=%d", PERSISTENT_SIZE); flashErase(FLASH_ADDR, PERSISTENT_SIZE); scheduleMsg(&logger, "Flashing with CRC=%d", result); efitimems_t nowMs = currentTimeMillis(); result = flashWrite(FLASH_ADDR, (const char *) &persistentState, PERSISTENT_SIZE); scheduleMsg(&logger, "Flash programmed in (ms): %d", currentTimeMillis() - nowMs); - scheduleMsg(&logger, "Flashed: %d", result); + scheduleMsg(&logger, "Flashing result: %d", result); #endif /* EFI_INTERNAL_FLASH */ } @@ -97,8 +97,7 @@ void readFromFlash(void) { boardConfiguration); } else { printMsg(&logger, "Got valid configuration from flash!"); - applyNonPersistentConfiguration(&logger, engineConfiguration, engineConfiguration2, - engineConfiguration->engineType); + applyNonPersistentConfiguration(&logger, engineConfiguration, engineConfiguration2); } // we can only change the state after the CRC check engineConfiguration->firmwareVersion = getRusEfiVersion(); diff --git a/firmware/controllers/flash_main.h b/firmware/controllers/flash_main.h index 1e127034eb..a28338d5c2 100644 --- a/firmware/controllers/flash_main.h +++ b/firmware/controllers/flash_main.h @@ -11,7 +11,7 @@ #include "engine_configuration.h" -#define FLASH_DATA_VERSION 3880 +#define FLASH_DATA_VERSION 3975 #ifdef __cplusplus extern "C" diff --git a/firmware/controllers/ignition_central.c b/firmware/controllers/ignition_central.c index 9a5668a5a5..bd03bf4e5d 100644 --- a/firmware/controllers/ignition_central.c +++ b/firmware/controllers/ignition_central.c @@ -35,7 +35,7 @@ void initIgnitionCentral(void) { initLogging(&logger, "IgnitionCentral"); for (int i = 0; i < engineConfiguration->cylindersCount; i++) { - io_pin_e pin = (io_pin_e)((int)INJECTOR_1_OUTPUT + i); + io_pin_e pin = (io_pin_e)((int)SPARKOUT_1_OUTPUT + i); outputPinRegisterExt2(getPinName(pin), pin, boardConfiguration->ignitionPins[i], &boardConfiguration->ignitionPinMode); } } diff --git a/firmware/controllers/map_averaging.cpp b/firmware/controllers/map_averaging.cpp index ef8c88c8b5..f3b2f8aaab 100644 --- a/firmware/controllers/map_averaging.cpp +++ b/firmware/controllers/map_averaging.cpp @@ -37,7 +37,6 @@ #include "analog_chart.h" #endif /* EFI_ANALOG_CHART */ - #define FAST_MAP_CHART_SKIP_FACTOR 16 static Logging logger; @@ -73,12 +72,13 @@ static scheduling_s startTimer[2]; static scheduling_s endTimer[2]; static void startAveraging(void*arg) { - chSysLockFromIsr() + bool wasLocked = lockAnyContext(); ; // with locking we would have a consistent state v_mapAccumulator = 0; mapMeasurementsCounter = 0; - chSysUnlockFromIsr() + if (!wasLocked) + chSysUnlockFromIsr() ; } @@ -111,11 +111,11 @@ void mapAveragingCallback(adcsample_t value) { } static void endAveraging(void *arg) { - chSysLockFromIsr() - ; + bool wasLocked = lockAnyContext(); // with locking we would have a consistent state v_averagedMapValue = v_mapAccumulator / mapMeasurementsCounter; - chSysUnlockFromIsr() + if (!wasLocked) + chSysUnlockFromIsr() ; } @@ -129,7 +129,7 @@ static void shaftPositionCallback(trigger_event_e ckpEventType, int index, void return; int rpm = getRpm(); - if(!isValidRpm(rpm)) + if (!isValidRpm(rpm)) return; perRevolution = perRevolutionCounter; @@ -139,6 +139,10 @@ static void shaftPositionCallback(trigger_event_e ckpEventType, int index, void float startAngle = interpolate2d(rpm, config->samplingAngleBins, config->samplingAngle, MAP_ANGLE_SIZE); float windowAngle = interpolate2d(rpm, config->samplingWindowBins, config->samplingWindow, MAP_WINDOW_SIZE); + if (windowAngle <= 0) { + firmwareError("map sampling angle should be positive"); + return; + } int structIndex = getRevolutionCounter() % 2; // todo: schedule this based on closest trigger event, same as ignition works @@ -172,7 +176,6 @@ void initMapAveraging(void) { endTimer[0].name = "map end0"; endTimer[1].name = "map end1"; - addTriggerEventListener(&shaftPositionCallback, "rpm reporter", NULL); addConsoleAction("faststat", showMapStats); } diff --git a/firmware/controllers/math/engine_math.cpp b/firmware/controllers/math/engine_math.cpp index aa9b7d12dc..a75065c22f 100644 --- a/firmware/controllers/math/engine_math.cpp +++ b/firmware/controllers/math/engine_math.cpp @@ -76,17 +76,19 @@ float fixAngle(float angle) { * @brief Returns engine load according to selected engine_load_mode * */ -float getEngineLoadT(engine_configuration_s *engineConfiguration) { +float getEngineLoadT(Engine *engine) { + efiAssert(engine!=NULL, "engine 2NULL", NAN); + engine_configuration_s *engineConfiguration = engine->engineConfiguration; + efiAssert(engineConfiguration!=NULL, "engineConfiguration 2NULL", NAN); switch (engineConfiguration->algorithm) { case LM_MAF: - return getMaf(); + return getMafT(engineConfiguration); + case LM_SPEED_DENSITY: + // SD engine load is used for timing lookup but not for fuel calculation case LM_MAP: return getMap(); case LM_TPS: return getTPS(); - case LM_SPEED_DENSITY: - // TODO: real implementation - return getMap(); default: firmwareError("Unexpected engine load parameter: %d", engineConfiguration->algorithm); return -1; diff --git a/firmware/controllers/math/engine_math.h b/firmware/controllers/math/engine_math.h index 6a2409535d..61fcbbfc0c 100644 --- a/firmware/controllers/math/engine_math.h +++ b/firmware/controllers/math/engine_math.h @@ -14,6 +14,7 @@ #include "ec2.h" #include "trigger_structure.h" #include "table_helper.h" +#include "engine.h" void findTriggerPosition(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, event_trigger_position_s *position, float angleOffset); @@ -38,8 +39,8 @@ float getCrankshaftRevolutionTimeMs(int rpm); int isCrankingRT(engine_configuration_s *engineConfiguration, int rpm); #define isCrankingR(rpm) isCrankingRT(engineConfiguration, rpm) -float getEngineLoadT(engine_configuration_s *engineConfiguration); -#define getEngineLoad() getEngineLoadT(engineConfiguration) +float getEngineLoadT(Engine *engine); +#define getEngineLoad() getEngineLoadT(&engine) float getSparkDwellMsT(engine_configuration_s *engineConfiguration, int rpm); #define getSparkDwellMs(rpm) getSparkDwellMsT(engineConfiguration, rpm) diff --git a/firmware/controllers/math/speed_density.cpp b/firmware/controllers/math/speed_density.cpp index afbd26631a..e29549f650 100644 --- a/firmware/controllers/math/speed_density.cpp +++ b/firmware/controllers/math/speed_density.cpp @@ -8,7 +8,6 @@ #include "main.h" #include "speed_density.h" #include "interpolation.h" -#include "engine.h" #include "rpm_calculator.h" #include "engine_math.h" #include "engine_state.h" @@ -49,6 +48,11 @@ float getTCharge(int rpm, int tps, float coolantTemp, float airTemp) { * @return value in seconds */ float sdMath(engine_configuration_s *engineConfiguration, float VE, float MAP, float AFR, float temp) { + if (MAP < 0.001 || cisnan(MAP)) { + warning(OBD_PCM_Processor_Fault, "invalid MAP value"); + return 0; + } + float injectorFlowRate = cc_minute_to_gramm_second(engineConfiguration->injectorFlow); float Vol = engineConfiguration->displacement / engineConfiguration->cylindersCount; return (Vol * VE * MAP) / (AFR * injectorFlowRate * GAS_R * temp); @@ -57,8 +61,8 @@ float sdMath(engine_configuration_s *engineConfiguration, float VE, float MAP, f /** * @return value in Milliseconds */ -float getSpeedDensityFuel(Engine *engine) { - int rpm = engine->rpmCalculator->rpm(); +float getSpeedDensityFuel(Engine *engine, int rpm) { + //int rpm = engine->rpmCalculator->rpm(); engine_configuration_s *engineConfiguration = engine->engineConfiguration; diff --git a/firmware/controllers/math/speed_density.h b/firmware/controllers/math/speed_density.h index c612d2cda7..980ea65ee4 100644 --- a/firmware/controllers/math/speed_density.h +++ b/firmware/controllers/math/speed_density.h @@ -9,6 +9,7 @@ #include "engine_configuration.h" #include "ec2.h" +#include "engine.h" float getTCharge(int rpm, int tps, float coolantTemp, float airTemp); void setDetaultVETable(engine_configuration_s *engineConfiguration); @@ -20,5 +21,6 @@ float sdMath(engine_configuration_s *engineConfiguration, float VE, float MAP, f void setDetaultVETable(engine_configuration_s *engineConfiguration); void initSpeedDensity(engine_configuration_s *engineConfiguration); +float getSpeedDensityFuel(Engine *engine, int rpm); #endif /* SPEED_DENSITY_H_ */ diff --git a/firmware/controllers/sensors/allsensors.h b/firmware/controllers/sensors/allsensors.h index 01c464a2c1..cbdc88845c 100644 --- a/firmware/controllers/sensors/allsensors.h +++ b/firmware/controllers/sensors/allsensors.h @@ -19,6 +19,11 @@ #include "ego.h" #include "voltage.h" #include "thermistors.h" +#include "adc_inputs.h" + +#if EFI_PROD_CODE || EFI_SIMULATOR +#include "adc_math.h" +#endif #ifdef __cplusplus diff --git a/firmware/controllers/sensors/maf.c b/firmware/controllers/sensors/maf.c index 660582a6a7..65e30f251a 100644 --- a/firmware/controllers/sensors/maf.c +++ b/firmware/controllers/sensors/maf.c @@ -2,9 +2,10 @@ #include "boards.h" #include "engine_configuration.h" #include "adc_inputs.h" +#include "maf.h" extern engine_configuration_s *engineConfiguration; float getMaf(void) { - return getVoltageDivided(engineConfiguration->mafAdcChannel); + return getMafT(engineConfiguration); } diff --git a/firmware/controllers/sensors/maf.h b/firmware/controllers/sensors/maf.h index 69d6a08c7b..ba833ddbfc 100644 --- a/firmware/controllers/sensors/maf.h +++ b/firmware/controllers/sensors/maf.h @@ -17,6 +17,8 @@ extern "C" { #endif /* __cplusplus */ +#define getMafT(ec) (getVoltageDivided(ec->mafAdcChannel)) + float getMaf(void); #ifdef __cplusplus diff --git a/firmware/controllers/sensors/map.cpp b/firmware/controllers/sensors/map.cpp index c1199c6c83..6ea32eb324 100644 --- a/firmware/controllers/sensors/map.cpp +++ b/firmware/controllers/sensors/map.cpp @@ -18,6 +18,9 @@ extern engine_configuration_s * engineConfiguration; */ static FastInterpolation denso183(0, -6.64, 5, 182.78); +// todo: figure out real values +static FastInterpolation honda3bar(0.32, -95.8371264, 4.84, 300); + static FastInterpolation mpx4250(0, 8, 5, 260); float decodePressure(float voltage, air_pressure_sensor_config_s * config) { @@ -29,6 +32,8 @@ float decodePressure(float voltage, air_pressure_sensor_config_s * config) { return denso183.getValue(voltage); case MT_MPX4250: return mpx4250.getValue(voltage); + case MT_HONDA3BAR: + return honda3bar.getValue(voltage); default: firmwareError("Unknown MAP type: %d", config->sensorType); return NAN; diff --git a/firmware/controllers/settings.cpp b/firmware/controllers/settings.cpp index 5fd3bfb01d..ee23cc16f8 100644 --- a/firmware/controllers/settings.cpp +++ b/firmware/controllers/settings.cpp @@ -125,7 +125,7 @@ static const char * boolToString(bool value) { */ void printConfiguration(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2) { - scheduleMsg(&logger, getConfigurationName(engineConfiguration)); + scheduleMsg(&logger, "Template %s trigger %d", getConfigurationName(engineConfiguration), engineConfiguration->triggerConfig.triggerType); scheduleMsg(&logger, "configurationVersion=%d", getGlobalConfigurationVersion()); @@ -172,10 +172,11 @@ void printConfiguration(engine_configuration_s *engineConfiguration, engine_conf // scheduleMsg(&logger, "crankingRpm: %d", engineConfiguration->crankingSettings.crankingRpm); scheduleMsg(&logger, "idlePinMode: %s", pinModeToString(boardConfiguration->idleValvePinMode)); - scheduleMsg(&logger, "malfunctionIndicatorPinMode: %s", pinModeToString(boardConfiguration->malfunctionIndicatorPinMode)); + scheduleMsg(&logger, "malfunctionIndicatorPinMode: %s", + pinModeToString(boardConfiguration->malfunctionIndicatorPinMode)); scheduleMsg(&logger, "analogInputDividerCoefficient: %f", engineConfiguration->analogInputDividerCoefficient); - scheduleMsg(&logger, "needSecondTriggerInput: %s", boolToString(engineConfiguration->needSecondTriggerInput)); + scheduleMsg(&logger, "needSecondTriggerInput: %s", boolToString(engineConfiguration2->triggerShape.needSecondTriggerInput)); #if EFI_PROD_CODE scheduleMsg(&logger, "idleValvePin: %s", hwPortname(boardConfiguration->idleValvePin)); @@ -204,12 +205,15 @@ void printConfiguration(engine_configuration_s *engineConfiguration, engine_conf scheduleMsg(&logger, "primary trigger input: %s", hwPortname(boardConfiguration->primaryTriggerInputPin)); scheduleMsg(&logger, "boardTestModeJumperPin: %s", hwPortname(boardConfiguration->boardTestModeJumperPin)); + + scheduleMsg(&logger, "digitalPotentiometerSpiDevice %d", boardConfiguration->digitalPotentiometerSpiDevice); + + for (int i = 0; i < DIGIPOT_COUNT; i++) { + scheduleMsg(&logger, "digitalPotentiometer CS%d %s", i, hwPortname(boardConfiguration->digitalPotentiometerChipSelect[i])); + } #endif /* EFI_PROD_CODE */ scheduleMsg(&logger, "isInjectionEnabledFlag %s", boolToString(engineConfiguration2->isInjectionEnabledFlag)); - - // appendPrintf(&logger, DELIMETER); -// scheduleLogging(&logger); } static void setFixedModeTiming(int value) { @@ -369,6 +373,11 @@ static void setCrankingRpm(int value) { doPrintConfiguration(); } +static void setAlgorithm(int value) { + engineConfiguration->algorithm = (engine_load_mode_e) value; + doPrintConfiguration(); +} + static void setFiringOrder(int value) { engineConfiguration->firingOrder = (firing_order_e) value; doPrintConfiguration(); @@ -415,9 +424,15 @@ static void setIgnitionMode(int value) { doPrintConfiguration(); } +static void setTriggerType(int value) { + engineConfiguration->triggerConfig.triggerType = (trigger_type_e)value; + incrementGlobalConfigurationVersion(); + doPrintConfiguration(); +} + static void setToothedWheel(int total, int skipped) { - setToothedWheelConfiguration(engineConfiguration, total, skipped); - initializeTriggerShape(&logger, engineConfiguration, engineConfiguration2); + setToothedWheelConfiguration(&engineConfiguration2->triggerShape, total, skipped, engineConfiguration); +// initializeTriggerShape(&logger, engineConfiguration, engineConfiguration2); incrementGlobalConfigurationVersion(); doPrintConfiguration(); } @@ -436,6 +451,7 @@ static void setGlobalFuelCorrection(float value) { } static void setWholeTimingMap(float value) { + // todo: table helper? scheduleMsg(&logger, "Setting whole timing map to %f", value); for (int l = 0; l < IGN_LOAD_COUNT; l++) { for (int r = 0; r < IGN_RPM_COUNT; r++) { @@ -549,9 +565,11 @@ void initSettings(void) { addConsoleActionI("set_rpm_hard_limit", setRpmHardLimit); addConsoleActionI("set_firing_order", setFiringOrder); + addConsoleActionI("set_algorithm", setAlgorithm); addConsoleAction("enable_injection", enableInjection); addConsoleAction("disable_injection", disableInjection); addConsoleActionII("set_toothed_wheel", setToothedWheel); + addConsoleActionI("set_trigger_type", setTriggerType); } diff --git a/firmware/controllers/system/SingleTimerExecutor.cpp b/firmware/controllers/system/SingleTimerExecutor.cpp index a198935186..078e4af04a 100644 --- a/firmware/controllers/system/SingleTimerExecutor.cpp +++ b/firmware/controllers/system/SingleTimerExecutor.cpp @@ -96,8 +96,11 @@ void Executor::doExecute(uint64_t nowUs) { * @param [in] delayUs the number of microseconds before the output signal immediate output if delay is zero. * @param [in] dwell the number of ticks of output duration. */ -void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) { - efiAssertVoid(delayUs >= 0, "Negative delayUs"); +void scheduleTask(const char *prefix, scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) { + if (delayUs < 0) { + firmwareError("Negative delayUs %s: %d", prefix, delayUs); + return; + } if (delayUs == 0) { callback(param); return; diff --git a/firmware/controllers/system/pwm_generator_logic.cpp b/firmware/controllers/system/pwm_generator_logic.cpp index 5a65515ad6..57703a54a4 100644 --- a/firmware/controllers/system/pwm_generator_logic.cpp +++ b/firmware/controllers/system/pwm_generator_logic.cpp @@ -47,16 +47,16 @@ static uint64_t getNextSwitchTimeUs(PwmConfig *state) { efiAssert(state->safe.phaseIndex < PWM_PHASE_MAX_COUNT, "phaseIndex range", 0); int iteration = state->safe.iteration; float switchTime = state->multiWave.getSwitchTime(state->safe.phaseIndex); - float periodMs = state->safe.periodMs; + float periodUs = state->safe.periodUs; #if DEBUG_PWM scheduleMsg(&logger, "iteration=%d switchTime=%f period=%f", iteration, switchTime, period); #endif /** - * todo: once 'iteration' gets relatively high, we might lose calculation precision here - * todo: double-check this spot + * Once 'iteration' gets relatively high, we might lose calculation precision here. + * This is addressed by ITERATION_LIMIT */ - uint64_t timeToSwitchUs = (iteration + switchTime) * periodMs * 1000; + uint64_t timeToSwitchUs = (iteration + switchTime) * periodUs; #if DEBUG_PWM scheduleMsg(&logger, "start=%d timeToSwitch=%d", state->safe.start, timeToSwitch); @@ -64,6 +64,25 @@ static uint64_t getNextSwitchTimeUs(PwmConfig *state) { return state->safe.startUs + timeToSwitchUs; } +void PwmConfig::handleCycleStart() { + if (safe.phaseIndex == 0) { + if (cycleCallback != NULL) + cycleCallback(this); + efiAssertVoid(periodUs != 0, "period not initialized"); + if (safe.periodUs != periodUs || safe.iteration == ITERATION_LIMIT) { + /** + * period length has changed - we need to reset internal state + */ + safe.startUs = getTimeNowUs(); + safe.iteration = 0; + safe.periodUs = periodUs; +#if DEBUG_PWM + scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration); +#endif + } + } +} + /** * @return Next time for signal toggle */ @@ -73,31 +92,21 @@ static uint64_t togglePwmState(PwmConfig *state) { scheduleMsg(&logger, "state->period=%f state->safe.period=%f", state->period, state->safe.period); #endif - if (state->safe.phaseIndex == 0) { - if (cisnan(state->periodMs)) { - /** - * zero period means PWM is paused - */ - return 1; - } - if (state->cycleCallback != NULL) - state->cycleCallback(state); - efiAssert(state->periodMs != 0, "period not initialized", 0); - if (state->safe.periodMs != state->periodMs || state->safe.iteration == ITERATION_LIMIT) { - /** - * period length has changed - we need to reset internal state - */ - state->safe.startUs = getTimeNowUs(); - state->safe.iteration = 0; - state->safe.periodMs = state->periodMs; -#if DEBUG_PWM - scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration); -#endif - } + if (cisnan(state->periodUs)) { + /** + * zero period means PWM is paused + */ + return 1; } - state->stateChangeCallback(state, - state->safe.phaseIndex == 0 ? state->phaseCount - 1 : state->safe.phaseIndex - 1); + state->handleCycleStart(); + + /** + * Here is where the 'business logic' - the actual pin state change is happening + */ + // callback state index is offset by one. todo: why? can we simplify this? + int cbStateIndex = state->safe.phaseIndex == 0 ? state->phaseCount - 1 : state->safe.phaseIndex - 1; + state->stateChangeCallback(state, cbStateIndex); uint64_t nextSwitchTimeUs = getNextSwitchTimeUs(state); #if DEBUG_PWM @@ -106,8 +115,13 @@ static uint64_t togglePwmState(PwmConfig *state) { // signed value is needed here int64_t timeToSwitch = nextSwitchTimeUs - getTimeNowUs(); if (timeToSwitch < 1) { -//todo: introduce error and test this error handling warning(OBD_PCM_Processor_Fault, "PWM: negative switch time"); - timeToSwitch = 1000; + /** + * We are here if we are late for a state transition. + * At 12000RPM=200Hz with a 60 toothed wheel we need to change state every + * 1000000 / 200 / 120 = ~41 uS. We are kind of OK. + */ + //todo: introduce error and test this error handling warning(OBD_PCM_Processor_Fault, "PWM: negative switch time"); + timeToSwitch = 10; } state->safe.phaseIndex++; @@ -118,9 +132,12 @@ static uint64_t togglePwmState(PwmConfig *state) { return timeToSwitch; } +/** + * Main PWM loop: toggle pin & schedule next invocation + */ static void timerCallback(PwmConfig *state) { time_t timeToSleepUs = togglePwmState(state); - scheduleTask(&state->scheduling, timeToSleepUs, (schfunc_t) timerCallback, state); + scheduleTask("pwm", &state->scheduling, timeToSleepUs, (schfunc_t) timerCallback, state); } /** @@ -144,7 +161,7 @@ void copyPwmParameters(PwmConfig *state, int phaseCount, float *switchTimes, int void weComplexInit(const char *msg, PwmConfig *state, int phaseCount, float *switchTimes, int waveCount, int **pinStates, pwm_cycle_callback *cycleCallback, pwm_gen_callback *stateChangeCallback) { - efiAssertVoid(state->periodMs != 0, "period is not initialized"); + efiAssertVoid(state->periodUs != 0, "period is not initialized"); if (phaseCount == 0) { firmwareError("signal length cannot be zero"); return; @@ -168,9 +185,10 @@ void weComplexInit(const char *msg, PwmConfig *state, int phaseCount, float *swi state->stateChangeCallback = stateChangeCallback; state->safe.phaseIndex = 0; - state->safe.periodMs = -1; + state->safe.periodUs = -1; state->safe.iteration = -1; state->name = msg; + // let's start the indefinite callback loop of PWM generation timerCallback(state); } diff --git a/firmware/controllers/system/pwm_generator_logic.h b/firmware/controllers/system/pwm_generator_logic.h index 0ca582e7db..06da141c9b 100644 --- a/firmware/controllers/system/pwm_generator_logic.h +++ b/firmware/controllers/system/pwm_generator_logic.h @@ -18,7 +18,7 @@ typedef struct { * a copy so that all phases are executed on the same period, even if another thread * would be adjusting PWM parameters */ - float periodMs; + float periodUs; /** * Iteration counter */ @@ -43,6 +43,10 @@ public: PwmConfig(); PwmConfig(float *switchTimes, single_wave_s *waves); void init(float *switchTimes, single_wave_s *waves); + + void handleCycleStart(); + + io_pin_e outputPins[PWM_PHASE_MAX_WAVE_PER_PWM]; multi_wave_s multiWave; const char *name; @@ -50,7 +54,7 @@ public: * float value of PWM period * PWM generation is not happening while this value is zero */ - float periodMs; + float periodUs; scheduling_s scheduling; diff --git a/firmware/controllers/system/scheduler.h b/firmware/controllers/system/scheduler.h index 992795ba4e..4651924a44 100644 --- a/firmware/controllers/system/scheduler.h +++ b/firmware/controllers/system/scheduler.h @@ -29,7 +29,7 @@ extern "C" { #endif /* __cplusplus */ -void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param); +void scheduleTask(const char *prefix, scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param); #ifdef __cplusplus } diff --git a/firmware/controllers/system/signal_executor_sleep.c b/firmware/controllers/system/signal_executor_sleep.c index 51af8eef87..57151bf861 100644 --- a/firmware/controllers/system/signal_executor_sleep.c +++ b/firmware/controllers/system/signal_executor_sleep.c @@ -28,7 +28,7 @@ #if EFI_SIGNAL_EXECUTOR_SLEEP || defined(__DOXYGEN__) -void scheduleTask(scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) { +void scheduleTask(const char *prefix, scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) { int delaySt = delayUs * CH_FREQUENCY / 1000000; if (delaySt == 0) { /** diff --git a/firmware/controllers/trigger/main_trigger_callback.cpp b/firmware/controllers/trigger/main_trigger_callback.cpp index 06b4d9bf9f..4956477f33 100644 --- a/firmware/controllers/trigger/main_trigger_callback.cpp +++ b/firmware/controllers/trigger/main_trigger_callback.cpp @@ -78,7 +78,7 @@ static cyclic_buffer ignitionErrorDetection; static Logging logger; static void handleFuelInjectionEvent(MainTriggerCallback *mainTriggerCallback, ActuatorEvent *event, int rpm) { - float fuelMs = getFuelMs(rpm) * mainTriggerCallback->engineConfiguration->globalFuelCorrection; + float fuelMs = getFuelMs(rpm, mainTriggerCallback->engine) * mainTriggerCallback->engineConfiguration->globalFuelCorrection; if (cisnan(fuelMs)) { warning(OBD_PCM_Processor_Fault, "NaN injection pulse"); return; @@ -156,7 +156,7 @@ static void handleSparkEvent(MainTriggerCallback *mainTriggerCallback, int event /** * The start of charge is always within the current trigger event range, so just plain time-based scheduling */ - scheduleTask(sUp, (int) MS2US(sparkDelay), (schfunc_t) &turnPinHigh, (void *) iEvent->io_pin); + scheduleTask("spark up", sUp, (int) MS2US(sparkDelay), (schfunc_t) &turnPinHigh, (void *) iEvent->io_pin); /** * Spark event is often happening during a later trigger event timeframe * TODO: improve precision @@ -171,7 +171,7 @@ static void handleSparkEvent(MainTriggerCallback *mainTriggerCallback, int event */ float timeTillIgnitionUs = getOneDegreeTimeUs(rpm) * iEvent->sparkPosition.angleOffset; - scheduleTask(sDown, (int) timeTillIgnitionUs, (schfunc_t) &turnPinLow, (void*) iEvent->io_pin); + scheduleTask("spark 1down", sDown, (int) timeTillIgnitionUs, (schfunc_t) &turnPinLow, (void*) iEvent->io_pin); } else { /** * Spark should be scheduled in relation to some future trigger event, this way we get better firing precision @@ -204,7 +204,7 @@ static void handleSpark(MainTriggerCallback *mainTriggerCallback, int eventIndex scheduling_s * sDown = ¤t->signalTimerDown; float timeTillIgnitionUs = getOneDegreeTimeUs(rpm) * current->sparkPosition.angleOffset; - scheduleTask(sDown, (int) timeTillIgnitionUs, (schfunc_t) &turnPinLow, (void*) current->io_pin); + scheduleTask("spark 2down", sDown, (int) timeTillIgnitionUs, (schfunc_t) &turnPinLow, (void*) current->io_pin); } } @@ -276,7 +276,7 @@ void onTriggerEvent(trigger_event_e ckpSignalType, int eventIndex, MainTriggerCa firmwareError("invalid dwell: %f at %d", dwellMs, rpm); return; } - float advance = getAdvance(rpm, getEngineLoadT(mainTriggerCallback->engineConfiguration)); + float advance = getAdvance(rpm, getEngineLoadT(mainTriggerCallback->engine)); float dwellAngle = dwellMs / getOneDegreeTimeMs(rpm); @@ -293,7 +293,7 @@ void onTriggerEvent(trigger_event_e ckpSignalType, int eventIndex, MainTriggerCa #if EFI_HISTOGRAMS && EFI_PROD_CODE int diff = hal_lld_get_counter_value() - beforeCallback; if (diff > 0) - hsAdd(&mainLoopHisto, diff); + hsAdd(&mainLoopHisto, diff); #endif /* EFI_HISTOGRAMS */ } @@ -309,21 +309,26 @@ static void showTriggerHistogram(void) { static void showMainInfo(void) { int rpm = getRpm(); - float el = getEngineLoadT(mainTriggerCallbackInstance.engineConfiguration); + float el = getEngineLoadT(mainTriggerCallbackInstance.engine); #if EFI_PROD_CODE scheduleMsg(&logger, "rpm %d engine_load %f", rpm, el); - scheduleMsg(&logger, "fuel %fms timing %f", getFuelMs(rpm), getAdvance(rpm, el)); + scheduleMsg(&logger, "fuel %fms timing %f", getFuelMs(rpm, mainTriggerCallbackInstance.engine), getAdvance(rpm, el)); #endif } -void MainTriggerCallback::init(engine_configuration_s *engineConfiguration, - engine_configuration2_s *engineConfiguration2) { - this->engineConfiguration = engineConfiguration; +void MainTriggerCallback::init(Engine *engine, engine_configuration2_s *engineConfiguration2) { + efiAssertVoid(engine!=NULL, "engine NULL"); + this->engine = engine; + this->engineConfiguration = engine->engineConfiguration; + efiAssertVoid(engineConfiguration!=NULL, "engineConfiguration NULL"); this->engineConfiguration2 = engineConfiguration2; } -void initMainEventListener(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2) { - mainTriggerCallbackInstance.init(engineConfiguration, engineConfiguration2); +void initMainEventListener(Engine *engine, engine_configuration2_s *engineConfiguration2) { + efiAssertVoid(engine!=NULL, "null engine"); + engine_configuration_s *engineConfiguration = engine->engineConfiguration; + + mainTriggerCallbackInstance.init(engine, engineConfiguration2); #if EFI_PROD_CODE addConsoleAction("performanceinfo", showTriggerHistogram); @@ -332,7 +337,7 @@ void initMainEventListener(engine_configuration_s *engineConfiguration, engine_c initLogging(&logger, "main event handler"); printMsg(&logger, "initMainLoop: %d", currentTimeMillis()); if (!isInjectionEnabled(mainTriggerCallbackInstance.engineConfiguration2)) - printMsg(&logger, "!!!!!!!!!!!!!!!!!!! injection disabled"); + printMsg(&logger, "!!!!!!!!!!!!!!!!!!! injection disabled"); #endif #if EFI_HISTOGRAMS diff --git a/firmware/controllers/trigger/rpm_calculator.cpp b/firmware/controllers/trigger/rpm_calculator.cpp index f1209a22b1..874ff50b90 100644 --- a/firmware/controllers/trigger/rpm_calculator.cpp +++ b/firmware/controllers/trigger/rpm_calculator.cpp @@ -231,7 +231,7 @@ void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void firmwareError("NaN delay?"); return; } - scheduleTask(timer, (int)MS2US(delayMs), callback, param); + scheduleTask("by angle", timer, (int)MS2US(delayMs), callback, param); } #endif diff --git a/firmware/controllers/trigger/trigger_bmw.cpp b/firmware/controllers/trigger/trigger_bmw.cpp index 06b48feaa2..7798843874 100644 --- a/firmware/controllers/trigger/trigger_bmw.cpp +++ b/firmware/controllers/trigger/trigger_bmw.cpp @@ -15,8 +15,7 @@ static inline float addPair(trigger_shape_s *s, float a, float w) { return a; } -void configureMiniCooperTriggerShape(trigger_config_s *triggerConfig, - trigger_shape_s *s) { +void configureMiniCooperTriggerShape(trigger_shape_s *s) { s->reset(FOUR_STROKE_CAM_SENSOR); @@ -67,5 +66,5 @@ void configureMiniCooperTriggerShape(trigger_config_s *triggerConfig, /** * With just one tooth on camshaft synchronization is not needed */ - triggerConfig->isSynchronizationNeeded = FALSE; + s->isSynchronizationNeeded = FALSE; } diff --git a/firmware/controllers/trigger/trigger_bmw.h b/firmware/controllers/trigger/trigger_bmw.h index 29a8c4c4fd..5d0fe6fbf9 100644 --- a/firmware/controllers/trigger/trigger_bmw.h +++ b/firmware/controllers/trigger/trigger_bmw.h @@ -10,7 +10,6 @@ #include "engine_configuration.h" #include "ec2.h" -void configureMiniCooperTriggerShape(trigger_config_s *triggerConfig, - trigger_shape_s *s); +void configureMiniCooperTriggerShape(trigger_shape_s *s); #endif /* TRIGGER_BMW_H_ */ diff --git a/firmware/controllers/trigger/trigger_chrysler.cpp b/firmware/controllers/trigger/trigger_chrysler.cpp index 986e0b56a7..2ecffcfcab 100644 --- a/firmware/controllers/trigger/trigger_chrysler.cpp +++ b/firmware/controllers/trigger/trigger_chrysler.cpp @@ -7,9 +7,15 @@ #include "trigger_chrysler.h" -void configureNeonTriggerShape(trigger_config_s *triggerConfig, trigger_shape_s *s) { +void configureNeonTriggerShape(trigger_shape_s *s) { s->reset(FOUR_STROKE_CAM_SENSOR); + setTriggerSynchronizationGap(s, 0.72); + + s->useRiseEdge = false; + s->needSecondTriggerInput = true; + + // voodoo magic - we always need 720 at the end int base = 720 - 560; diff --git a/firmware/controllers/trigger/trigger_chrysler.h b/firmware/controllers/trigger/trigger_chrysler.h index 66fbf3bcfa..4cea93ce97 100644 --- a/firmware/controllers/trigger/trigger_chrysler.h +++ b/firmware/controllers/trigger/trigger_chrysler.h @@ -10,6 +10,6 @@ #include "trigger_structure.h" -void configureNeonTriggerShape(trigger_config_s *triggerConfig, trigger_shape_s *s); +void configureNeonTriggerShape(trigger_shape_s *s); #endif /* TRIGGER_CHRYSLER_H_ */ diff --git a/firmware/controllers/trigger/trigger_decoder.cpp b/firmware/controllers/trigger/trigger_decoder.cpp index d341766095..f71d8c0ef0 100644 --- a/firmware/controllers/trigger/trigger_decoder.cpp +++ b/firmware/controllers/trigger/trigger_decoder.cpp @@ -47,16 +47,16 @@ int isTriggerDecoderError(void) { static inline int isSynchronizationGap(TriggerState const *shaftPositionState, trigger_shape_s const *triggerShape, trigger_config_s const *triggerConfig, const int currentDuration) { - if (!triggerConfig->isSynchronizationNeeded) + if (!triggerShape->isSynchronizationNeeded) return false; - return currentDuration > shaftPositionState->toothed_previous_duration * triggerConfig->syncRatioFrom - && currentDuration < shaftPositionState->toothed_previous_duration * triggerConfig->syncRatioTo; + return currentDuration > shaftPositionState->toothed_previous_duration * triggerShape->syncRatioFrom + && currentDuration < shaftPositionState->toothed_previous_duration * triggerShape->syncRatioTo; } static inline int noSynchronizationResetNeeded(TriggerState *shaftPositionState, trigger_shape_s const *triggerShape, trigger_config_s const*triggerConfig) { - if (triggerConfig->isSynchronizationNeeded) + if (triggerShape->isSynchronizationNeeded) return false; if (!shaftPositionState->shaft_is_synchronized) return TRUE; @@ -73,8 +73,8 @@ static inline int noSynchronizationResetNeeded(TriggerState *shaftPositionState, void TriggerState::decodeTriggerEvent(trigger_shape_s const*triggerShape, trigger_config_s const*triggerConfig, trigger_event_e signal, uint64_t nowUs) { - int isLessImportant = (triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_UP) - || (!triggerConfig->useRiseEdge && signal != SHAFT_PRIMARY_DOWN); + int isLessImportant = (triggerShape->useRiseEdge && signal != SHAFT_PRIMARY_UP) + || (!triggerShape->useRiseEdge && signal != SHAFT_PRIMARY_DOWN); if (isLessImportant) { /** @@ -139,11 +139,12 @@ static void initializeSkippedToothTriggerShape(trigger_shape_s *s, int totalTeet s->addEvent(720, T_PRIMARY, TV_LOW); } -void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfiguration2, int totalTeethCount, +void initializeSkippedToothTriggerShapeExt(trigger_shape_s *s, int totalTeethCount, int skippedCount, operation_mode_e operationMode) { efiAssertVoid(totalTeethCount > 0, "totalTeethCount is zero"); - trigger_shape_s *s = &engineConfiguration2->triggerShape; + s->totalToothCount = totalTeethCount; + s->skippedToothCount = skippedCount; initializeSkippedToothTriggerShape(s, totalTeethCount, skippedCount, operationMode); s->shaftPositionEventCount = ((totalTeethCount - skippedCount) * 2); @@ -151,6 +152,7 @@ void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfig } static void configureFordAspireTriggerShape(trigger_config_s *triggerConfig, trigger_shape_s * s) { + s->isSynchronizationNeeded = false; s->reset(FOUR_STROKE_CAM_SENSOR); s->shaftPositionEventCount = 10; @@ -174,23 +176,34 @@ static void configureFordAspireTriggerShape(trigger_config_s *triggerConfig, tri void initializeTriggerShape(Logging *logger, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2) { #if EFI_PROD_CODE - printMsg(logger, "initializeTriggerShape()"); + scheduleMsg(logger, "initializeTriggerShape()"); #endif trigger_config_s *triggerConfig = &engineConfiguration->triggerConfig; trigger_shape_s *triggerShape = &engineConfiguration2->triggerShape; + + setTriggerSynchronizationGap(triggerShape, 2); + triggerShape->useRiseEdge = TRUE; + triggerShape->needSecondTriggerInput = TRUE; + + switch (triggerConfig->triggerType) { case TT_TOOTHED_WHEEL: - initializeSkippedToothTriggerShapeExt(engineConfiguration2, triggerConfig->totalToothCount, triggerConfig->skippedToothCount, + engineConfiguration2->triggerShape.needSecondTriggerInput = false; + + engineConfiguration2->triggerShape.isSynchronizationNeeded = engineConfiguration->triggerConfig.customIsSynchronizationNeeded; + + initializeSkippedToothTriggerShapeExt(triggerShape, triggerConfig->customTotalToothCount, + triggerConfig->customSkippedToothCount, getOperationMode(engineConfiguration)); return; case TT_MAZDA_MIATA_NB: - initializeMazdaMiataNbShape(triggerConfig, triggerShape); + initializeMazdaMiataNbShape(triggerShape); return; case TT_DODGE_NEON: - configureNeonTriggerShape(triggerConfig, triggerShape); + configureNeonTriggerShape(triggerShape); return; case TT_FORD_ASPIRE: @@ -202,11 +215,20 @@ void initializeTriggerShape(Logging *logger, engine_configuration_s *engineConfi return; case TT_FORD_ESCORT_GT: - configureMazdaProtegeLx(triggerConfig, triggerShape); + configureMazdaProtegeLx(triggerShape); return; case TT_MINI_COOPER_R50: - configureMiniCooperTriggerShape(triggerConfig, triggerShape); + configureMiniCooperTriggerShape(triggerShape); + return; + + case TT_TOOTHED_WHEEL_60_2: + setToothedWheelConfiguration(triggerShape, 60, 2, engineConfiguration); + setTriggerSynchronizationGap(triggerShape, 2.5); + return; + + case TT_TOOTHED_WHEEL_36_1: + setToothedWheelConfiguration(triggerShape, 36, 1, engineConfiguration); return; default: diff --git a/firmware/controllers/trigger/trigger_decoder.h b/firmware/controllers/trigger/trigger_decoder.h index f31c25e97f..8922c881f7 100644 --- a/firmware/controllers/trigger/trigger_decoder.h +++ b/firmware/controllers/trigger/trigger_decoder.h @@ -23,7 +23,7 @@ private: bool secondaryWheelState; }; -void initializeSkippedToothTriggerShapeExt(engine_configuration2_s *engineConfiguration2, int totalTeethCount, int skippedCount, operation_mode_e operationMode); +void initializeSkippedToothTriggerShapeExt(trigger_shape_s *s, int totalTeethCount, int skippedCount, operation_mode_e operationMode); int findTriggerZeroEventIndex(trigger_shape_s * shape, trigger_config_s const*triggerConfig); void initializeTriggerShape(Logging *logger, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2); void initTriggerDecoder(void); diff --git a/firmware/controllers/trigger/trigger_emulator_algo.cpp b/firmware/controllers/trigger/trigger_emulator_algo.cpp index 8f5039b085..b9bf2cd808 100644 --- a/firmware/controllers/trigger/trigger_emulator_algo.cpp +++ b/firmware/controllers/trigger/trigger_emulator_algo.cpp @@ -36,22 +36,25 @@ void setTriggerEmulatorRPM(int rpm) { * togglePwmState() would see that the periodMs has changed and act accordingly */ if (rpm == 0) { - triggerSignal.periodMs = NAN; + triggerSignal.periodUs = NAN; } else { float gRpm = rpm * engineConfiguration->rpmMultiplier / 60.0; // per minute converted to per second - triggerSignal.periodMs = frequency2period(gRpm); + triggerSignal.periodUs = frequency2periodUs(gRpm); } scheduleMsg(&logger, "Emulating position sensor(s). RPM=%d", rpm); } static void updateTriggerShapeIfNeeded(PwmConfig *state) { - if(localVersion.isOld()) { + if (localVersion.isOld()) { scheduleMsg(&logger, "Stimulator: updating trigger shape: %d/%d %d", localVersion.getVersion(), getGlobalConfigurationVersion(), currentTimeMillis()); + + applyNonPersistentConfiguration(&logger, engineConfiguration, engineConfiguration2); + trigger_shape_s *s = &engineConfiguration2->triggerShape; int *pinStates[2] = {s->wave.waves[0].pinStates, s->wave.waves[1].pinStates}; copyPwmParameters(state, s->getSize(), s->wave.switchTimes, 2, pinStates); - state->safe.periodMs = -1; // this would cause loop re-initialization + state->safe.periodUs = -1; // this would cause loop re-initialization } } diff --git a/firmware/controllers/trigger/trigger_mazda.cpp b/firmware/controllers/trigger/trigger_mazda.cpp index 98702868fd..bc0629e7a6 100644 --- a/firmware/controllers/trigger/trigger_mazda.cpp +++ b/firmware/controllers/trigger/trigger_mazda.cpp @@ -20,7 +20,10 @@ #include "trigger_mazda.h" -void initializeMazdaMiataNbShape(trigger_config_s *triggerConfig, trigger_shape_s *s) { +void initializeMazdaMiataNbShape(trigger_shape_s *s) { + setTriggerSynchronizationGap(s, 0.11); + s->useRiseEdge = false; + s->reset(FOUR_STROKE_CAM_SENSOR); /** @@ -57,7 +60,10 @@ void initializeMazdaMiataNbShape(trigger_config_s *triggerConfig, trigger_shape_ s->shaftPositionEventCount = 6 + 16; } -void configureMazdaProtegeLx(trigger_config_s *triggerConfig, trigger_shape_s *s) { +void configureMazdaProtegeLx(trigger_shape_s *s) { + + s->needSecondTriggerInput = FALSE; + s->reset(FOUR_STROKE_CAM_SENSOR); // s->initialState[0] = 1; @@ -97,5 +103,5 @@ void configureMazdaProtegeLx(trigger_config_s *triggerConfig, trigger_shape_s *s // s->shaftPositionEventCount = 2 + 8; s->shaftPositionEventCount = 8; - triggerConfig->isSynchronizationNeeded = false; + s->isSynchronizationNeeded = false; } diff --git a/firmware/controllers/trigger/trigger_mazda.h b/firmware/controllers/trigger/trigger_mazda.h index 0cc01f3d17..87e1b2b6da 100644 --- a/firmware/controllers/trigger/trigger_mazda.h +++ b/firmware/controllers/trigger/trigger_mazda.h @@ -12,7 +12,7 @@ #include "engine_configuration.h" #include "ec2.h" -void initializeMazdaMiataNbShape(trigger_config_s *triggerConfig, trigger_shape_s *s); -void configureMazdaProtegeLx(trigger_config_s *triggerConfig, trigger_shape_s *s); +void initializeMazdaMiataNbShape(trigger_shape_s *s); +void configureMazdaProtegeLx(trigger_shape_s *s); #endif /* TRIGGER_MAZDA_H_ */ diff --git a/firmware/controllers/trigger/trigger_structure.cpp b/firmware/controllers/trigger/trigger_structure.cpp index 215f942fc3..a11cdb8ac2 100644 --- a/firmware/controllers/trigger/trigger_structure.cpp +++ b/firmware/controllers/trigger/trigger_structure.cpp @@ -21,6 +21,7 @@ #include "main.h" #include "trigger_structure.h" #include "error_handling.h" +#include "trigger_decoder.h" trigger_shape_helper::trigger_shape_helper() { waves[0].init(pinStates0); @@ -188,3 +189,22 @@ void trigger_shape_s::setSwitchTime(int index, float angle) { void multi_wave_s::checkSwitchTimes(int size) { checkSwitchTimes2(size, switchTimes); } + +void setToothedWheelConfiguration(trigger_shape_s *s, int total, int skipped, engine_configuration_s const *engineConfiguration) { + s->isSynchronizationNeeded = (skipped != 0); + + s->totalToothCount = total; + s->skippedToothCount = skipped; + s->needSecondTriggerInput = false; + s->useRiseEdge = TRUE; + + initializeSkippedToothTriggerShapeExt(s, s->totalToothCount, + s->skippedToothCount, + getOperationMode(engineConfiguration)); +} + +void setTriggerSynchronizationGap(trigger_shape_s *s, float synchGap) { + s->isSynchronizationNeeded = TRUE; + s->syncRatioFrom = synchGap * 0.75; + s->syncRatioTo = synchGap * 1.25; +} diff --git a/firmware/controllers/trigger/trigger_structure.h b/firmware/controllers/trigger/trigger_structure.h index ede13a3e8b..ee79de4b38 100644 --- a/firmware/controllers/trigger/trigger_structure.h +++ b/firmware/controllers/trigger/trigger_structure.h @@ -71,6 +71,19 @@ private: trigger_shape_helper h; int size; public: + int isSynchronizationNeeded; + + int totalToothCount; + int skippedToothCount; + + float syncRatioFrom; + float syncRatioTo; + + int useRiseEdge; + + bool needSecondTriggerInput; + + trigger_shape_s(); void addEvent(float angle, trigger_wheel_e waveIndex, trigger_value_e state); float getAngle(int phaseIndex) const; @@ -123,4 +136,7 @@ private: operation_mode_e operationMode; }; +void setTriggerSynchronizationGap(trigger_shape_s *s, float synchGap); +void setToothedWheelConfiguration(trigger_shape_s *s, int total, int skipped, engine_configuration_s const *engineConfiguration); + #endif /* TRIGGER_STRUCTURE_H_ */ diff --git a/firmware/emulation/engine_emulator.cpp b/firmware/emulation/engine_emulator.cpp index 6d0bdd1319..c7ee574e2d 100644 --- a/firmware/emulation/engine_emulator.cpp +++ b/firmware/emulation/engine_emulator.cpp @@ -1,16 +1,16 @@ /** - * @file engine_emulator.c + * @file engine_emulator.cpp * @brief Entry point for all the emulation and analysis code * * @date Mar 15, 2013 * @author Andrey Belomutskiy, (c) 2012-2014 */ -extern "C" { - #include "main.h" #include "engine_emulator.h" +extern "C" { + #include "status_loop.h" #include "advance_map.h" #include "wave_analyzer.h" @@ -92,12 +92,12 @@ static void initECUstimulator(void) { chThdCreateStatic(eeThreadStack, sizeof(eeThreadStack), NORMALPRIO, (tfunc_t) eeThread, NULL); } -void initEngineEmulator(void) { +void initEngineEmulator(board_configuration_s *boardConfiguration) { if (hasFirmwareError()) return; #if EFI_POTENTIOMETER - initPotentiometers(); + initPotentiometers(boardConfiguration); #endif /* EFI_POTENTIOMETER */ //initECUstimulator(); diff --git a/firmware/emulation/engine_emulator.h b/firmware/emulation/engine_emulator.h index 6494f25b9a..8de4135040 100644 --- a/firmware/emulation/engine_emulator.h +++ b/firmware/emulation/engine_emulator.h @@ -8,18 +8,7 @@ #ifndef ENGINE_EMULATOR_H_ #define ENGINE_EMULATOR_H_ -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -void initEngineEmulator(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +#include "engine_configuration.h" +void initEngineEmulator(board_configuration_s *boardConfiguration); #endif /* ENGINE_EMULATOR_H_ */ diff --git a/firmware/emulation/hw_layer/poten.c b/firmware/emulation/hw_layer/poten.c index 1e54aa0f07..a443e3ee71 100644 --- a/firmware/emulation/hw_layer/poten.c +++ b/firmware/emulation/hw_layer/poten.c @@ -11,6 +11,7 @@ #include "eficonsole.h" #include "pin_repository.h" #include "engine_configuration.h" +#include "hardware.h" /** * MCP42010 digital potentiometer driver @@ -35,40 +36,30 @@ * */ -SPIDriver * getDigiralPotDevice(void) { -#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) -// return &SPID2; +SPIDriver * getDigiralPotDevice(spi_device_e spiDevice) { +#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__) + if (spiDevice == SPI_DEVICE_1) + return &SPID1; #endif - return &SPID3; +#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__) + if (spiDevic e== SPI_DEVICE_2) + return &SPID2; +#endif +#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__) + if (spiDevice == SPI_DEVICE_3) + return &SPID3; +#endif + firmwareError("Unexpected SPI device: %d", spiDevice); + return NULL; } - -//#define POTEN_CS_PORT GPIOB -//#define POTEN_CS_PIN 12 - - -//#define POT_SPI &SPID1 - -// PA13 & PA14 are system pins - -//// chip select -//#define POTEN_CS_PORT GPIOE -//#define POTEN_CS_PIN 15 - -// chip select -#define POTEN_CS_PORT GPIOA -#define POTEN_CS_PIN 10 -//#define POT_SPI &SPID3 - - /* Low speed SPI configuration (281.250kHz, CPHA=0, CPOL=0, MSb first).*/ #define SPI_POT_CONFIG SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_DFF static Logging logger; - #if EFI_POTENTIOMETER -Mcp42010Driver config0; +Mcp42010Driver config[DIGIPOT_COUNT]; void initPotentiometer(Mcp42010Driver *driver, SPIDriver *spi, ioportid_t port, ioportmask_t pin) { driver->spiConfig.end_cb = NULL; @@ -83,14 +74,15 @@ static int getPotStep(int resistanceWA) { return 256 - (int) ((resistanceWA - 52) * 256 / 10000); } - static void sendToPot(Mcp42010Driver *driver, int channel, int value) { + lockSpi(SPI_NONE); spiStart(driver->spi, &driver->spiConfig); spiSelect(driver->spi); int word = (17 + channel) * 256 + value; spiSend(driver->spi, 1, &word); spiUnselect(driver->spi); spiStop(driver->spi); + unlockSpi(); } void setPotResistance(Mcp42010Driver *driver, int channel, int resistance) { @@ -105,32 +97,42 @@ void setPotResistance(Mcp42010Driver *driver, int channel, int resistance) { appendPrintf(&logger, "%d for R=%d", value, resistance); appendMsgPostfix(logging); - scheduleLogging(logging); sendToPot(driver, channel, value); } - static void setPotResistance0(int value) { - setPotResistance(&config0, 0, value); + setPotResistance(&config[0], 0, value); } static void setPotResistance1(int value) { - setPotResistance(&config0, 1, value); + setPotResistance(&config[0], 1, value); } static void setPotValue1(int value) { - sendToPot(&config0, 1, value); + sendToPot(&config[0], 1, value); } #endif /* EFI_POTENTIOMETER */ -void initPotentiometers() { +void initPotentiometers(board_configuration_s *boardConfiguration) { #if EFI_POTENTIOMETER initLogging(&logger, "potentiometer"); + if (boardConfiguration->digitalPotentiometerSpiDevice == SPI_NONE) { + scheduleMsg(&logger, "digiPot spi disabled"); + return; + } + turnOnSpi(boardConfiguration->digitalPotentiometerSpiDevice); - initPotentiometer(&config0, getDigiralPotDevice(), POTEN_CS_PORT, POTEN_CS_PIN); + for (int i = 0; i < DIGIPOT_COUNT; i++) { + brain_pin_e csPin = boardConfiguration->digitalPotentiometerChipSelect[i]; + if (csPin == GPIO_NONE) + continue; + + initPotentiometer(&config[i], getDigiralPotDevice(boardConfiguration->digitalPotentiometerSpiDevice), + getHwPort(csPin), getHwPin(csPin)); + } addConsoleActionI("pot0", setPotResistance0); addConsoleActionI("pot1", setPotResistance1); @@ -140,6 +142,6 @@ void initPotentiometers() { setPotResistance0(3000); setPotResistance1(7000); #else - print("potentiometer disabled\r\n"); + print("digiPot logic disabled\r\n"); #endif } diff --git a/firmware/emulation/hw_layer/poten.h b/firmware/emulation/hw_layer/poten.h index 8c53bfeaa0..c15de7de95 100644 --- a/firmware/emulation/hw_layer/poten.h +++ b/firmware/emulation/hw_layer/poten.h @@ -10,6 +10,7 @@ #define POTEN_H_ #include "main.h" +#include "engine_configuration.h" typedef struct { SPIDriver *spi; @@ -17,7 +18,7 @@ typedef struct { } Mcp42010Driver; void initPotentiometer(Mcp42010Driver *driver, SPIDriver *spi, ioportid_t port, ioportmask_t pin); -void initPotentiometers(void); +void initPotentiometers(board_configuration_s *boardConfiguration); void setPotResistance(Mcp42010Driver *driver, int channel, int resistance); #endif /* POTEN_H_ */ diff --git a/firmware/emulation/rfi_perftest.cpp b/firmware/emulation/rfi_perftest.cpp index a071c80324..0bd8eebb9b 100644 --- a/firmware/emulation/rfi_perftest.cpp +++ b/firmware/emulation/rfi_perftest.cpp @@ -76,17 +76,17 @@ static void testRusefiMethods(const int count) { start = currentTimeMillis(); for (int i = 0; i < count; i++) - tempi += getBaseFuel(4020, 2.21111); + tempi += getBaseTableFuel(4020, 2.21111); time = currentTimeMillis() - start; if (tempi != 0) scheduleMsg(&logger, "Finished %d iterations of getBaseFuel in %dms", count, time); - start = currentTimeMillis(); - for (int i = 0; i < count; i++) - tempi += getFuelMs(1200); - time = currentTimeMillis() - start; - if (tempi != 0) - scheduleMsg(&logger, "Finished %d iterations of getFuelMs in %dms", count, time); +// start = currentTimeMillis(); +// for (int i = 0; i < count; i++) +// tempi += getFuelMs(1200, NULL); // todo +// time = currentTimeMillis() - start; +// if (tempi != 0) +// scheduleMsg(&logger, "Finished %d iterations of getFuelMs in %dms", count, time); start = currentTimeMillis(); for (int i = 0; i < count; i++) { diff --git a/firmware/hw_layer/AdcConfiguration.h b/firmware/hw_layer/AdcConfiguration.h index 15e579741f..39fdebcfa5 100644 --- a/firmware/hw_layer/AdcConfiguration.h +++ b/firmware/hw_layer/AdcConfiguration.h @@ -16,6 +16,7 @@ public: int size(); void init(void); int conversionCount; + int errorsCount; private: ADCConversionGroup* hwConfig; /** diff --git a/firmware/hw_layer/adc_inputs.cpp b/firmware/hw_layer/adc_inputs.cpp index b9c93a6ce0..b8a95ac414 100644 --- a/firmware/hw_layer/adc_inputs.cpp +++ b/firmware/hw_layer/adc_inputs.cpp @@ -1,5 +1,5 @@ /** - * @file adc_inputs.c + * @file adc_inputs.cpp * @brief Low level ADC code * * @date Jan 14, 2013 @@ -33,6 +33,8 @@ AdcConfiguration::AdcConfiguration(ADCConversionGroup* hwConfig) { #define ADC_NUMBER_CHANNELS_FAST 1 // todo: migrate from hardware timer to software ADC conversion triggering +// todo: I guess we would have to use ChibiOS timer and not our own timer because +// todo: adcStartConversionI requires OS lock. currently slow ADC is 10Hz (?) #define PWM_FREQ_SLOW 5000 /* PWM clock frequency. I wonder what does this setting mean? */ #define PWM_PERIOD_SLOW 500 /* PWM period (in PWM ticks). */ @@ -40,7 +42,8 @@ AdcConfiguration::AdcConfiguration(ADCConversionGroup* hwConfig) { * 8000 RPM is 133Hz * If we want to sample MAP once per 5 degrees we need 133Hz * (360 / 5) = 9576Hz of fast ADC */ -// todo: migrate to continues ADC mode? +// todo: migrate to continues ADC mode? probably not - we cannot afford the callback in +// todo: continues mode. todo: look into our options #define PWM_FREQ_FAST 100000 /* PWM clock frequency. I wonder what does this setting mean? */ #define PWM_PERIOD_FAST 10 /* PWM period (in PWM ticks). */ @@ -158,11 +161,13 @@ static void pwmpcb_slow(PWMDriver *pwmp) { if (ADC_FAST_DEVICE.state != ADC_READY && ADC_FAST_DEVICE.state != ADC_COMPLETE && ADC_FAST_DEVICE.state != ADC_ERROR) { - firmwareError("ADC slow not ready?"); + // todo: why and when does this happen? firmwareError("ADC slow not ready?"); + slowAdc.errorsCount++; chSysUnlockFromIsr() ; return; } + slowAdc.errorsCount++; adcStartConversionI(&ADC_SLOW_DEVICE, &adcgrpcfgSlow, slowAdcState.samples, ADC_GRP1_BUF_DEPTH_SLOW); chSysUnlockFromIsr() ; @@ -184,7 +189,8 @@ static void pwmpcb_fast(PWMDriver *pwmp) { if (ADC_FAST_DEVICE.state != ADC_READY && ADC_FAST_DEVICE.state != ADC_COMPLETE && ADC_FAST_DEVICE.state != ADC_ERROR) { - firmwareError("ADC fast not ready?"); + fastAdc.errorsCount++; + // todo: when? why? firmwareError("ADC fast not ready?"); chSysUnlockFromIsr() ; return; diff --git a/firmware/hw_layer/board_test.cpp b/firmware/hw_layer/board_test.cpp index ebb385ea93..102a892c3e 100644 --- a/firmware/hw_layer/board_test.cpp +++ b/firmware/hw_layer/board_test.cpp @@ -140,7 +140,7 @@ void initBoardTest(void) { // print("ADC%d val= %d%s", hwIndex, value, DELIMETER); float volts = adcToVolts(adcValue) * 2; - print("v=%f adc=%d c=%d\r\n", volts, adcValue, c++); + print("v=%f adc=%d c=%d (hit 'n' for next step\r\n", volts, adcValue, c++); chThdSleepMilliseconds(300); diff --git a/firmware/hw_layer/gpio_helper.c b/firmware/hw_layer/gpio_helper.c index 8f989df2a3..39109e0106 100644 --- a/firmware/hw_layer/gpio_helper.c +++ b/firmware/hw_layer/gpio_helper.c @@ -31,6 +31,11 @@ * @brief Initialize the hardware output pin while also assigning it a logical name */ void initOutputPinExt(const char *msg, OutputPin *outputPin, GPIO_TypeDef *port, uint32_t pinNumber, iomode_t mode) { +// if (outputPin->port != NULL) { +// todo: need to clear '&outputs' in io_pins.c +// firmwareError("outputPin already assigned to %x%d", outputPin->port, outputPin->pin); +// return; +// } outputPin->currentLogicValue = -1; outputPin->port = port; outputPin->pin = pinNumber; diff --git a/firmware/hw_layer/hardware.cpp b/firmware/hw_layer/hardware.cpp index 8ef625b95b..4833a720ae 100644 --- a/firmware/hw_layer/hardware.cpp +++ b/firmware/hw_layer/hardware.cpp @@ -39,12 +39,12 @@ #include "engine_configuration.h" #include "ec2.h" -McpAdcState adcState; - extern engine_configuration_s *engineConfiguration; extern engine_configuration2_s * engineConfiguration2; extern board_configuration_s *boardConfiguration; +static bool isSpiInitialized[5] = { false, false, false, false, false }; + static void initSpiModule(SPIDriver *driver, ioportid_t sckPort, ioportmask_t sckPin, ioportid_t misoPort, ioportmask_t misoPin, ioportid_t mosiPort, ioportmask_t mosiPin, int af) { mySetPadMode("SPI clock", sckPort, sckPin, PAL_MODE_ALTERNATE(af)); @@ -53,23 +53,59 @@ static void initSpiModule(SPIDriver *driver, ioportid_t sckPort, ioportmask_t sc mySetPadMode("SPI master in ", misoPort, misoPin, PAL_MODE_ALTERNATE(af)); } -void initSpiModules(void) { +static Mutex spiMtx; + +/** + * Only one consumer can use SPI bus at a given time + */ +void lockSpi(spi_device_e device) { + // todo: different locks for different SPI devices! + chMtxLock(&spiMtx); +} + +void unlockSpi(void) { + chMtxUnlock(); +} + +void turnOnSpi(spi_device_e device) { + if (isSpiInitialized[device]) + return; // already initialized + isSpiInitialized[device] = true; + if (device == SPI_DEVICE_1) { +#if STM32_SPI_USE_SPI1 +// scheduleMsg(&logging, "Turning on SPI1 pins"); + initSpiModule(&SPID1, + EFI_SPI1_SCK_PORT, EFI_SPI1_SCK_PIN, + EFI_SPI1_MISO_PORT, EFI_SPI1_MISO_PIN, + EFI_SPI1_MOSI_PORT, EFI_SPI1_MOSI_PIN, + EFI_SPI1_AF); +#endif + } + if (device == SPI_DEVICE_2) { #if STM32_SPI_USE_SPI2 // scheduleMsg(&logging, "Turning on SPI2 pins"); - initSpiModule(&SPID2, - EFI_SPI2_SCK_PORT, EFI_SPI2_SCK_PIN, - EFI_SPI2_MISO_PORT, EFI_SPI2_MISO_PIN, - EFI_SPI2_MOSI_PORT, EFI_SPI2_MOSI_PIN, - EFI_SPI2_AF); + initSpiModule(&SPID2, + EFI_SPI2_SCK_PORT, EFI_SPI2_SCK_PIN, + EFI_SPI2_MISO_PORT, EFI_SPI2_MISO_PIN, + EFI_SPI2_MOSI_PORT, EFI_SPI2_MOSI_PIN, + EFI_SPI2_AF); #endif + } + if (device == SPI_DEVICE_3) { #if STM32_SPI_USE_SPI3 // scheduleMsg(&logging, "Turning on SPI3 pins"); - initSpiModule(&SPID3, - EFI_SPI3_SCK_PORT, EFI_SPI3_SCK_PIN, - EFI_SPI3_MISO_PORT, EFI_SPI3_MISO_PIN, - EFI_SPI3_MOSI_PORT, EFI_SPI3_MOSI_PIN, - EFI_SPI3_AF); + initSpiModule(&SPID3, + EFI_SPI3_SCK_PORT, EFI_SPI3_SCK_PIN, + EFI_SPI3_MISO_PORT, EFI_SPI3_MISO_PIN, + EFI_SPI3_MOSI_PORT, EFI_SPI3_MOSI_PIN, + EFI_SPI3_AF); #endif + } +} + +void initSpiModules(void) { + turnOnSpi(SPI_DEVICE_2); + turnOnSpi(SPI_DEVICE_3); } static I2CConfig i2cfg = { OPMODE_I2C, 100000, STD_DUTY_CYCLE, }; @@ -100,6 +136,9 @@ void initHardware(Logging *logger) { // 10 extra seconds to re-flash the chip //flashProtect(); + chMtxInit(&spiMtx); + + #if EFI_HISTOGRAMS /** * histograms is a data structure for CPU monitor, it does not depend on configuration @@ -199,9 +238,7 @@ void initHardware(Logging *logger) { if (hasFirmwareError()) return; - char buffer[16]; - itoa10(buffer, SVN_VERSION); - lcd_HD44780_print_string(buffer); + lcd_HD44780_print_string(VCS_VERSION); #endif /* EFI_HD44780_LCD */ diff --git a/firmware/hw_layer/hardware.h b/firmware/hw_layer/hardware.h index 7e024b24ad..3e7641556d 100644 --- a/firmware/hw_layer/hardware.h +++ b/firmware/hw_layer/hardware.h @@ -10,6 +10,19 @@ #include "main.h" +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +void turnOnSpi(spi_device_e device); +void lockSpi(spi_device_e device); +void unlockSpi(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + #define GET_BOARD_TEST_MODE_VALUE() (!palReadPad(getHwPort(boardConfiguration->boardTestModeJumperPin), getHwPin(boardConfiguration->boardTestModeJumperPin))) void initHardware(Logging *logging); diff --git a/firmware/hw_layer/io_pins.c b/firmware/hw_layer/io_pins.c index 6a386fd6c4..da52cdca67 100644 --- a/firmware/hw_layer/io_pins.c +++ b/firmware/hw_layer/io_pins.c @@ -114,6 +114,7 @@ static void errBlinkingThread(void *arg) { static void outputPinRegisterExt(const char *msg, io_pin_e ioPin, GPIO_TypeDef *port, uint32_t pin, pin_output_mode_e *outputMode) { + efiAssertVoid((int)ioPin < IO_PIN_COUNT, "io pin out of range"); if (port == GPIO_NULL) { // that's for GRIO_NONE outputs[ioPin].port = port; @@ -184,6 +185,13 @@ void initOutputPins(void) { outputPinRegister("is running status", LED_RUNNING, LED_RUNNING_STATUS_PORT, LED_RUNNING_STATUS_PIN); outputPinRegister("communication status 1", LED_COMMUNICATION_1, LED_COMMUNICATION_PORT, LED_COMMUNICATION_PIN); + /** + * want to make sure it's all zeros so that we can compare in initOutputPinExt() method + */ +// todo: it's too late to clear now? this breaks default status LEDs +// todo: fix this? +// memset(&outputs, 0, sizeof(outputs)); + // outputPinRegister("ext led 1", LED_EXT_1, EXTRA_LED_1_PORT, EXTRA_LED_1_PIN); // outputPinRegister("ext led 2", LED_EXT_2, EXTRA_LED_2_PORT, EXTRA_LED_2_PIN); // outputPinRegister("ext led 3", LED_EXT_3, EXTRA_LED_2_PORT, EXTRA_LED_3_PIN); @@ -192,10 +200,11 @@ void initOutputPins(void) { outputPinRegister("MalfunctionIndicator", LED_CHECK_ENGINE, getHwPort(boardConfiguration->malfunctionIndicatorPin), getHwPin(boardConfiguration->malfunctionIndicatorPin)); - outputPinRegister("spi CS1", SPI_CS_1, SPI_CS1_PORT, SPI_CS1_PIN); - outputPinRegister("spi CS2", SPI_CS_2, SPI_CS2_PORT, SPI_CS2_PIN); - outputPinRegister("spi CS3", SPI_CS_3, SPI_CS3_PORT, SPI_CS3_PIN); - outputPinRegister("spi CS4", SPI_CS_4, SPI_CS4_PORT, SPI_CS4_PIN); +// todo: are these needed here? todo: make configurable +// outputPinRegister("spi CS1", SPI_CS_1, SPI_CS1_PORT, SPI_CS1_PIN); +// outputPinRegister("spi CS2", SPI_CS_2, SPI_CS2_PORT, SPI_CS2_PIN); +// outputPinRegister("spi CS3", SPI_CS_3, SPI_CS3_PORT, SPI_CS3_PIN); +// outputPinRegister("spi CS4", SPI_CS_4, SPI_CS4_PORT, SPI_CS4_PIN); outputPinRegister("spi CS5", SPI_CS_SD_MODULE, SPI_SD_MODULE_PORT, SPI_SD_MODULE_PIN); // todo: should we move this code closer to the fuel pump logic? diff --git a/firmware/hw_layer/lcd/lcd_HD44780.c b/firmware/hw_layer/lcd/lcd_HD44780.c index 2a9945f18a..3a072a6d2b 100644 --- a/firmware/hw_layer/lcd/lcd_HD44780.c +++ b/firmware/hw_layer/lcd/lcd_HD44780.c @@ -150,7 +150,7 @@ void lcd_HD44780_print_char(char data) { } } -void lcd_HD44780_print_string(char* string) { +void lcd_HD44780_print_string(const char* string) { while (*string != 0x00) lcd_HD44780_print_char(*string++); } diff --git a/firmware/hw_layer/lcd/lcd_HD44780.h b/firmware/hw_layer/lcd/lcd_HD44780.h index 7221df151a..c4f95c8e36 100644 --- a/firmware/hw_layer/lcd/lcd_HD44780.h +++ b/firmware/hw_layer/lcd/lcd_HD44780.h @@ -16,7 +16,7 @@ extern "C" void lcd_HD44780_init(void); void lcd_HD44780_set_position(uint8_t row, uint8_t column); void lcd_HD44780_print_char(char data); -void lcd_HD44780_print_string(char *string); +void lcd_HD44780_print_string(const char *string); void lcdShowFatalMessage(char *message); diff --git a/firmware/hw_layer/mmc_card.c b/firmware/hw_layer/mmc_card.c index 813e7814dc..c65f68a633 100644 --- a/firmware/hw_layer/mmc_card.c +++ b/firmware/hw_layer/mmc_card.c @@ -19,6 +19,7 @@ #include "mmc_card.h" #include "pin_repository.h" #include "ff.h" +#include "hardware.h" #define PUSHPULLDELAY 500 @@ -88,20 +89,24 @@ static void sdStatistics(void) { * so that we can later append to that file */ static void createLogFile(void) { + lockSpi(SPI_NONE); memset(&FDLogFile, 0, sizeof(FIL)); // clear the memory FRESULT err = f_open(&FDLogFile, "rusefi.log", FA_OPEN_ALWAYS | FA_WRITE); // Create new file if (err != FR_OK && err != FR_EXIST) { + unlockSpi(); printError("Card mounted...\r\nCan't create Log file, check your SD.\r\nFS mount failed", err); // else - show error return; } err = f_lseek(&FDLogFile, f_size(&FDLogFile)); // Move to end of the file to append data if (err) { + unlockSpi(); printError("Seek error", err); return; } f_sync(&FDLogFile); fs_ready = TRUE; // everything Ok + unlockSpi(); } static void ff_cmd_dir(char *path) { @@ -163,11 +168,13 @@ void appendToLog(char *line) { } int lineLength = strlen(line); totalLoggedBytes += lineLength; + lockSpi(SPI_NONE); FRESULT err = f_write(&FDLogFile, line, lineLength, &bytesWrited); if (bytesWrited < lineLength) { printError("write error or disk full", err); // error or disk full } f_sync(&FDLogFile); + unlockSpi(); } /* @@ -203,11 +210,14 @@ static void MMCmount(void) { mmcStart(&MMCD1, &mmccfg); // Configures and activates the MMC peripheral. // Performs the initialization procedure on the inserted card. + lockSpi(SPI_NONE); if (mmcConnect(&MMCD1) != CH_SUCCESS) { - scheduleMsg(&logger, "Can't connect or mount MMC/SD"); + warning(OBD_PCM_Processor_Fault, "Can't connect or mount MMC/SD"); + unlockSpi(); return; } + unlockSpi(); // if Ok - mount FS now memset(&MMC_FS, 0, sizeof(FATFS)); // reserve the memory if (f_mount(0, &MMC_FS) == FR_OK) { diff --git a/firmware/hw_layer/pwm_generator.cpp b/firmware/hw_layer/pwm_generator.cpp index 111f03ae41..3572f2a213 100644 --- a/firmware/hw_layer/pwm_generator.cpp +++ b/firmware/hw_layer/pwm_generator.cpp @@ -44,7 +44,7 @@ void startSimplePwm(PwmConfig *state, const char *msg, io_pin_e ioPin, state->outputPins[0] = ioPin; - state->periodMs = frequency2period(frequency); + state->periodUs = frequency2periodUs(frequency); weComplexInit(msg, state, 2, switchTimes, 1, pinStates, NULL, applyPinState); } diff --git a/firmware/hw_layer/pwm_generator.h b/firmware/hw_layer/pwm_generator.h index a86ac7c83f..3f7ba6043a 100644 --- a/firmware/hw_layer/pwm_generator.h +++ b/firmware/hw_layer/pwm_generator.h @@ -15,16 +15,16 @@ #include "gpio_helper.h" +void startSimplePwm(PwmConfig *state, const char *msg, io_pin_e ioPin, + float dutyCycle, float frequency); +void applyPinState(PwmConfig *state, int stateIndex); + + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -void applyPinState(PwmConfig *state, int stateIndex); - -void startSimplePwm(PwmConfig *state, const char *msg, io_pin_e ioPin, - float dutyCycle, float frequency); - void startSimplePwmExt(PwmConfig *state, const char *msg, brain_pin_e brainPin, io_pin_e ioPin, float frequency, float dutyCycle); diff --git a/firmware/hw_layer/serial_over_usb/usbconsole.h b/firmware/hw_layer/serial_over_usb/usbconsole.h index 24b3736655..cc9b6f9d7a 100644 --- a/firmware/hw_layer/serial_over_usb/usbconsole.h +++ b/firmware/hw_layer/serial_over_usb/usbconsole.h @@ -8,7 +8,16 @@ #ifndef USBCONSOLE_H_ #define USBCONSOLE_H_ +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + void usb_serial_start(void); int is_usb_serial_ready(void); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + #endif /* USBCONSOLE_H_ */ diff --git a/firmware/hw_layer/trigger_input.cpp b/firmware/hw_layer/trigger_input.cpp index 4aba3f5d41..cb65eda94f 100644 --- a/firmware/hw_layer/trigger_input.cpp +++ b/firmware/hw_layer/trigger_input.cpp @@ -22,6 +22,7 @@ static WaveReaderHw primaryCrankInput; static WaveReaderHw secondaryCrankInput; extern engine_configuration_s *engineConfiguration; +extern engine_configuration2_s *engineConfiguration2; extern board_configuration_s *boardConfiguration; @@ -39,7 +40,7 @@ static inline ICUDriver *getSecondaryInputCaptureDriver(void) { */ static void shaft_icu_width_callback(ICUDriver *icup) { int isPrimary = icup == getPrimaryInputCaptureDriver(); - if (!isPrimary && !engineConfiguration->needSecondTriggerInput) + if (!isPrimary && !engineConfiguration2->triggerShape.needSecondTriggerInput) return; // icucnt_t last_width = icuGetWidth(icup); so far we are fine with system time trigger_event_e signal = isPrimary ? SHAFT_PRIMARY_UP : SHAFT_SECONDARY_UP; @@ -49,7 +50,7 @@ static void shaft_icu_width_callback(ICUDriver *icup) { static void shaft_icu_period_callback(ICUDriver *icup) { int isPrimary = icup == getPrimaryInputCaptureDriver(); - if (!isPrimary && !engineConfiguration->needSecondTriggerInput) + if (!isPrimary && !engineConfiguration2->triggerShape.needSecondTriggerInput) return; // icucnt_t last_period = icuGetPeriod(icup); so far we are fine with system time diff --git a/firmware/iar/ch.ewp b/firmware/iar/ch.ewp index 016d134ac0..49673c971f 100644 --- a/firmware/iar/ch.ewp +++ b/firmware/iar/ch.ewp @@ -2034,13 +2034,13 @@ tunerstudio - $PROJ_DIR$\..\console\tunerstudio\tunerstudio.c + $PROJ_DIR$\..\console\tunerstudio\tunerstudio.cpp $PROJ_DIR$\..\console\tunerstudio\tunerstudio.h - $PROJ_DIR$\..\console\tunerstudio\tunerstudio_algo.c + $PROJ_DIR$\..\console\tunerstudio\tunerstudio_algo.cpp $PROJ_DIR$\..\console\tunerstudio\tunerstudio_algo.h @@ -2111,6 +2111,12 @@ $PROJ_DIR$\..\controllers\algo\ec2.h + + $PROJ_DIR$\..\controllers\algo\engine.cpp + + + $PROJ_DIR$\..\controllers\algo\engine.h + $PROJ_DIR$\..\controllers\algo\engine_configuration.cpp @@ -2153,6 +2159,12 @@ $PROJ_DIR$\..\controllers\algo\malfunction_central.h + + $PROJ_DIR$\..\controllers\algo\map_adjuster.c + + + $PROJ_DIR$\..\controllers\algo\map_adjuster.h + $PROJ_DIR$\..\controllers\algo\nmea.c @@ -2210,6 +2222,12 @@ $PROJ_DIR$\..\controllers\core\signal_filtering.h + + $PROJ_DIR$\..\controllers\core\table_helper.cpp + + + $PROJ_DIR$\..\controllers\core\table_helper.h + math @@ -2450,6 +2468,12 @@ emulation hw_layer + + $PROJ_DIR$\..\emulation\hw_layer\poten.c + + + $PROJ_DIR$\..\emulation\hw_layer\poten.h + test diff --git a/firmware/rusefi.cpp b/firmware/rusefi.cpp index 81435cef0f..49ab99623e 100644 --- a/firmware/rusefi.cpp +++ b/firmware/rusefi.cpp @@ -150,7 +150,7 @@ void runRusEfi(void) { #endif #if EFI_ENGINE_EMULATOR - initEngineEmulator(); + initEngineEmulator(boardConfiguration); #endif startStatusThreads(); @@ -253,5 +253,5 @@ void firmwareError(const char *fmt, ...) { } int getRusEfiVersion(void) { - return 20140709; + return 20140724; } diff --git a/firmware/svnversion.h b/firmware/svnversion.h index 4b61c21238..6fe1449f9e 100644 --- a/firmware/svnversion.h +++ b/firmware/svnversion.h @@ -1,5 +1,5 @@ // This file was generated by Version2Header -// Sat Jul 05 19:09:48 EDT 2014 -#ifndef SVN_VERSION -#define SVN_VERSION 3860 +// Wed Jul 23 08:21:40 EDT 2014 +#ifndef VCS_VERSION +#define VCS_VERSION "4047" #endif diff --git a/firmware/tunerstudio/rusefi.ini b/firmware/tunerstudio/rusefi.ini index bbd8e9a83c..473a6c7623 100644 --- a/firmware/tunerstudio/rusefi.ini +++ b/firmware/tunerstudio/rusefi.ini @@ -1,6 +1,6 @@ ; this is TunerStudio project for www.rusefi.com DIY engine management system -; version 20140706 +; version 20140721 ; this should stop TS from looking for the CAN ID in the 2nd byte location and allow the page reads to work correctly. enable2ndByteCanID = false @@ -15,7 +15,7 @@ enable2ndByteCanID = false endianness = little nPages = 1 - pageSize = 5804 + pageSize = 5824 pageIdentifier = "\x00\x00" pageReadCommand = "R\x00\x00%2o%2c" @@ -110,7 +110,7 @@ enable2ndByteCanID = false fuelKeyBins = array, F32, 792, [16], "V", 1, 0, 0.0, 10.0, 2; size 132 fuelRpmBins = array, F32, 856, [16], "RPM", 1, 0, 0.0, 25500.0, 2; size 92 displacement = scalar, F32, 920, "°C", 1, 0, 0, 1000.0, 2 ; size 4 - rpmHardLimit = scalar, U32, 924, "°C", 1, 0, 0, 1000.0, 2 ; size 4 + rpmHardLimit = scalar, U32, 924, "°C", 1, 0, 0, 10000.0, 2 ; size 4 crankingInjectionMode = scalar, U32, 928, "°C", 1, 0, 0, 1000.0, 2 ; size 4 injectionMode = scalar, U32, 932, "°C", 1, 0, 0, 1000.0, 2 ; size 4 globalTriggerOffsetAngle = scalar, F32, 936, "RPM", 1, 0, 0, 720, 0 ; size 4 @@ -135,7 +135,7 @@ enable2ndByteCanID = false tpsAdcInput = bits, U32, 1012, [0:4] "PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7", "PB0", "PB1", "PB0", "PB1", "PB2", "PB3", "PB4", "PB5" overrideCrankingIgnition= scalar, F32, 1016, "RPM", 1, 0.0, 0, 1000.0, 2 ; size 4 analogChartFrequency = scalar, U32, 1020, "index", 1, 0, 0, 300, 0 ; size 4 - trigger_type = bits, U32, 1024, [0:1], "toothed wheel", "ford aspire", "dodge neon", "INVALID" + trigger_type = bits, U32, 1024, [0:3], "custom toothed wheel", "ford aspire", "dodge neon", "Miata NA", "Miata NB", "GM_7X", "Cooper", "Escort GT", "60/2", "36/1", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" isSynchronizationNeeded = bits, U32, 1028, [0:0], "false", "true" totalToothCount = scalar, F32, 1032, "RPM", 1, 0.0, 0, 1000.0, 2 ; size 4 skippedToothCount = scalar, F32, 1036, "RPM", 1, 0.0, 0, 1000.0, 2 ; size 4 @@ -210,9 +210,30 @@ enable2ndByteCanID = false electronicThrottlePin1 = bits, U32, 5612, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" electronicThrottlePin1Mode = bits, U32, 5616, [0:1], "default", "default inverted", "open", "open inverted" -; idleSwitchPin + idleSwitchPin = bits, U32, 5620, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" +; idleSwitchPinMode + alternatorControlPin = bits, U32, 5628, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" +; alternatorControlPinMode ;todo + HD44780_rs = bits, U32, 5636, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + HD44780_e = bits, U32, 5640, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + HD44780_db4 = bits, U32, 5644, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + HD44780_db5 = bits, U32, 5648, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + HD44780_db6 = bits, U32, 5652, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + HD44780_db7 = bits, U32, 5656, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + + ;triggerSimulatorPin0 + ;triggerSimulatorPin1 + ;triggerSimulatorPinModes + + + digitalPotentiometerSpiDevice=bits,U32, 5676, [0:1], "Off", "SPI1", "SPI2", "SPI3" + digitalPotentiometerChipSelect0=bits,U32, 5680, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + digitalPotentiometerChipSelect1=bits,U32, 5684, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + digitalPotentiometerChipSelect2=bits,U32, 5688, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + digitalPotentiometerChipSelect3=bits,U32, 5692, [0:6], "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", "GPIOA_15", "GPIOB_0", "GPIOB_1", "GPIOB_2", "GPIOB_3", "GPIOB_4", "GPIOB_5", "GPIOB_6", "GPIOB_7", "GPIOB_8", "GPIOB_9", "GPIOB_10", "GPIOB_11", "GPIOB_12", "GPIOB_13", "GPIOB_14", "GPIOB_15", "GPIOC_0", "GPIOC_1", "GPIOC_2", "GPIOC_3", "GPIOC_4", "GPIOC_5", "GPIOC_6", "GPIOC_7", "GPIOC_8", "GPIOC_9", "GPIOC_10", "GPIOC_11", "GPIOC_12", "GPIOC_13", "GPIOC_14", "GPIOC_15", "GPIOD_0", "GPIOD_1", "GPIOD_2", "GPIOD_3", "GPIOD_4", "GPIOD_5", "GPIOD_6", "GPIOD_7", "GPIOD_8", "GPIOD_9", "GPIOD_10", "GPIOD_11", "GPIOD_12", "GPIOD_13", "GPIOD_14", "GPIOD_15", "GPIOE_0", "GPIOE_1", "GPIOE_2", "GPIOE_3", "GPIOE_4", "GPIOE_5", "GPIOE_6", "GPIOE_7", "GPIOE_8", "GPIOE_9", "GPIOE_10", "GPIOE_11", "GPIOE_12", "GPIOE_13", "GPIOE_14", "GPIOE_15", "NONE", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + adcModePA0 = bits, U32, 5696, [0:1], "Off", "Slow", "Fast", "INVALID" adcModePA1 = bits, U32, 5700, [0:1], "Off", "Slow", "Fast", "INVALID" adcModePA2 = bits, U32, 5704, [0:1], "Off", "Slow", "Fast", "INVALID" @@ -409,12 +430,14 @@ enable2ndByteCanID = false menu = "&Engine" subMenu = engineChars, "&Engine Characteristics" + subMenu = lcdScreen, "LCD screen" subMenu = boardInputs, "&Board inputs" subMenu = boardInputMode, "Board inputs mode" subMenu = boardOutputs1, "Board outputs #1" subMenu = boardOutputs2, "Board outputs #2" subMenu = injChars, "&injector Characteristicks" subMenu = injectorsDeadTime, "&Injectors Dead Time" + subMenu = ecuStimulator, "ECU stimulator" menu = "&Sensors" subMenu = clt_thermistor, "&CLT Thermistor" subMenu = iat_thermistor, "&IAT Thermistor" @@ -471,9 +494,17 @@ enable2ndByteCanID = false field = "Ignition Mode", IgnitionMode field = "Firing Order", FiringOrder field = "rpm Multiplier", rpmMultiplier - field = "display Mode", displayMode field = "log format", logFormat + dialog = lcdScreen, "LCD screen" + field = "display Mode", displayMode + field = "RS pin", HD44780_rs + field = "E pin", HD44780_e + field = "D4 pin", HD44780_db4 + field = "D5 pin", HD44780_db5 + field = "D6 pin", HD44780_db6 + field = "D7 pin", HD44780_db7 + dialog = boardInputs, "Board inputs" field = "Analog Input Divider Coefficient", analogInputDividerCoefficient field = "Battery Input Divider Coefficient", VBattDividerCoefficient @@ -503,6 +534,12 @@ enable2ndByteCanID = false field = "ADC on PC4", adcModePC4 field = "ADC on PC5", adcModePC5 + dialog = ecuStimulator, "ECU stimulator" + field = "digipot spi", digitalPotentiometerSpiDevice + field = "digipot CS #0", digitalPotentiometerChipSelect0 + field = "digipot CS #1", digitalPotentiometerChipSelect1 + field = "digipot CS #2", digitalPotentiometerChipSelect2 + field = "digipot CS #3", digitalPotentiometerChipSelect3 dialog = boardOutputs1, "Board properties #1" field = "Injection Pin 1", injectionPin1 @@ -585,13 +622,13 @@ enable2ndByteCanID = false dialog = triggerConfiguration, "Trigger configuration" field = "trigger type", trigger_type - field = "Synchronization Needed?", isSynchronizationNeeded - field = "total Tooth Count", totalToothCount - field = "skipped Tooth Count", skippedToothCount - field = "sync Ratio From", syncRatioFrom - field = "sync Ratio To", syncRatioTo - field = "use Rise Edge?", useRiseEdge - field = "needed Second Trigger Input?", needSecondTriggerInput + field = "Synchronization Needed?", isSynchronizationNeeded, {trigger_type == 0} + field = "total Tooth Count", totalToothCount, {trigger_type == 0} + field = "skipped Tooth Count", skippedToothCount, {trigger_type == 0} + field = "sync Ratio From", syncRatioFrom, {trigger_type == 0} + field = "sync Ratio To", syncRatioTo, {trigger_type == 0} + field = "use Rise Edge?", useRiseEdge, {trigger_type == 0} + field = "needed Second Trigger Input?", needSecondTriggerInput, {trigger_type == 0} dialog = crankingFuel, "Cranking Fuel" diff --git a/firmware/util/efilib.h b/firmware/util/efilib.h index d5df350370..c3462f9f7a 100644 --- a/firmware/util/efilib.h +++ b/firmware/util/efilib.h @@ -11,7 +11,11 @@ #include "stdint.h" // number of milliseconds in one period of given frequency (per second) -#define frequency2period(freq) (((float)1000) / (freq)) +#define frequency2periodMs(freq) ((1000.0f) / (freq)) + +// number of microseconds in one period of given frequency (per second) +#define frequency2periodUs(freq) ((1000000.0f) / (freq)) + #ifndef FALSE #define FALSE 0