manual sync with SF

This commit is contained in:
rusefi 2014-06-28 14:38:08 -04:00
parent 102ee997cb
commit 0d87be6add
168 changed files with 4761 additions and 2057 deletions

View File

@ -50,6 +50,7 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/math}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console_util}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/test}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/flash}&quot;"/>
@ -59,7 +60,10 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/adc}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/splib}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/boards/ST_STM32F4_DISCOVERY}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/TIMv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/I2Cv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32}&quot;"/>
@ -67,14 +71,11 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/OTGv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/GPIOv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/SPIv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/SPIv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx/CMSIS/include}&quot;"/>
</option>
<option id="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.other.otherflags.720321025" name="Other flags" superClass="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.other.otherflags" value="-fgnu89-inline -c -fmessage-length=0 -Werror=type-limits -Werror-implicit-function-declaration -Werror -Wno-error=pointer-sign -Wno-error=unused-function -Wno-error=unused-variable" valueType="string"/>
@ -110,6 +111,7 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/math}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console_util}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/test}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/flash}&quot;"/>
@ -119,7 +121,10 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/adc}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/splib}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/boards/ST_STM32F4_DISCOVERY}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/TIMv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/I2Cv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32}&quot;"/>
@ -127,17 +132,14 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/OTGv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/GPIOv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/SPIv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx/CMSIS/include}&quot;"/>
</option>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags.1439013659" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags" value="-c -fmessage-length=0 -std=c++11" valueType="string"/>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags.1439013659" name="Other flags" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.otherflags" value="-c -fmessage-length=0 -std=c++11 -Werror=write-strings" valueType="string"/>
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input.1939416167" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input"/>
</tool>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.debug.369587711" name="ARM Sourcery Windows GCC C Linker" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.debug"/>
@ -188,13 +190,14 @@
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input.1359572999" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.assembler.base.input"/>
</tool>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.compiler.release.431693497" name="ARM Sourcery Windows GCC C Compiler" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.compiler.release">
<option id="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.optimization.level.329705686" name="Optimization level" superClass="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.optimization.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.optimization.level.size" valueType="enumerated"/>
<option id="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.optimization.level.329705686" name="Optimization level" superClass="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.optimization.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.optimization.level.optimize" valueType="enumerated"/>
<option id="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.include.paths.1664205045" name="Include paths (-I)" superClass="org.eclipse.cdt.cross.arm.gnu.c.compiler.option.include.paths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/ext}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/ext_algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/util}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/engines}&quot;"/>
@ -205,24 +208,25 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/math}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/sensors}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/core}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/trigger}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/linked/controllers}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/linked/controllers/math}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/ckp}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/adc}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/splib}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/lcd}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/serial_over_usb}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/boards/ST_STM32F4_DISCOVERY}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/various}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/RTCv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/OTGv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/I2Cv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/GPIOv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/SPIv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/TIMv1}&quot;"/>
@ -242,8 +246,59 @@
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.c.compiler.base.input.1479270851" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.c.compiler.base.input"/>
</tool>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.cpp.compiler.release.487461954" name="ARM Sourcery Windows GCC C++ Compiler" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.cpp.compiler.release">
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.optimization.level.74521503" name="Optimization level" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.optimization.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.optimization.level.size" valueType="enumerated"/>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.optimization.level.74521503" name="Optimization level" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.optimization.level" value="org.eclipse.cdt.cross.arm.gnu.base.option.optimization.level.optimize" valueType="enumerated"/>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.verbose.1350766121" name="Verbose (-v)" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.other.verbose" value="false" valueType="boolean"/>
<option id="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.include.paths.346409971" name="Include paths (-I)" superClass="org.eclipse.cdt.cross.arm.gnu.cpp.compiler.option.include.paths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/serial_over_usb}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/lcd}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/ext}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/ext_algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/various}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/util}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console/tunerstudio}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/engines}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/boards}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/core}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/trigger}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/sensors}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/controllers/math}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/console_util}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/test}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/emulation/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw_layer/flash}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/algo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/ckp}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/russianefi/adc}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/config/system}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/splib}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/kernel/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/boards/ST_STM32F4_DISCOVERY}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/TIMv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/I2Cv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/RTCv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/OTGv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/GPIOv2}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/SPIv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/hal/platforms/STM32/USARTv1}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/GCC/ARMCMx/STM32F4xx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/chibios/os/ports/common/ARMCMx/CMSIS/include}&quot;"/>
</option>
<inputType id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input.815685204" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.cpp.compiler.base.input"/>
</tool>
<tool id="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.release.1692652942" name="ARM Sourcery Windows GCC C Linker" superClass="org.eclipse.cdt.cross.arm.gnu.sourcery.windows.elf.c.linker.release"/>

View File

@ -18,7 +18,7 @@ endif
# C++ specific options here (added to USE_OPT).
ifeq ($(USE_CPPOPT),)
USE_CPPOPT = -std=c++11 -fno-rtti -fno-exceptions -fno-use-cxa-atexit
USE_CPPOPT = -std=c++11 -fno-rtti -fno-exceptions -fno-use-cxa-atexit -Werror=write-strings
endif
# Enable this if you want the linker to remove unused code and data
@ -196,8 +196,9 @@ INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
hw_layer/serial_over_usb \
hw_layer/algo \
hw_layer/lcd \
emulation/hw_layer \
emulation \
emulation/hw_layer \
emulation/test \
controllers \
controllers/sensors \
controllers/system \
@ -292,7 +293,7 @@ ULIBS = -lm
##############################################################################
ifeq ($(USE_FPU),yes)
USE_OPT += -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -fsingle-precision-constant
USE_OPT += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant
DDEFS += -DCORTEX_USE_FPU=TRUE
else
DDEFS += -DCORTEX_USE_FPU=FALSE

View File

@ -192,10 +192,11 @@ static void serve_interrupt(SerialDriver *sdp) {
/* Physical transmission end.*/
if (sr & USART_SR_TC) {
chSysLockFromIsr();
chnAddFlagsI(sdp, CHN_TRANSMISSION_END);
chSysUnlockFromIsr();
u->CR1 = cr1 & ~(USART_CR1_TXEIE | USART_CR1_TCIE);
if (chOQIsEmptyI(&sdp->oqueue))
chnAddFlagsI(sdp, CHN_TRANSMISSION_END);
u->CR1 = cr1 & ~USART_CR1_TCIE;
u->SR = ~USART_SR_TC;
chSysUnlockFromIsr();
}
}

View File

@ -35,6 +35,28 @@
#include "ch.h"
extern stkalign_t __main_stack_base__;
int getRemainingStack(Thread *otp) {
#if CH_DBG_ENABLE_STACK_CHECK
register struct intctx *r13 asm ("r13");
otp->activeStack = r13;
int rs;
if (dbg_isr_cnt > 0) {
// ISR context
rs = (stkalign_t *) (r13 - 1) - &__main_stack_base__;
} else {
rs = (stkalign_t *) (r13 - 1) - otp->p_stklimit;
}
otp->remainingStack = rs;
return rs;
#else
return 99999;
#endif /* CH_DBG_ENABLE_STACK_CHECK */
}
/*===========================================================================*/
/* Port interrupt handlers. */
/*===========================================================================*/

View File

@ -490,6 +490,8 @@ struct context {
void chDbgStackOverflowPanic(Thread *otp);
int getRemainingStack(Thread *otp);
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
@ -504,8 +506,7 @@ void chDbgStackOverflowPanic(Thread *otp);
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
register struct intctx *r13 asm ("r13"); \
if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \
if (getRemainingStack(otp) < 0) \
chDbgStackOverflowPanic(otp); \
_port_switch(ntp, otp); \
}

View File

@ -39,6 +39,21 @@
/* Port interrupt handlers. */
/*===========================================================================*/
int getRemainingStack(Thread *otp) {
#if CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
int remainingStack;
if (dbg_isr_cnt > 0) {
remainingStack = 999; // todo
} else {
remainingStack = (stkalign_t *)(__get_SP() - sizeof(struct intctx)) - otp->p_stklimit;
}
otp->remainingStack = remainingStack;
return remainingStack;
#else
return 999999;
#endif
}
/**
* @brief System Timer vector.
* @details This interrupt is used as system tick.

View File

@ -470,6 +470,8 @@ struct context {
#define port_wait_for_interrupt()
#endif
int getRemainingStack(Thread *otp);
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
@ -484,7 +486,7 @@ struct context {
#define port_switch(ntp, otp) _port_switch(ntp, otp)
#else
#define port_switch(ntp, otp) { \
if ((stkalign_t *)(__get_SP() - sizeof(struct intctx)) < otp->p_stklimit) \
if (getRemainingStack(otp) < 0) \
chDbgPanic("stack overflow"); \
_port_switch(ntp, otp); \
}

View File

@ -205,8 +205,8 @@
#define TS_SERIAL_RX_PIN 11
#define TS_SERIAL_AF 7
#define LED_CRANKING_STATUS_PORT GPIOD
#define LED_CRANKING_STATUS_PIN GPIOD_LED3
#define LED_WARNING_PORT GPIOD
#define LED_WARNING_PIN GPIOD_LED3
#define LED_RUNNING_STATUS_PORT GPIOD
#define LED_RUNNING_STATUS_PIN GPIOD_LED4

View File

@ -10,15 +10,17 @@
#ifndef EFIFEATURES_H_
#define EFIFEATURES_H_
#define EFI_USE_CCM TRUE
//#define EFI_UART_ECHO_TEST_MODE TRUE
#define EFI_USE_UART_FOR_CONSOLE FALSE
/**
* Build-in logic analyzer support. Logic analyzer viewer is one of the java console panes.
*/
#define EFI_WAVE_ANALYZER TRUE
#define EFI_WAVE_CHART TRUE
#define EFI_ANALOG_CHART TRUE
//#define SERIAL_SPEED (8 * 115200)
//#define SERIAL_SPEED (2 * 115200)
#define SERIAL_SPEED 115200
@ -28,10 +30,6 @@
*/
#define EFI_TUNER_STUDIO TRUE
#define EFI_SERIAL_OVER_USB TRUE
#define EFI_SERIAL_OVER_UART FALSE
//#define EFI_TUNER_STUDIO_OVER_USB TRUE
/**
* TunerStudio debug output
*/
@ -82,19 +80,6 @@
#define EFI_ENGINE_EMULATOR TRUE
#define EFI_EMULATE_POSITION_SENSORS TRUE
#if EFI_TUNER_STUDIO
#if EFI_SERIAL_OVER_USB
#if EFI_TUNER_STUDIO_OVER_USB
#pragma "Cannot be EFI_SERIAL_OVER_USB and EFI_TUNER_STUDIO_OVER_USB at the same time"
#endif
#else
#if EFI_TUNER_STUDIO_OVER_USB
#else
#pragma "Cannot be serial over USART and TUNER_STUDIO over USART at the same time"
#endif
#endif /* EFI_TUNER_STUDIO */
#endif /* EFI_SERIAL_OVER_USB */
/**
* This macros is used to hide pieces of the code from unit tests, so it only makes sense in folders exposed to the tests project.
* This macros is NOT about taking out logging in general.
@ -120,7 +105,18 @@
#define EFI_SUPPORT_NISSAN_PRIMERA TRUE
#define EFI_SUPPORT_1995_FORD_INLINE_6 TRUE
#if defined __GNUC__
#define EFI_PERF_METRICS TRUE
#define EFI_ANALOG_CHART TRUE
#define EFI_WAVE_CHART TRUE
#define DL_OUTPUT_BUFFER 9000
#else
// todo: CCM usage for IAR?
#define EFI_PERF_METRICS FALSE
#define EFI_ANALOG_CHART FALSE
#define EFI_WAVE_CHART FALSE
#define DL_OUTPUT_BUFFER 6000
#endif
/**
* Do we need GPS logic?

View File

@ -1,5 +1,5 @@
/**
* @file GY6_139QMB.c
* @file GY6_139QMB.cpp
* @brief 139qmb default engine configuration
*
* @date Feb 13, 2014
@ -7,6 +7,7 @@
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "GY6_139QMB.h"
void setGy6139qmbDefaultEngineConfiguration(engine_configuration_s *engineConfiguration) {
@ -17,7 +18,7 @@ void setGy6139qmbDefaultEngineConfiguration(engine_configuration_s *engineConfig
engineConfiguration->globalTriggerAngleOffset = 15;
engineConfiguration->analogChartMode = AC_MAP;
engineConfiguration->cylindersCount = 1;
engineConfiguration->rpmMultiplier = 1;
setOperationMode(engineConfiguration, FOUR_STROKE_CRANK_SENSOR);
engineConfiguration->firingOrder = FO_ONE_CYLINDER;

View File

@ -1,5 +1,5 @@
/**
* @file audi_aan.c
* @file audi_aan.cpp
* @brief Audo AAN default engine configuration
*
* @date Nov 24, 2013

View File

@ -1,5 +1,5 @@
/**
* @file dodge_neon.c
* @file dodge_neon.cpp
*
* DODGE_NEON_1995 = 2
*
@ -18,6 +18,7 @@
void setDodgeNeonEngineConfiguration(engine_configuration_s *engineConfiguration,
board_configuration_s *boardConfiguration) {
engineConfiguration->triggerConfig.triggerType = TT_DODGE_NEON;
engineConfiguration->engineLoadMode = LM_TPS;
@ -39,10 +40,8 @@ void setDodgeNeonEngineConfiguration(engine_configuration_s *engineConfiguration
// set_whole_fuel_map 3
setWholeFuelMap(engineConfiguration, 3);
engineConfiguration->triggerConfig.syncRatioFrom = 0.72 * 0.8;
engineConfiguration->triggerConfig.syncRatioTo = 0.72 * 1.3;
setTriggerSynchronizationGap(engineConfiguration, 0.72);
engineConfiguration->triggerConfig.isSynchronizationNeeded = TRUE;
engineConfiguration->triggerConfig.useRiseEdge = FALSE;
engineConfiguration->needSecondTriggerInput = TRUE;

View File

@ -1,15 +0,0 @@
/**
* @file engines.h
*
* @date Aug 30, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef ENGINE_H_
#define ENGINE_H_
#include "boards.h"
#include "efifeatures.h"
#include "rusefi_enums.h"
#endif /* ENGINE_H_ */

View File

@ -14,5 +14,6 @@ ENGINES_SRC_CPP = $(PROJECT_DIR)/config/engines/ford_aspire.cpp \
$(PROJECT_DIR)/config/engines/honda_accord.cpp \
$(PROJECT_DIR)/config/engines/snow_blower.cpp \
$(PROJECT_DIR)/config/engines/GY6_139QMB.cpp \
$(PROJECT_DIR)/config/engines/rover_v8.cpp \
$(PROJECT_DIR)/config/engines/mazda_323.cpp \
$(PROJECT_DIR)/config/engines/saturn_ion.cpp

View File

@ -1,5 +1,5 @@
/**
* @file ford_1995_inline_6.c
* @file ford_1995_inline_6.cpp
* @brief Default engine configuration for a 1995 Ford inline 6 engine
*
* http://rusefi.com/forum/viewtopic.php?f=3&t=469
@ -23,10 +23,7 @@
void setFordInline6(engine_configuration_s *engineConfiguration, board_configuration_s *boardConfiguration) {
engineConfiguration->cylindersCount = 6;
/**
* 0.5 means primary position sensor is on a camshaft
*/
engineConfiguration->rpmMultiplier = 0.5;
setOperationMode(engineConfiguration, FOUR_STROKE_CAM_SENSOR);
engineConfiguration->ignitionMode = IM_ONE_COIL;
engineConfiguration->firingOrder = FO_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4;
@ -41,6 +38,7 @@ void setFordInline6(engine_configuration_s *engineConfiguration, board_configura
/**
* We treat the trigger as 6/0 toothed wheel
*/
engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL;
engineConfiguration->triggerConfig.totalToothCount = 6;
engineConfiguration->triggerConfig.skippedToothCount = 0;
engineConfiguration->triggerConfig.isSynchronizationNeeded = FALSE;

View File

@ -13,7 +13,6 @@
#include "ford_aspire.h"
#include "allsensors.h"
#include "engines.h"
#include "engine_math.h"
#include "advance_map.h"
#include "engine_configuration.h"
@ -103,6 +102,10 @@ void setFordAspireEngineConfiguration(engine_configuration_s *engineConfiguratio
// engineConfiguration->ignitionPinMode = OM_INVERTED;
engineConfiguration->cylindersCount = 4;
engineConfiguration->displacement = 1.3;
// Denso 195500-2110
engineConfiguration->injectorFlow = 119.8;
engineConfiguration->firingOrder = FO_1_THEN_3_THEN_4_THEN2;
engineConfiguration->globalTriggerAngleOffset = 175;
engineConfiguration->ignitionOffset = 98 - 11;

View File

@ -1,5 +1,5 @@
/**
* @file ford_fiesta.c
* @file ford_fiesta.cpp
* @brief European 1990 Ford Fiesta
*
* FORD_FIESTA = 4
@ -18,8 +18,7 @@
void setFordFiestaDefaultEngineConfiguration(engine_configuration_s *engineConfiguration) {
engineConfiguration->rpmHardLimit = 7000;
// only crankshaft sensor so far
engineConfiguration->rpmMultiplier = 1;
setOperationMode(engineConfiguration, FOUR_STROKE_CRANK_SENSOR);
engineConfiguration->triggerConfig.totalToothCount = 36;
engineConfiguration->triggerConfig.skippedToothCount = 1;

View File

@ -1,5 +1,5 @@
/**
* @file honda_accord.c
* @file honda_accord.cpp
*
* @date Jan 12, 2014
* @author Andrey Belomutskiy, (c) 2012-2014

View File

@ -1,5 +1,5 @@
/**
* @file mazda_323.c
* @file mazda_323.cpp
*
* @date Mar 8, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
@ -8,7 +8,8 @@
#include "mazda_323.h"
void setMazda323EngineConfiguration(engine_configuration_s *engineConfiguration) {
engineConfiguration->cylindersCount = 6;
engineConfiguration->cylindersCount = 4;
engineConfiguration->displacement = 1.6;
engineConfiguration->ignitionMode = IM_ONE_COIL;

View File

@ -1,5 +1,5 @@
/**
* @file mazda_miata_nb.c
* @file mazda_miata_nb.cpp
*
* MAZDA_MIATA_NB = 9
*
@ -16,10 +16,8 @@ void setMazdaMiataNbEngineConfiguration(engine_configuration_s *engineConfigurat
engineConfiguration->rpmHardLimit = 3000; // yes, 3k. let's play it safe for now
engineConfiguration->triggerConfig.triggerType = TT_MAZDA_MIATA_NB;
engineConfiguration->triggerConfig.isSynchronizationNeeded = TRUE;
engineConfiguration->triggerConfig.syncRatioFrom = 0.11 * 0.7;
engineConfiguration->triggerConfig.syncRatioTo = 0.11 * 1.3;
setTriggerSynchronizationGap(engineConfiguration, 0.11);
engineConfiguration->triggerConfig.useRiseEdge = FALSE;
engineConfiguration->globalTriggerAngleOffset = 276;

View File

@ -1,5 +1,7 @@
/**
* @file nissan_primera.c
* @file nissan_primera.cpp
*
* engine_type 5
*
* @date Oct 14, 2013
* @author Andrey Belomutskiy, (c) 2012-2014

View File

@ -0,0 +1,70 @@
/**
* @file rover_v8.cpp
*
* V8, firing order 18436572
*
* ROVER_V8 = 10
*
* @date Jun 27, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "rover_v8.h"
void setRoverv8(engine_configuration_s *engineConfiguration,
board_configuration_s *boardConfiguration) {
setOperationMode(engineConfiguration, FOUR_STROKE_CRANK_SENSOR);
engineConfiguration->triggerConfig.totalToothCount = 36;
engineConfiguration->triggerConfig.skippedToothCount = 1;
// todo: displacement? 4 liters?
engineConfiguration->displacement = 4;
engineConfiguration->cylindersCount = 8;
engineConfiguration->firingOrder = FO_1_8_4_3_6_5_7_2;
// set_rpm_hard_limit 4000
engineConfiguration->rpmHardLimit = 4000; // yes, 4k. let's play it safe for now
// set_cranking_rpm 550
engineConfiguration->crankingSettings.crankingRpm = 550;
// set_whole_fuel_map 3
setWholeFuelMap(engineConfiguration, 3);
// set_cranking_injection_mode 0
engineConfiguration->crankingInjectionMode = IM_SEQUENTIAL;
// set_injection_mode 1
engineConfiguration->injectionMode = IM_SEQUENTIAL;
// set_ignition_mode 2
engineConfiguration->ignitionMode = IM_WASTED_SPARK;
// Frankenstein: low side - inj #1: PC14
// Frankenstein: low side - inj #2: PC15
// Frankenstein: low side - inj #3: PE6
// Frankenstein: low side - inj #4: PC13
// Frankenstein: low side - inj #5: PE4
// Frankenstein: low side - inj #6: PE5
// Frankenstein: low side - inj #7: PE2
// Frankenstein: low side - inj #8: PE3
// Frankenstein: low side - inj #9: PE0
// Frankenstein: low side - inj #10: PE1
// Frankenstein: low side - inj #11: PB8
// Frankenstein: low side - inj #12: PB9
boardConfiguration->injectionPins[0] = GPIOB_9; // Frankenstein: low side - inj #12
boardConfiguration->injectionPins[1] = GPIOB_8; // Frankenstein: low side - inj #11
boardConfiguration->injectionPins[2] = GPIOE_3; // Frankenstein: low side - inj #8
boardConfiguration->injectionPins[3] = GPIOE_5; // Frankenstein: low side - inj #6
boardConfiguration->fuelPumpPin = GPIOC_13; // Frankenstein: low side - inj #4
boardConfiguration->fuelPumpPinMode = OM_DEFAULT;
// set_injection_pin_mode 0
boardConfiguration->injectionPinMode = OM_DEFAULT;
}

View File

@ -0,0 +1,15 @@
/**
* @file rover_v8.h
*
* @date Jun 27, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef ROVER_V8_H_
#define ROVER_V8_H_
#include "engine_configuration.h"
void setRoverv8(engine_configuration_s *engineConfiguration,
board_configuration_s *boardConfiguration);
#endif /* ROVER_V8_H_ */

View File

@ -1,5 +1,5 @@
/**
* @file snow_blower.c
* @file snow_blower.cpp
* @brief Default configuration of a single-cylinder engine
*
* @date Sep 9, 2013
@ -7,8 +7,3 @@
*/
#include "main.h"
#if EFI_ENGINE_SNOW_BLOWER
#endif

View File

@ -28,8 +28,8 @@
/*
* ST32F407xG memory setup.
*/
__main_stack_size__ = 0x0400;
__process_stack_size__ = 0x0400;
__main_stack_size__ = 0x0600;
__process_stack_size__ = 0x0600;
MEMORY
{
@ -127,7 +127,7 @@ SECTIONS
__main_thread_stack_end__ = .;
} > ram
.ccm :
.ccm (NOLOAD) :
{
PROVIDE(_cmm_start = .);
. = ALIGN(4);

View File

@ -45,11 +45,11 @@
}
#define PORT_IDLE_THREAD_STACK_SIZE 256
#define PORT_IDLE_THREAD_STACK_SIZE 1024
#define PORT_INT_REQUIRED_STACK 128
#define PORT_INT_REQUIRED_STACK 768
#define CHPRINTF_USE_FLOAT TRUE
#define CHPRINTF_USE_FLOAT TRUE
/**
* number of ticks per second
@ -480,6 +480,8 @@
*/
#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
#define THREAD_EXT_FIELDS \
void *activeStack; \
int remainingStack; \
/* Add threads custom fields here.*/
#endif

View File

@ -30,7 +30,9 @@
#define STM32F4xx_MCUCONF
#include "engines.h"
#include "boards.h"
#include "efifeatures.h"
#include "rusefi_enums.h"
/*
* HAL driver system settings.

View File

@ -22,12 +22,19 @@
#include "console_io.h"
#if EFI_PROD_CODE
extern SerialUSBDriver SDU1;
#include "usbcfg.h"
#include "usbconsole.h"
#endif
#include "rfiutil.h"
int lastWriteSize;
int lastWriteActual;
static bool_t isSerialConsoleStarted = FALSE;
static EventListener consoleEventListener;
/**
* @brief Reads a whole line from the input channel.
*
@ -38,7 +45,7 @@ static bool_t isSerialConsoleStarted = FALSE;
* @retval TRUE the channel was reset or CTRL-D pressed.
* @retval FALSE operation successful.
*/
static bool_t getConsoleLine(BaseSequentialStream *chp, char *line, unsigned size) {
static bool getConsoleLine(BaseSequentialStream *chp, char *line, unsigned size) {
char *p = line;
while (TRUE) {
@ -49,6 +56,30 @@ static bool_t getConsoleLine(BaseSequentialStream *chp, char *line, unsigned siz
}
short c = (short) chSequentialStreamGet(chp);
if (isSerialOverUart()) {
uint32_t flags;
chSysLock()
;
flags = chEvtGetAndClearFlagsI(&consoleEventListener);
chSysUnlock()
;
if (flags & SD_OVERRUN_ERROR) {
// firmwareError("serial overrun");
}
}
#if EFI_UART_ECHO_TEST_MODE
/**
* That's test code - let's test connectivity
*/
consolePutChar((uint8_t) c);
continue;
#endif
if (c < 0)
return TRUE;
if (c == 4) {
@ -84,13 +115,19 @@ static char consoleInput[] = "
void (*console_line_callback)(char *);
static WORKING_AREA(consoleThreadStack, 2 * UTILITY_THREAD_STACK_SIZE);
static bool is_serial_over_uart;
bool isSerialOverUart(void) {
return is_serial_over_uart;
}
static THD_WORKING_AREA(consoleThreadStack, 2 * UTILITY_THREAD_STACK_SIZE);
static msg_t consoleThreadThreadEntryPoint(void *arg) {
(void) arg;
chRegSetThreadName("console thread");
while (TRUE) {
bool_t end = getConsoleLine((BaseSequentialStream *) CONSOLE_CHANNEL, consoleInput, sizeof(consoleInput));
bool end = getConsoleLine((BaseSequentialStream*) getConsoleChannel(), consoleInput, sizeof(consoleInput));
if (end) {
// firmware simulator is the only case when this happens
continue;
@ -103,47 +140,68 @@ static msg_t consoleThreadThreadEntryPoint(void *arg) {
#endif
}
#if EFI_SERIAL_OVER_USB
#else
#if EFI_SERIAL_OVER_UART
static SerialConfig serialConfig = {SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0};
#endif /* EFI_SERIAL_OVER_UART */
#endif /* EFI_SERIAL_OVER_USB */
#if EFI_PROD_CODE
#if ! EFI_SERIAL_OVER_USB && ! EFI_SIMULATOR
int isConsoleReady(void) {
return isSerialConsoleStarted;
static SerialConfig serialConfig = { SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };
SerialDriver * getConsoleChannel(void) {
if (isSerialOverUart()) {
return (SerialDriver *) EFI_CONSOLE_UART_DEVICE;
} else {
return (SerialDriver *) &SDU1;
}
}
#endif
int isConsoleReady(void) {
if (isSerialOverUart()) {
return isSerialConsoleStarted;
} else {
return is_usb_serial_ready();
}
}
#endif /* EFI_PROD_CODE */
void consolePutChar(int x) {
chSequentialStreamPut(CONSOLE_CHANNEL, (uint8_t )(x));
chSequentialStreamPut(getConsoleChannel(), (uint8_t )(x));
}
// 10 seconds
#define CONSOLE_WRITE_TIMEOUT 10000
void consoleOutputBuffer(const int8_t *buf, int size) {
chSequentialStreamWrite(CONSOLE_CHANNEL, buf, size);
lastWriteSize = size;
#if !EFI_UART_ECHO_TEST_MODE
lastWriteActual = chnWriteTimeout(getConsoleChannel(), buf, size, CONSOLE_WRITE_TIMEOUT);
// if (r != size)
// firmwareError("Partial console write");
#endif /* EFI_UART_ECHO_TEST_MODE */
}
void startConsole(void (*console_line_callback_p)(char *)) {
console_line_callback = console_line_callback_p;
#if EFI_SERIAL_OVER_USB
usb_serial_start();
#else
#if EFI_SERIAL_OVER_UART
/*
* Activates the serial using the driver default configuration (that's 38400)
* it is important to set 'NONE' as flow control! in terminal application on the PC
*/
sdStart(CONSOLE_CHANNEL, &serialConfig);
#if EFI_PROD_CODE
is_serial_over_uart = palReadPad(GPIOA, GPIOA_BUTTON) != EFI_USE_UART_FOR_CONSOLE;
// cannot use pin repository here because pin repository prints to console
palSetPadMode(EFI_CONSOLE_RX_PORT, EFI_CONSOLE_RX_PIN, PAL_MODE_ALTERNATE(EFI_CONSOLE_AF));
palSetPadMode(EFI_CONSOLE_TX_PORT, EFI_CONSOLE_TX_PIN, PAL_MODE_ALTERNATE(EFI_CONSOLE_AF));
if (isSerialOverUart()) {
/*
* Activates the serial using the driver default configuration (that's 38400)
* it is important to set 'NONE' as flow control! in terminal application on the PC
*/
sdStart(EFI_CONSOLE_UART_DEVICE, &serialConfig);
isSerialConsoleStarted = TRUE;
#endif /* EFI_SERIAL_OVER_UART */
#endif /* EFI_SERIAL_OVER_USB */
// cannot use pin repository here because pin repository prints to console
palSetPadMode(EFI_CONSOLE_RX_PORT, EFI_CONSOLE_RX_PIN, PAL_MODE_ALTERNATE(EFI_CONSOLE_AF));
palSetPadMode(EFI_CONSOLE_TX_PORT, EFI_CONSOLE_TX_PIN, PAL_MODE_ALTERNATE(EFI_CONSOLE_AF));
isSerialConsoleStarted = TRUE;
chEvtRegisterMask((EventSource *) chnGetEventSource(EFI_CONSOLE_UART_DEVICE), &consoleEventListener, 1);
} else {
usb_serial_start();
}
#endif /* EFI_PROD_CODE */
chThdCreateStatic(consoleThreadStack, sizeof(consoleThreadStack), NORMALPRIO, consoleThreadThreadEntryPoint, NULL);
}
@ -152,7 +210,7 @@ extern cnt_t dbg_isr_cnt;
/**
* @return TRUE if already in locked context
*/
bool_t lockAnyContext(void) {
bool lockAnyContext(void) {
int alreadyLocked = isLocked();
if (alreadyLocked)
return TRUE;

View File

@ -21,23 +21,18 @@
#include "efifeatures.h"
#include "boards.h"
#if EFI_SERIAL_OVER_USB
#include "usbcfg.h"
extern SerialUSBDriver SDU1;
#define CONSOLE_CHANNEL (&SDU1)
#else
#define CONSOLE_CHANNEL EFI_CONSOLE_UART_DEVICE
#endif
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
SerialDriver * getConsoleChannel(void);
void consolePutChar(int x);
void consoleOutputBuffer(const int8_t *buf, int size);
void startConsole(void (*console_line_callback_p)(char *));
int isConsoleReady(void);
bool isSerialOverUart(void);
#ifdef __cplusplus
}

View File

@ -46,6 +46,10 @@ static void myfatal(void) {
chDbgCheck(0, "my fatal");
}
static void myerror(void) {
firmwareError("firmwareError: %d", getRusEfiVersion());
}
static void sayHello(void) {
printMsg(&logger, "*** rusEFI (c) Andrey Belomutskiy, 2012-2014. All rights reserved.");
printMsg(&logger, "rusEFI v%d@%d", getRusEfiVersion(), SVN_VERSION);
@ -69,6 +73,9 @@ static void sayHello(void) {
printMsg(&logger, "STM32_PCLK2=%d", STM32_PCLK2);
#endif
printMsg(&logger, "PORT_IDLE_THREAD_STACK_SIZE=%d", PORT_IDLE_THREAD_STACK_SIZE);
printMsg(&logger, "CH_DBG_ENABLE_ASSERTS=%d", CH_DBG_ENABLE_ASSERTS);
printMsg(&logger, "CH_DBG_ENABLED=%d", CH_DBG_ENABLED);
printMsg(&logger, "CH_DBG_SYSTEM_STATE_CHECK=%d", CH_DBG_SYSTEM_STATE_CHECK);
@ -91,19 +98,8 @@ static void sayHello(void) {
printMsg(&logger, "EFI_SIGNAL_EXECUTOR_HW_TIMER=%d", EFI_SIGNAL_EXECUTOR_HW_TIMER);
#endif
#ifdef EFI_TUNER_STUDIO_OVER_USB
printMsg(&logger, "EFI_TUNER_STUDIO_OVER_USB=%d", EFI_TUNER_STUDIO_OVER_USB);
#else
printMsg(&logger, "EFI_TUNER_STUDIO_OVER_USB=%d", 0);
#endif
#ifdef EFI_SHAFT_POSITION_INPUT
printMsg(&logger, "EFI_SHAFT_POSITION_INPUT=%d", EFI_SHAFT_POSITION_INPUT);
#endif
#ifdef EFI_INTERNAL_ADC
printMsg(&logger, "EFI_INTERNAL_ADC=%d", EFI_INTERNAL_ADC);
#endif
// printSimpleMsg(&logger, "", );
// printSimpleMsg(&logger, "", );
@ -119,6 +115,7 @@ static void sayHello(void) {
* This methods prints all threads and their total times
*/
static void cmd_threads(void) {
#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__)
static const char *states[] = { THD_STATE_NAMES };
Thread *tp;
@ -130,6 +127,7 @@ static void cmd_threads(void) {
states[tp->p_state], (uint32_t) tp->p_time, tp->p_name);
tp = chRegNextThread(tp);
} while (tp != NULL );
#endif
}
void sendOutConfirmation(char *value, int i) {
@ -140,12 +138,14 @@ void sendOutConfirmation(char *value, int i) {
* This methods prints the message to whatever is configured as our primary console
*/
void print(const char *format, ...) {
#if !EFI_UART_ECHO_TEST_MODE
if (!isConsoleReady())
return;
va_list ap;
va_start(ap, format);
chvprintf((BaseSequentialStream *)CONSOLE_CHANNEL, format, ap);
chvprintf((BaseSequentialStream*)getConsoleChannel(), format, ap);
va_end(ap);
#endif /* EFI_UART_ECHO_TEST_MODE */
}
void initializeConsole() {
@ -163,5 +163,6 @@ void initializeConsole() {
#endif
addConsoleAction("fatal", myfatal);
addConsoleAction("error", myerror);
addConsoleAction("threadsinfo", cmd_threads);
}

View File

@ -38,10 +38,8 @@
#include "io_pins.h"
#include "mmc_card.h"
#include "console_io.h"
#define PRINT_FIRMWARE_ONCE TRUE
static bool_t firmwareErrorReported = FALSE;
#include "malfunction_central.h"
#include "speed_density.h"
#include "advance_map.h"
#if EFI_TUNER_STUDIO
@ -57,6 +55,7 @@ static bool_t firmwareErrorReported = FALSE;
#include "engine_configuration.h"
#include "rfiutil.h"
#include "svnversion.h"
#include "engine.h"
#if EFI_PROD_CODE
// todo: move this logic to algo folder!
@ -65,6 +64,8 @@ static bool_t firmwareErrorReported = FALSE;
#include "rusefi.h"
#endif
extern Engine engine;
// this 'true' value is needed for simulator
static volatile int fullLog = TRUE;
int warningEnabled = TRUE;
@ -72,6 +73,7 @@ int warningEnabled = TRUE;
extern engine_configuration_s * engineConfiguration;
extern engine_configuration2_s * engineConfiguration2;
extern board_configuration_s *boardConfiguration;
#define FULL_LOGGING_KEY "fl"
#if EFI_PROD_CODE || EFI_SIMULATOR
@ -97,7 +99,7 @@ static void reportSensorF(const char *caption, float value, int precision) {
#endif /* EFI_FILE_LOGGING */
}
static void reportSensorI(char *caption, int value) {
static void reportSensorI(const char *caption, int value) {
#if EFI_PROD_CODE || EFI_SIMULATOR
debugInt(&logger, caption, value);
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
@ -154,6 +156,7 @@ void printSensors(void) {
}
void printState(int currentCkpEventCounter) {
#if EFI_SHAFT_POSITION_INPUT
printSensors();
int rpm = getRpm();
@ -177,6 +180,7 @@ void printState(int currentCkpEventCounter) {
// float fuel = getDefaultFuel(rpm, map);
// debugFloat(&logger, "d_fuel", fuel, 2);
#endif /* EFI_SHAFT_POSITION_INPUT */
}
#define INITIAL_FULL_LOG TRUE
@ -201,32 +205,31 @@ static void printStatus(void) {
// return getTCharge(getCurrentRpm(), tps, cltK, iatK);
//}
#if EFI_CUSTOM_PANIC_METHOD
extern char *dbg_panic_file;
extern int dbg_panic_line;
#endif
//#if EFI_CUSTOM_PANIC_METHOD
//extern char *dbg_panic_file;
//extern int dbg_panic_line;
//#endif
bool_t hasFatalError(void) {
return dbg_panic_msg != NULL;
}
static void checkIfShouldHalt(void) {
#if CH_DBG_ENABLED
if (hasFatalError()) {
setOutputPinValue(LED_ERROR, 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
}
//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
@ -253,14 +256,14 @@ extern char errorMessageBuffer[200];
void updateDevConsoleState(void) {
if (!isConsoleReady())
return;
checkIfShouldHalt();
// looks like this is not needed anymore
// checkIfShouldHalt();
printPending();
if (hasFirmwareError()) {
if (!firmwareErrorReported || !PRINT_FIRMWARE_ONCE)
printMsg(&logger, "firmware error: %s", errorMessageBuffer);
firmwareErrorReported = TRUE;
printMsg(&logger, "firmware error: %s", errorMessageBuffer);
warningEnabled = FALSE;
chThdSleepMilliseconds(200);
return;
}
@ -324,7 +327,7 @@ void updateHD44780lcd(void) {
lcd_HD44780_print_char('R');
lcd_HD44780_set_position(0, 10);
char * ptr = itoa10((uint8_t*) buffer, getRpm());
char * ptr = itoa10(buffer, getRpm());
ptr[0] = 0;
int len = ptr - buffer;
for (int i = 0; i < 6 - len; i++)
@ -346,7 +349,7 @@ void updateHD44780lcd(void) {
}
#endif /* EFI_PROD_CODE */
static WORKING_AREA(lcdThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(lcdThreadStack, UTILITY_THREAD_STACK_SIZE);
static void lcdThread(void *arg) {
chRegSetThreadName("lcd");
@ -354,20 +357,49 @@ static void lcdThread(void *arg) {
#if EFI_HD44780_LCD
updateHD44780lcd();
#endif
chThdSleepMilliseconds(50);
chThdSleepMilliseconds(boardConfiguration->lcdThreadPeriod);
}
}
static WORKING_AREA(tsThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(tsThreadStack, UTILITY_THREAD_STACK_SIZE);
#if EFI_TUNER_STUDIO
extern TunerStudioOutputChannels tsOutputChannels;
void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels) {
#if EFI_SHAFT_POSITION_INPUT
int rpm = getRpm();
#else
int rpm = 0;
#endif
float tps = getTPS();
float coolant = getCoolantTemperature();
float intake = getIntakeAirTemperature();
tsOutputChannels->rpm = rpm;
tsOutputChannels->coolant_temperature = coolant;
tsOutputChannels->intake_air_temperature = intake;
tsOutputChannels->throttle_positon = tps;
tsOutputChannels->mass_air_flow = getMaf();
tsOutputChannels->air_fuel_ratio = getAfr();
tsOutputChannels->v_batt = getVBatt();
tsOutputChannels->tpsADC = getTPS10bitAdc();
tsOutputChannels->atmospherePressure = getBaroPressure();
tsOutputChannels->manifold_air_pressure = getMap();
tsOutputChannels->checkEngine = hasErrorCodes();
tsOutputChannels->tCharge = getTCharge(rpm, tps, coolant, intake);
}
#endif /* EFI_TUNER_STUDIO */
static void tsStatusThread(void *arg) {
chRegSetThreadName("tuner s");
while (true) {
#if EFI_TUNER_STUDIO
// sensor state for EFI Analytics Tuner Studio
updateTunerStudioState();
updateTunerStudioState(&tsOutputChannels);
#endif /* EFI_TUNER_STUDIO */
chThdSleepMilliseconds(50);
chThdSleepMilliseconds(boardConfiguration->tunerStudioThreadPeriod);
}
}

View File

@ -37,13 +37,37 @@
#include "tunerstudio_configuration.h"
#include "malfunction_central.h"
#include "wave_math.h"
#include "console_io.h"
#include "crc.h"
#if EFI_TUNER_STUDIO
#define MAX_PAGE_ID 5
#define PAGE_0_SIZE 1356
// in MS, that's 10 seconds
#define TS_READ_TIMEOUT 10000
#define TS_SERIAL_UART_DEVICE &SD3
//#define TS_SERIAL_SPEED 115200
#define TS_SERIAL_SPEED 38400
#define PROTOCOL "001"
extern SerialUSBDriver SDU1;
BaseChannel * getTsSerialDevice(void) {
if (isSerialOverUart()) {
// if console uses UART then TS uses USB
return (BaseChannel *) &SDU1;
} else {
return (BaseChannel *) TS_SERIAL_UART_DEVICE;
}
}
static Logging logger;
extern engine_configuration_s *engineConfiguration;
extern board_configuration_s *boardConfiguration;
extern persistent_config_s configWorkingCopy;
extern persistent_config_container_s persistentState;
@ -52,47 +76,49 @@ extern SerialUSBDriver SDU1;
static efitimems_t previousWriteReportMs = 0;
#if EFI_TUNER_STUDIO_OVER_USB
#define ts_serail_ready() is_usb_serial_ready()
#else
#define ts_serail_ready() TRUE
static SerialConfig tsSerialConfig = { TS_SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };
#endif /* EFI_TUNER_STUDIO_OVER_USB */
static int ts_serail_ready(void) {
if (isSerialOverUart()) {
// TS uses USB when console uses serial
return is_usb_serial_ready();
} else {
// TS uses serial when console uses USB
return TRUE;
}
}
static WORKING_AREA(TS_WORKING_AREA, UTILITY_THREAD_STACK_SIZE);
static SerialConfig tsSerialConfig = { TS_SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };
static THD_WORKING_AREA(TS_WORKING_AREA, UTILITY_THREAD_STACK_SIZE);
static int tsCounter = 0;
static int writeCounter = 0;
static short pageId;
static TunerStudioWriteRequest writeRequest;
//static TunerStudioWriteValueRequest writeValueRequest;
//static TunerStudioWriteChunkRequest writeChunkRequest;
extern TunerStudioOutputChannels tsOutputChannels;
//char *constantsAsPtr = (char *) &configWorkingCopy;
extern TunerStudioState tsState;
static void printStats(void) {
#if EFI_TUNER_STUDIO_OVER_USB
#else
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_TUNER_STUDIO_OVER_USB */
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);
}
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 C counter=%d", tsState.readPageCommandsCounter);
scheduleMsg(&logger, "TunerStudio P counter=%d", tsState.readPageCommandsCounter);
scheduleMsg(&logger, "TunerStudio B counter=%d", tsState.burnCommandCounter);
scheduleMsg(&logger, "TunerStudio W counter=%d", writeCounter);
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, "page 0 size=%d", getTunerStudioPageSize(0));
scheduleMsg(&logger, "page 1 size=%d", getTunerStudioPageSize(1));
}
void tunerStudioWriteData(const uint8_t * buffer, int size) {
chSequentialStreamWrite(TS_SERIAL_DEVICE, buffer, size);
chSequentialStreamWrite(getTsSerialDevice(), buffer, size);
}
void tunerStudioDebug(char *msg) {
@ -108,6 +134,11 @@ char *getWorkingPageAddr(int pageIndex) {
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;
}
@ -115,86 +146,143 @@ char *getWorkingPageAddr(int pageIndex) {
int getTunerStudioPageSize(int pageIndex) {
switch (pageIndex) {
case 0:
return sizeof(configWorkingCopy.engineConfiguration);
return PAGE_0_SIZE;
case 1:
return sizeof(configWorkingCopy.boardConfiguration);
case 2:
case 3:
case 4:
return 1024;
}
return 0;
}
void handlePageSelectCommand(uint16_t pageId) {
tsState.pageCommandCounter++;
tsState.currentPageId = pageId;
scheduleMsg(&logger, "page %d selected", tsState.currentPageId);
tunerStudioWriteCrcPacket(TS_RESPONSE_OK, NULL, 0);
}
/**
* This command is needed to make the whole transfer a bit faster
* @note See also handleWriteValueCommand
*/
void handleWriteChunkCommand(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);
// out of range
tsState.errorCounter++;
offset = 0;
}
if (count > getTunerStudioPageSize(tsState.currentPageId)) {
scheduleMsg(&logger, "ERROR count %d", count);
// out of range
tsState.errorCounter++;
count = 0;
}
uint8_t * addr = (uint8_t *) (getWorkingPageAddr(tsState.currentPageId) + offset);
// memcpy(addr, content, count);
tunerStudioWriteCrcPacket(TS_RESPONSE_OK, NULL, 0);
}
/**
* 'Write' command receives a single value at a given offset
* @note Writing values one by one is pretty slow
*/
void handleValueWriteCommand(void) {
writeCounter++;
void handleWriteValueCommand(uint16_t page, uint16_t offset, uint8_t value) {
tsState.writeValueCommandCounter++;
//tunerStudioDebug("got W (Write)"); // we can get a lot of these
tsState.currentPageId = page;
//tunerStudioDebug("got W (Write)"); // we can get a lot of these
int recieved = chSequentialStreamRead(TS_SERIAL_DEVICE, (uint8_t *)&pageId, 2);
if (recieved != 2) {
tsState.errorCounter++;
return;
}
#if EFI_TUNER_STUDIO_VERBOSE
// scheduleMsg(&logger, "Page number %d\r\n", pageId); // we can get a lot of these
#endif
int size = sizeof(TunerStudioWriteRequest);
int size = sizeof(TunerStudioWriteValueRequest);
// scheduleMsg(&logger, "Reading %d\r\n", size);
recieved = chSequentialStreamRead(TS_SERIAL_DEVICE, (uint8_t *)&writeRequest, size);
// scheduleMsg(&logger, "got %d", recieved);
// unsigned char offset = writeBuffer[0];
// unsigned char value = writeBuffer[1];
//
if (offset > getTunerStudioPageSize(tsState.currentPageId)) {
scheduleMsg(&logger, "ERROR offset %d", offset);
// out of range
tsState.errorCounter++;
offset = 0;
return;
}
efitimems_t nowMs = currentTimeMillis();
if (nowMs - previousWriteReportMs > 5) {
previousWriteReportMs = nowMs;
// scheduleMsg(&logger, "page %d offset %d: value=%d", pageId, writeRequest.offset, writeRequest.value);
scheduleMsg(&logger, "page %d offset %d: value=%d", tsState.currentPageId, offset, value);
}
getWorkingPageAddr(pageId)[writeRequest.offset] = writeRequest.value;
getWorkingPageAddr(tsState.currentPageId)[offset] = value;
// scheduleMsg(&logger, "va=%d", configWorkingCopy.boardConfiguration.idleValvePin);
}
void handlePageReadCommand(void) {
static void sendErrorCode(void) {
tunerStudioWriteCrcPacket(TS_RESPONSE_CRC_FAILURE, NULL, 0);
}
void handlePageReadCommand(uint16_t pageId, uint16_t offset, uint16_t count) {
tsState.readPageCommandsCounter++;
tunerStudioDebug("got C (Constants)");
int recieved = chSequentialStreamRead(TS_SERIAL_DEVICE, (uint8_t *)&pageId, 2);
if (recieved != 2) {
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;
tsState.errorCounter++;
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);
tunerStudioWriteCrcPacket(TS_RESPONSE_OK, addr, count);
#if EFI_TUNER_STUDIO_VERBOSE
scheduleMsg(&logger, "Page number %d", pageId);
scheduleMsg(&logger, "Sending %d done", size);
#endif
tunerStudioWriteData((const uint8_t *) getWorkingPageAddr(pageId), getTunerStudioPageSize(pageId));
}
/**
* 'Burn' command is a command to commit the changes
*/
void handleBurnCommand(void) {
void handleBurnCommand(uint16_t page) {
tsState.burnCommandCounter++;
tunerStudioDebug("got B (Burn)");
int recieved = chSequentialStreamRead(TS_SERIAL_DEVICE, (uint8_t *)&pageId, 2);
if (recieved != 2) {
tsState.errorCounter++;
return;
}
tsState.currentPageId = page;
#if EFI_TUNER_STUDIO_VERBOSE
scheduleMsg(&logger, "Page number %d\r\n", pageId);
scheduleMsg(&logger, "Page number %d\r\n", tsState.currentPageId);
#endif
// todo: how about some multi-threading?
// todo: how about some multi-threading?
memcpy(&persistentState.persistentConfiguration, &configWorkingCopy, sizeof(persistent_config_s));
scheduleMsg(&logger, "va1=%d", configWorkingCopy.boardConfiguration.idleValvePin);
@ -202,8 +290,15 @@ void handleBurnCommand(void) {
writeToFlash();
incrementGlobalConfigurationVersion();
tunerStudioWriteCrcPacket(TS_RESPONSE_BURN_OK, NULL, 0);
}
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");
@ -216,41 +311,128 @@ static msg_t tsThreadEntryPoint(void *arg) {
wasReady = FALSE;
continue;
}
if (!wasReady) {
wasReady = TRUE;
// scheduleSimpleMsg(&logger, "ts channel is now ready ", hTimeNow());
}
short command = (short) chSequentialStreamGet(TS_SERIAL_DEVICE);
int success = tunerStudioHandleCommand(command);
if (!success && command != 0)
print("got unexpected TunerStudio command %c:%d\r\n", command, command);
tsCounter++;
int recieved = chSequentialStreamRead(getTsSerialDevice(), &firstByte, 1);
if (recieved != 1) {
tsState.errorCounter++;
continue;
}
// scheduleMsg(&logger, "Got first=%x=[%c]", firstByte, firstByte);
if (firstByte == TS_HELLO_COMMAND) {
scheduleMsg(&logger, "Got naked Query command");
handleQueryCommand(FALSE);
continue;
} else if (firstByte == 't' || firstByte == 'T') {
handleTestCommand();
continue;
} else if (firstByte == TS_READ_COMMAND) {
scheduleMsg(&logger, "Got naked READ PAGE???");
continue;
} else if (firstByte == TS_OUTPUT_COMMAND) {
scheduleMsg(&logger, "Got naked Channels???");
continue;
} else if (firstByte == 'F') {
tunerStudioDebug("not ignoring F");
tunerStudioWriteData((const uint8_t *) PROTOCOL, strlen(PROTOCOL));
continue;
}
recieved = chSequentialStreamRead(getTsSerialDevice(), &secondByte, 1);
if (recieved != 1) {
tsState.errorCounter++;
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);
tsState.errorCounter++;
sendErrorCode();
continue;
}
recieved = chnReadTimeout(getTsSerialDevice(), crcIoBuffer, 1, MS2ST(TS_READ_TIMEOUT));
if (recieved != 1) {
scheduleMsg(&logger, "did not receive command");
tsState.errorCounter++;
continue;
}
char command = crcIoBuffer[0];
if (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) {
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));
if (recieved != incomingPacketSize + 4 - 1) {
scheduleMsg(&logger, "got ONLY %d", recieved);
tsState.errorCounter++;
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);
tsState.errorCounter++;
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 = tunerStudioHandleCommand(crcIoBuffer, incomingPacketSize);
if (!success)
print("got unexpected TunerStudio command %x:%c\r\n", command, command);
}
#if defined __GNUC__
return 0;
#endif
}
extern engine_configuration_s *engineConfiguration;
void syncTunerStudioCopy(void) {
memcpy(&configWorkingCopy, &persistentState.persistentConfiguration, sizeof(persistent_config_s));
}
void startTunerStudioConnectivity(void) {
initLogging(&logger, "tuner studio");
#if EFI_TUNER_STUDIO_OVER_USB
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));
memset(&tsState, 0, sizeof(tsState));
if (isSerialOverUart()) {
print("TunerStudio over USB serial");
usb_serial_start();
} else {
sdStart(TS_SERIAL_DEVICE, &tsSerialConfig);
#endif
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);
}
syncTunerStudioCopy();
@ -259,18 +441,22 @@ void startTunerStudioConnectivity(void) {
chThdCreateStatic(TS_WORKING_AREA, sizeof(TS_WORKING_AREA), NORMALPRIO, tsThreadEntryPoint, NULL);
}
void updateTunerStudioState() {
tsOutputChannels.rpm = getRpm();
tsOutputChannels.coolant_temperature = getCoolantTemperature();
tsOutputChannels.intake_air_temperature = getIntakeAirTemperature();
tsOutputChannels.throttle_positon = getTPS();
tsOutputChannels.mass_air_flow = getMaf();
tsOutputChannels.air_fuel_ratio = getAfr();
tsOutputChannels.v_batt = getVBatt();
tsOutputChannels.tpsADC = getTPS10bitAdc();
tsOutputChannels.atmospherePressure = getBaroPressure();
tsOutputChannels.manifold_air_pressure = getMap();
tsOutputChannels.checkEngine = hasErrorCodes();
/**
* 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 */

View File

@ -8,13 +8,18 @@
#ifndef TUNERSTUDIO_H_
#define TUNERSTUDIO_H_
#if EFI_TUNER_STUDIO_OVER_USB
#define TS_SERIAL_DEVICE (&SDU1)
#else
#define TS_SERIAL_DEVICE &SD3
#define TS_SERIAL_SPEED 115200
#include "tunerstudio_configuration.h"
#endif /* EFI_TUNER_STUDIO_OVER_USB */
#if defined __GNUC__
typedef struct
__attribute__((packed)) {
#else
typedef __packed struct {
#endif
short int offset;
short int count;
} TunerStudioWriteChunkRequest;
#if defined __GNUC__
typedef struct
@ -25,19 +30,19 @@ typedef struct
short int offset;
unsigned char value;
} TunerStudioWriteRequest;
} TunerStudioWriteValueRequest;
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif /* __cplusplus */
void startTunerStudioConnectivity(void);
void syncTunerStudioCopy(void);
void updateTunerStudioState(void);
void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels);
void tunerStudioWriteCrcPacket(const uint8_t command, const void *buf, const uint16_t size);
#ifdef __cplusplus
}
}
#endif /* __cplusplus */
#endif /* TUNERSTUDIO_H_ */

View File

@ -2,6 +2,8 @@
* @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
@ -63,17 +65,34 @@ TunerStudioOutputChannels tsOutputChannels;
*/
persistent_config_s configWorkingCopy;
int tunerStudioHandleCommand(short command) {
if (command == 'H') {
handleQueryCommand();
} else if (command == 'O') {
int tunerStudioHandleCommand(char *data, int incomingPacketSize) {
char command = data[0];
data++;
if (command == TS_HELLO_COMMAND) {
tunerStudioDebug("got CRC Query");
handleQueryCommand(TRUE);
} else if (command == TS_OUTPUT_COMMAND) {
handleOutputChannelsCommand();
} else if (command == 'W') {
handleValueWriteCommand();
} else if (command == 'B') {
handleBurnCommand();
} else if (command == 'C') {
handlePageReadCommand();
} else if (command == TS_PAGE_COMMAND) {
uint16_t page = *(uint16_t *) data;
handlePageSelectCommand(page);
} else if (command == TS_CHUNK_WRITE_COMMAND) {
uint16_t offset = *(uint16_t *) data;
uint16_t count = *(uint16_t *) (data + 2);
handleWriteChunkCommand(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(page, offset, value);
} else if (command == TS_BURN_COMMAND) {
uint16_t page = *(uint16_t *) data;
handleBurnCommand(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(page, offset, count);
} else if (command == 't' || command == 'T') {
handleTestCommand();
} else if (command == 'F') {
@ -86,23 +105,23 @@ int tunerStudioHandleCommand(short command) {
* Currently on some firmware versions the F command is not used and is just ignored by the firmware as a unknown command."
*/
} else {
#if EFI_TUNER_STUDIO_OVER_USB
/**
* With TTL there is a real chance of corrupted messages.
* With serial-over-USB we are not expecting communication errors
*/
// fatal("unexpected TunerStudio command in USB mode");
#endif /* EFI_TUNER_STUDIO_OVER_USB */
tunerStudioDebug("ignoring unexpected");
tsState.errorCounter++;
return FALSE;
}
return TRUE;
}
void handleQueryCommand(void) {
void handleQueryCommand(int needCrc) {
tsState.queryCommandCounter++;
tunerStudioDebug("got H (queryCommand)");
tunerStudioWriteData((const uint8_t *) TS_SIGNATURE, strlen(TS_SIGNATURE) + 1);
if (needCrc) {
// Query with CRC takes place while re-establishing connection
tunerStudioWriteCrcPacket(TS_RESPONSE_OK, (const uint8_t *) TS_SIGNATURE, strlen(TS_SIGNATURE) + 1);
} else {
// Query without CRC takes place on TunerStudio startup
tunerStudioWriteData((const uint8_t *) TS_SIGNATURE, strlen(TS_SIGNATURE) + 1);
}
}
/**
@ -111,7 +130,7 @@ void handleQueryCommand(void) {
void handleOutputChannelsCommand(void) {
tsState.outputChannelsCommandCounter++;
// this method is invoked too often to print any debug information
tunerStudioWriteData((const uint8_t *) &tsOutputChannels, sizeof(TunerStudioOutputChannels));
tunerStudioWriteCrcPacket(TS_RESPONSE_OK, (const uint8_t *) &tsOutputChannels, sizeof(TunerStudioOutputChannels));
}
void handleTestCommand(void) {
@ -119,6 +138,6 @@ 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)\r\n");
tunerStudioDebug("got T (Test)");
tunerStudioWriteData((const uint8_t *) "alive\r\n", 7);
}

View File

@ -12,27 +12,55 @@
#include <stdint.h>
// http://en.wikipedia.org/wiki/Endianness
#define SWAP_UINT16(x) ((x) << 8) | ((x) >> 8)
#define SWAP_UINT32(x) (((x) >> 24) & 0xff) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) | (((x) << 24) & 0xff000000)
// response codes
#define TS_RESPONSE_OK 0x00
#define TS_RESPONSE_BURN_OK 0x04
#define TS_RESPONSE_CRC_FAILURE 0x82
typedef struct {
int queryCommandCounter;
int outputChannelsCommandCounter;
int readPageCommandsCounter;
int burnCommandCounter;
int pageCommandCounter;
int writeValueCommandCounter;
int writeChunkCommandCounter;
int errorCounter;
// this field is in the end to simply aligning situation
short currentPageId;
} TunerStudioState;
int tunerStudioHandleCommand(short command);
int tunerStudioHandleCommand(char *data, int incomingPacketSize);
void handleTestCommand(void);
void handleQueryCommand(void);
void handleQueryCommand(int needCrc);
void handleOutputChannelsCommand(void);
char *getWorkingPageAddr(int pageIndex);
int getTunerStudioPageSize(int pageIndex);
void handleValueWriteCommand(void);
void handlePageReadCommand(void);
void handleBurnCommand(void);
void handleWriteValueCommand(uint16_t page, uint16_t offset, uint8_t value);
void handleWriteChunkCommand(short offset, short count, void *content);
void handlePageSelectCommand(uint16_t pageId);
void handlePageReadCommand(uint16_t pageId, uint16_t offset, uint16_t count);
void handleBurnCommand(uint16_t page);
void tunerStudioWriteData(const uint8_t * buffer, int size);
void tunerStudioDebug(char *msg);
#define TS_HELLO_COMMAND 'H'
#define TS_OUTPUT_COMMAND 'O'
#define TS_READ_COMMAND 'R'
#define TS_PAGE_COMMAND 'P'
#define TS_SINGLE_WRITE_COMMAND 'W'
#define TS_CHUNK_WRITE_COMMAND 'C'
#define TS_BURN_COMMAND 'B'
#endif /* TUNERSTUDIO_ALGO_H_ */

View File

@ -29,6 +29,7 @@ typedef struct {
float atmospherePressure; // size 4, offset 36
float manifold_air_pressure; // size 4, offset 40
int checkEngine; // size 4, offset 44
float tCharge;
} TunerStudioOutputChannels;
#endif /* TUNERSTUDIO_CONFIGURATION_H_ */

View File

@ -38,7 +38,6 @@
#include "memstreams.h"
#include "console_io.h"
#define OUTPUT_BUFFER 9000
/**
* This is the size of the MemoryStream used by chvprintf
*/
@ -50,18 +49,15 @@
/**
* This is the buffer into which all the data providers write
*/
#if defined __GNUC__
static char pendingBuffer[OUTPUT_BUFFER] __attribute__((section(".ccm")));
#else
static char pendingBuffer[OUTPUT_BUFFER];
#endif
static char pendingBuffer[DL_OUTPUT_BUFFER] CCM_OPTIONAL;
/**
* We copy all the pending data into this buffer once we are ready to push it out
*/
static char outputBuffer[OUTPUT_BUFFER];
static char outputBuffer[DL_OUTPUT_BUFFER];
static MemoryStream intermediateLoggingBuffer;
static uint8_t intermediateLoggingBufferData[INTERMEDIATE_LOGGING_BUFFER_SIZE]; //todo define max-printf-buffer
static uint8_t intermediateLoggingBufferData[INTERMEDIATE_LOGGING_BUFFER_SIZE] CCM_OPTIONAL; //todo define max-printf-buffer
static bool intermediateLoggingBufferInited = FALSE;
static int validateBuffer(Logging *logging, int extraLen, const char *text) {
@ -76,7 +72,7 @@ static int validateBuffer(Logging *logging, int extraLen, const char *text) {
strcat(logging->SMALL_BUFFER, logging->name);
strcat(logging->SMALL_BUFFER, "/");
strcat(logging->SMALL_BUFFER, text);
fatal(logging->SMALL_BUFFER);
firmwareError(logging->SMALL_BUFFER);
// unlockOutputBuffer();
// resetLogging(logging);
return TRUE;
@ -85,7 +81,7 @@ static int validateBuffer(Logging *logging, int extraLen, const char *text) {
}
void append(Logging *logging, const char *text) {
chDbgCheck(text!=NULL, "append NULL");
efiAssertVoid(text != NULL, "append NULL");
int extraLen = strlen(text);
int errcode = validateBuffer(logging, extraLen, text);
if (errcode)
@ -102,8 +98,9 @@ static void vappendPrintfI(Logging *logging, const char *fmt, va_list arg) {
}
void vappendPrintf(Logging *logging, const char *fmt, va_list arg) {
efiAssertVoid(getRemainingStack(chThdSelf()) > 16, "stack#5b");
if (!intermediateLoggingBufferInited) {
fatal("intermediateLoggingBufferInited not inited!");
firmwareError("intermediateLoggingBufferInited not inited!");
return;
}
int is_locked = isLocked();
@ -128,6 +125,7 @@ void vappendPrintf(Logging *logging, const char *fmt, va_list arg) {
}
void appendPrintf(Logging *logging, const char *fmt, ...) {
efiAssertVoid(getRemainingStack(chThdSelf()) > 16, "stack#4");
va_list ap;
va_start(ap, fmt);
vappendPrintf(logging, fmt, ap);
@ -154,7 +152,7 @@ char* getCaption(LoggingPoints loggingPoint) {
case LP_MAP_RAW:
return "MAP_R";
}
fatal("No such loggingPoint");
firmwareError("No such loggingPoint");
return NULL;
}
@ -176,7 +174,7 @@ static char* get2ndCaption(int loggingPoint) {
case LP_MAF:
return "MAF";
}
fatal("No such loggingPoint");
firmwareError("No such loggingPoint");
return NULL;
}
@ -204,7 +202,11 @@ void debugInt(Logging *logging, const char *caption, int value) {
}
void appendFloat(Logging *logging, float value, int precision) {
// todo: this implementation is less than perfect
/**
* todo: #1 this implementation is less than perfect
* todo: #2 The only way to avoid double promotion would probably be using *float instead of float
* See also http://stackoverflow.com/questions/5522051/printing-a-float-in-c-while-avoiding-variadic-parameter-promotion-to-double
*/
switch (precision) {
case 1:
appendPrintf(logging, "%..10f", value);
@ -324,7 +326,7 @@ void scheduleMsg(Logging *logging, const char *fmt, ...) {
}
// todo: remove this method, replace with 'scheduleMsg'
void scheduleIntValue(Logging *logging, char *msg, int value) {
void scheduleIntValue(Logging *logging, const char *msg, int value) {
resetLogging(logging);
append(logging, msg);
@ -339,10 +341,10 @@ void scheduleLogging(Logging *logging) {
// this could be done without locking
int newLength = strlen(logging->buffer);
bool_t alreadyLocked = lockOutputBuffer();
bool alreadyLocked = lockOutputBuffer();
// I hope this is fast enough to operate under sys lock
int curLength = strlen(pendingBuffer);
if (curLength + newLength >= OUTPUT_BUFFER) {
if (curLength + newLength >= DL_OUTPUT_BUFFER) {
/**
* if no one is consuming the data we have to drop it
* this happens in case of serial-over-USB, todo: find a better solution

View File

@ -81,7 +81,7 @@ void append(Logging *logging, const char *text);
void scheduleLogging(Logging *logging);
void scheduleIntValue(Logging *logging, char *msg, int value);
void scheduleIntValue(Logging *logging, const char *msg, int value);
/**
* this should only be invoked by the 'main' thread in order to keep the console safe

View File

@ -22,6 +22,8 @@
#include <string.h>
#include "rfiutil.h"
/*
not used, not sure if we still need it. I guess we will remove it in 2015
int mylog10(int param) {
if (param < 10)
return 0;
@ -39,49 +41,10 @@ int mylog10(int param) {
return 6;
if (param < 100000000)
return 7;
#warning This would be better without recursion
return mylog10(param / 10) + 1;
}
static char *ltoa_internal(char *p, long num, unsigned radix) {
int i;
char *q;
q = p + _MAX_FILLER;
do {
i = (int) (num % radix);
i += '0';
if (i > '9')
i += 'A' - '0' - 10;
*--q = i;
} while ((num /= radix) != 0);
i = (int) (p + _MAX_FILLER - q);
do
*p++ = *q++;
while (--i);
return p;
}
static char* itoa_signed(uint8_t *p, int num, unsigned radix) {
if (num < 0) {
*p++ = '-';
char *end = ltoa_internal(p, -num, radix);
*end = 0;
return end;
}
char *end = ltoa_internal(p, num, radix);
*end = 0;
return end;
}
/**
* Integer to string
*/
char* itoa10(uint8_t *p, int num) {
// todo: unit test
return itoa_signed(p, num, 10);
}
*/
char hexChar(int v) {
v = v & 0xF;
@ -103,11 +66,15 @@ int isLocked(void) {
return dbg_lock_cnt > 0;
}
void chVTSetAny(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
void chVTSetAny(virtual_timer_t *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
if (isIsrContext()) {
chSysLockFromIsr()
;
/**
* todo: this could be simplified once we migrate to ChibiOS 3.0
* See http://www.chibios.org/dokuwiki/doku.php?id=chibios:howtos:porting_from_2_to_3
*/
if (chVTIsArmedI(vtp))
chVTResetI(vtp);

View File

@ -13,23 +13,15 @@
#include "histogram.h"
#include "datalogging.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define _MAX_FILLER 11
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
char* itoa10(uint8_t *p, int num);
char hexC(int v);
int isIsrContext(void);
int isLocked(void);
void chVTSetAny(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par);
void chVTSetAny(virtual_timer_t *vtp, systime_t time, vtfunc_t vtfunc, void *par);
void printHistogram(Logging *logging, histogram_s *histogram);
#ifdef __cplusplus

View File

@ -15,18 +15,7 @@
static Logging logger;
static float _switchTimes[2];
// todo: extract helper for simple PWM?
static int pinStates[2];
static single_wave_s wave(pinStates);
static single_wave_s sr[1] = { wave };
static PwmConfig pwmTest[5] = { PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr),
PwmConfig(_switchTimes, sr)};
static SimplePwm pwmTest[5];
extern board_configuration_s *boardConfiguration;
@ -34,20 +23,15 @@ static void startPwmTest(int freq) {
scheduleMsg(&logger, "running pwm test @%d", freq);
// PD13, GPIO_NONE because pin is initialized elsewhere already
startSimplePwm(&pwmTest[0], "tester", GPIO_NONE,
LED_CRANKING, 0.5, 10, FALSE);
// currently this is PB9 by default
startSimplePwm(&pwmTest[1], "tester", boardConfiguration->injectionPins[0],
INJECTOR_1_OUTPUT, 0.5, freq / 1.3333333333, FALSE);
startSimplePwm(&pwmTest[0], "tester", LED_WARNING, 10, 0.5);
// currently this is PB9 by default - see boardConfiguration->injectionPins
startSimplePwm(&pwmTest[1], "tester", INJECTOR_1_OUTPUT, freq / 1.3333333333, 0.5);
// currently this is PB8 by default
startSimplePwm(&pwmTest[2], "tester", GPIO_NONE,
INJECTOR_2_OUTPUT, 0.5, freq / 1000, FALSE);
startSimplePwm(&pwmTest[2], "tester", INJECTOR_2_OUTPUT, freq / 1000, 0.5);
// currently this is PE3 by default
startSimplePwm(&pwmTest[3], "tester", GPIO_NONE,
INJECTOR_3_OUTPUT, 0.5, freq, FALSE);
startSimplePwm(&pwmTest[3], "tester", INJECTOR_3_OUTPUT, freq, 0.5);
// currently this is PE5 by default
startSimplePwm(&pwmTest[4], "tester", GPIO_NONE,
INJECTOR_4_OUTPUT, 0.5, freq / 33.33333333333, FALSE);
startSimplePwm(&pwmTest[4], "tester", INJECTOR_4_OUTPUT, freq / 33.33333333333, 0.5);
}
void initPwmTester(void) {

View File

@ -18,25 +18,30 @@ extern engine_configuration_s *engineConfiguration;
static AccelEnrichmemnt instance;
void AccelEnrichmemnt::updateDiffEnrichment(engine_configuration_s *engineConfiguration, float engineLoad) {
for (int i = 1; i < 4; i++) {
for (int i = 3; i == 1; i--)
engineLoadD[i] = engineLoadD[i - 1];
}
engineLoadD[0] = engineLoad;
float Dcurr = engineLoadD[0] - engineLoadD[1];
float Dold = engineLoadD[2] - engineLoadD[3];
diffEnrichment = ((3 * Dcurr + Dold) / 4) * (engineConfiguration->diffLoadEnrichmentCoef);
diffEnrichment = ((3 * (engineLoadD[0] - engineLoadD[1]) + (engineLoadD[2] - engineLoadD[3])) / 4)
* (engineConfiguration->diffLoadEnrichmentCoef);
}
float AccelEnrichmemnt::getDiffEnrichment() {
return diffEnrichment;
}
AccelEnrichmemnt::AccelEnrichmemnt() {
for (int i = 0; i < 4; i++)
engineLoadD[i] = 0;
diffEnrichment = 0;
}
float getAccelEnrichment(void) {
return instance.getDiffEnrichment();
}
#if EFI_PROD_CODE
static WORKING_AREA(aeThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(aeThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t DiffEnrichmentThread(int param) {
chRegSetThreadName("Diff Enrichment");
@ -54,3 +59,4 @@ void initDiffEnrichment(void) {
}
#endif

View File

@ -14,14 +14,18 @@
class AccelEnrichmemnt {
public:
void updateDiffEnrichment(engine_configuration_s *engineConfiguration, float engineLoad);
AccelEnrichmemnt();
void updateDiffEnrichment(engine_configuration_s *engineConfiguration,
float engineLoad);
float getDiffEnrichment(void);
private:
float engineLoadD[5];
float engineLoadD[4];
float diffEnrichment;
};
void initDiffEnrichment(void);
float getAccelEnrichment(void);
#endif /* ACC_ENRICHMENT_H_ */

View File

@ -1,58 +1,54 @@
/**
* @file advance_map.c
*
* @date Mar 27, 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 <http://www.gnu.org/licenses/>.
*/
#include "advance_map.h"
#include "interpolation.h"
// that's for 'max' function
#include "idle_controller.h"
#include "engine_configuration.h"
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
//extern engine_configuration2_s *engineConfiguration2;
static float *timing_ptrs[AD_LOAD_COUNT];
static int initialized = FALSE;
float getBaseAdvance(int rpm, float engineLoad) {
chDbgAssert(initialized, "fuel map initialized", NULL);
efiAssert(!cisnan(engineLoad), "invalid el");
efiAssert(!cisnan(engineLoad), "invalid rpm");
return interpolate3d(engineLoad, engineConfiguration->ignitionLoadBins, AD_LOAD_COUNT, rpm,
engineConfiguration->ignitionRpmBins,
AD_RPM_COUNT, timing_ptrs);
}
float getAdvance(int rpm, float engineLoad) {
float angle;
if (isCrankingR(rpm)) {
angle = engineConfiguration->crankingTimingAngle;
} else {
angle = getBaseAdvance(rpm, engineLoad);
}
return fixAngle(angle + engineConfiguration->ignitionOffset);
}
void prepareTimingMap(void) {
for (int k = 0; k < AD_LOAD_COUNT; k++)
timing_ptrs[k] = engineConfiguration->ignitionTable[k];
initialized = TRUE;
}
/**
* @file advance_map.c
*
* @date Mar 27, 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 <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "advance_map.h"
#include "interpolation.h"
// that's for 'max' function
#include "idle_controller.h"
#include "engine_configuration.h"
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
//extern engine_configuration2_s *engineConfiguration2;
static Map3D1616 advanceMap;
float getBaseAdvance(int rpm, float engineLoad) {
efiAssert(!cisnan(engineLoad), "invalid el", NAN);
efiAssert(!cisnan(engineLoad), "invalid rpm", NAN);
return advanceMap.getValue(engineLoad, engineConfiguration->ignitionLoadBins, rpm,
engineConfiguration->ignitionRpmBins);
}
float getAdvance(int rpm, float engineLoad) {
float angle;
if (isCrankingR(rpm)) {
angle = engineConfiguration->crankingTimingAngle;
} else {
angle = getBaseAdvance(rpm, engineLoad);
}
return fixAngle(angle + engineConfiguration->ignitionOffset);
}
void prepareTimingMap(void) {
advanceMap.init(engineConfiguration->ignitionTable);
}

View File

@ -1,5 +1,5 @@
/*
* advance.h
* @file advance_map.h
*
* @date Mar 27, 2013
* @author Andrey Belomutskiy, (c) 2012-2014

View File

@ -1,16 +1,17 @@
CONTROLLERS_ALGO_SRC = $(PROJECT_DIR)/controllers/algo/map_adjuster.c \
$(PROJECT_DIR)/controllers/algo/advance_map.c \
$(PROJECT_DIR)/controllers/algo/signal_executor.c \
$(PROJECT_DIR)/controllers/algo/malfunction_central.c \
$(PROJECT_DIR)/controllers/algo/event_registry.c \
$(PROJECT_DIR)/controllers/algo/idle_controller.c \
$(PROJECT_DIR)/controllers/algo/wave_chart.c \
$(PROJECT_DIR)/controllers/algo/nmea.c
CONTROLLERS_ALGO_SRC_CPP = $(PROJECT_DIR)/controllers/algo/OutputSignalArray.cpp \
$(PROJECT_DIR)/controllers/algo/advance_map.cpp \
$(PROJECT_DIR)/controllers/algo/fuel_math.cpp \
$(PROJECT_DIR)/controllers/algo/accel_enrichment.cpp \
$(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \
$(PROJECT_DIR)/controllers/algo/engine.cpp \
$(PROJECT_DIR)/controllers/algo/event_registry.cpp \
$(PROJECT_DIR)/controllers/algo/algo.cpp

View File

@ -13,8 +13,19 @@
#define EC2_H_
#include "engine_configuration.h"
#include "event_registry.h"
#include "trigger_structure.h"
/**
* @brief Here we store information about which injector or spark should be fired when.
*/
typedef struct {
ActuatorEventList crankingInjectionEvents;
ActuatorEventList injectionEvents;
IgnitionEventList ignitionEvents[2];
} EventHandlerConfiguration;
#ifdef __cplusplus
extern "C"
{
@ -42,15 +53,26 @@ public:
EventHandlerConfiguration engineEventConfiguration;
int isInjectionEnabledFlag;
/**
* This coefficient translates ADC value directly into voltage adjusted according to
* voltage divider configuration.
*/
float adcToVoltageInputDividerCoefficient;
};
typedef struct {
engine_configuration_s *engineConfiguration;
engine_configuration2_s *engineConfiguration2;
} configuration_s;
void prepareOutputSignals(engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2);
void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2, float dwellMs, ActuatorEventList *list);
void initializeIgnitionActions(float advance, float dwellAngle, engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2, IgnitionEventList *list);
void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *engineConfiguration2, ActuatorEventList *list, injection_mode_e mode);
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, ActuatorEventList *list, OutputSignal *actuator, float angleOffset);
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, ActuatorEvent *e, OutputSignal *actuator, float angleOffset);
void resetConfigurationExt(Logging * logger, engine_type_e engineType,
engine_configuration_s *engineConfiguration,

View File

@ -0,0 +1,13 @@
/**
* @file engine.cpp
*
*
* This might be a http://en.wikipedia.org/wiki/God_object but that's best way I can
* express myself in C/C++. I am open for suggestions :)
*
* @date May 21, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/

View File

@ -0,0 +1,21 @@
/**
* @file engine.h
*
* @date May 21, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef ENGINE_H_
#define ENGINE_H_
#include "main.h"
#include "engine_configuration.h"
class RpmCalculator;
class Engine {
public:
RpmCalculator *rpmCalculator;
engine_configuration_s *engineConfiguration;
};
#endif /* ENGINE_H_ */

View File

@ -1,5 +1,5 @@
/**
* @file engine_controller.c
* @file engine_configuration.cpp
* @brief Utility method related to the engine configuration data structure.
*
* @date Nov 22, 2013
@ -46,6 +46,7 @@
#include "MiniCooperR50.h"
#include "ford_escort_gt.h"
#include "citroenBerlingoTU3JP.h"
#include "rover_v8.h"
static volatile int globalConfigurationVersion = 0;
@ -77,6 +78,14 @@ void initBpsxD1Sensor(afr_sensor_s *sensor) {
sensor->value2 = 19;
}
void setWholeVEMap(engine_configuration_s *engineConfiguration, float value) {
// for (int l = 0; l < VE_LOAD_COUNT; l++) {
// for (int r = 0; r < VE_RPM_COUNT; r++) {
// engineConfiguration->veTable[l][r] = value;
// }
// }
}
void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value) {
for (int l = 0; l < FUEL_LOAD_COUNT; l++) {
for (int r = 0; r < FUEL_RPM_COUNT; r++) {
@ -85,6 +94,13 @@ void setWholeFuelMap(engine_configuration_s *engineConfiguration, float value) {
}
}
void setTriggerSynchronizationGap(engine_configuration_s *engineConfiguration, float synchGap) {
engineConfiguration->triggerConfig.isSynchronizationNeeded = TRUE;
engineConfiguration->triggerConfig.syncRatioFrom = synchGap * 0.75;
engineConfiguration->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
@ -192,20 +208,20 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_
engineConfiguration->canReadEnabled = TRUE;
engineConfiguration->canWriteEnabled = FALSE;
/**
* 0.5 means primary position sensor is on a camshaft
*/
engineConfiguration->rpmMultiplier = 0.5;
setOperationMode(engineConfiguration, FOUR_STROKE_CAM_SENSOR);
engineConfiguration->cylindersCount = 4;
engineConfiguration->displacement = 2;
/**
* By the way http://users.erols.com/srweiss/tableifc.htm has a LOT of data
*/
engineConfiguration->injectorFlow = 200;
engineConfiguration->displayMode = DM_HD44780;
engineConfiguration->logFormat = LF_NATIVE;
engineConfiguration->triggerConfig.triggerType = TT_TOOTHED_WHEEL;
engineConfiguration->triggerConfig.syncRatioFrom = 1.5;
engineConfiguration->triggerConfig.syncRatioTo = 3;
engineConfiguration->triggerConfig.isSynchronizationNeeded = TRUE;
setTriggerSynchronizationGap(engineConfiguration, 2);
engineConfiguration->triggerConfig.useRiseEdge = TRUE;
engineConfiguration->HD44780width = 16;
@ -291,6 +307,13 @@ void setDefaultConfiguration(engine_configuration_s *engineConfiguration, board_
boardConfiguration->primaryLogicAnalyzerPin = GPIOA_8;
boardConfiguration->secondaryLogicAnalyzerPin = GPIOE_7;
boardConfiguration->idleThreadPeriod = 100;
boardConfiguration->consoleLoopPeriod = 200;
boardConfiguration->lcdThreadPeriod = 300;
boardConfiguration->tunerStudioThreadPeriod = 300;
boardConfiguration->generalPeriodicThreadPeriod = 200;
boardConfiguration->tunerStudioSerialSpeed = 38400;
}
void setDefaultNonPersistentConfiguration(engine_configuration2_s *engineConfiguration2) {
@ -363,6 +386,10 @@ void resetConfigurationExt(Logging * logger, engine_type_e engineType, engine_co
case CITROEN_TU3JP:
setCitroenBerlingoTU3JPConfiguration(engineConfiguration, boardConfiguration);
break;
case ROVER_V8:
setRoverv8(engineConfiguration, boardConfiguration);
break;
default:
firmwareError("Unexpected engine type: %d", engineType);
@ -398,6 +425,22 @@ void applyNonPersistentConfiguration(Logging * logger, engine_configuration_s *e
prepareOutputSignals(engineConfiguration, engineConfiguration2);
// todo: looks like this is here only for unit tests. todo: remove
initializeIgnitionActions(0, engineConfiguration, engineConfiguration2, 0, &engineConfiguration2->engineEventConfiguration.ignitionEvents[0]);
initializeIgnitionActions(0, 0, engineConfiguration, engineConfiguration2,
&engineConfiguration2->engineEventConfiguration.ignitionEvents[0]);
}
void setOperationMode(engine_configuration_s *engineConfiguration, operation_mode_e mode) {
if (mode == FOUR_STROKE_CAM_SENSOR) {
engineConfiguration->rpmMultiplier = 0.5;
} else if (mode == FOUR_STROKE_CRANK_SENSOR) {
engineConfiguration->rpmMultiplier = 1;
}
}
operation_mode_e getOperationMode( engine_configuration_s const *engineConfiguration) {
if(engineConfiguration->rpmMultiplier == 1)
return FOUR_STROKE_CRANK_SENSOR;
return FOUR_STROKE_CAM_SENSOR;
}

View File

@ -13,7 +13,6 @@
#include "crc.h"
#include "sensor_types.h"
#include "can_header.h"
#include "event_registry.h"
#include "rusefi_enums.h"
typedef struct {
@ -29,17 +28,12 @@ typedef struct {
short int crankingRpm;
} cranking_parameters_s;
/**
* @brief Here we store information about which injector or spark should be fired when.
*/
typedef struct {
ActuatorEventList crankingInjectionEvents;
ActuatorEventList injectionEvents;
ActuatorEventList ignitionEvents[2];
} EventHandlerConfiguration;
#define FUEL_RPM_COUNT 16
#define FUEL_LOAD_COUNT 16
#define VE_RPM_COUNT 16
#define VE_LOAD_COUNT 16
#define AFR_RPM_COUNT 16
#define AFR_LOAD_COUNT 16
#define CLT_CURVE_SIZE 16
#define IAT_CURVE_SIZE 16
@ -115,6 +109,14 @@ typedef struct {
*/
typedef struct {
float injectorLag; // size 4, offset 0
/**
* cc/min, cubic centimeter per minute
*
* By the way, g/s = 0.125997881 * (lb/hr)
* g/s = 0.125997881 * (cc/min)/10.5
* g/s = 0.0119997981 * cc/min
*
*/
float injectorFlow; // size 4, offset 4
float battInjectorLagCorrBins[VBAT_INJECTOR_CURVE_SIZE]; // size 32, offset 8
float battInjectorLagCorr[VBAT_INJECTOR_CURVE_SIZE]; // size 32, offset 40
@ -145,9 +147,8 @@ typedef struct {
float sparkDwellBins[DWELL_COUNT]; // offset 580
float sparkDwell[DWELL_COUNT];
float ignitionTable[IGN_LOAD_COUNT][IGN_RPM_COUNT];
float ignitionLoadBins[IGN_LOAD_COUNT]; // offset 3450
float ignitionRpmBins[IGN_RPM_COUNT]; // offset 3542
float ignitionLoadBins[IGN_LOAD_COUNT];
float ignitionRpmBins[IGN_RPM_COUNT];
/**
* this value could be used to offset the whole ignition timing table by a constant
@ -170,12 +171,16 @@ typedef struct {
// WARNING: by default, our small enums are ONE BYTE. but if the are surrounded by non-enums - alignments do the trick
engine_type_e engineType;
float fuelTable[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]; // size 1024, offset 1816
float fuelLoadBins[FUEL_LOAD_COUNT]; // offset 2840
float fuelLoadBins[FUEL_LOAD_COUNT]; //
// RPM is float and not integer in order to use unified methods for interpolation
float fuelRpmBins[FUEL_RPM_COUNT]; // offset 3542
float fuelRpmBins[FUEL_RPM_COUNT]; //
int unused[3];
/**
* Engine displacement, in liters
* see also cylindersCount
*/
float displacement;
int unused[2];
injection_mode_e crankingInjectionMode;
injection_mode_e injectionMode;
@ -270,8 +275,24 @@ typedef struct {
float diffLoadEnrichmentCoef;
air_pressure_sensor_config_s baroSensor;
float veLoadBins[VE_LOAD_COUNT];
float veRpmBins[VE_RPM_COUNT];
float afrLoadBins[AFR_LOAD_COUNT];
float afrRpmBins[AFR_RPM_COUNT];
// the large tables are always in the end - that's related to TunerStudio paging implementation
float fuelTable[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]; // size 1024
float ignitionTable[IGN_LOAD_COUNT][IGN_RPM_COUNT]; // size 1024
float veTable[VE_LOAD_COUNT][VE_RPM_COUNT]; // size 1024
float afrTable[AFR_LOAD_COUNT][AFR_RPM_COUNT]; // size 1024
} engine_configuration_s;
void setOperationMode(engine_configuration_s *engineConfiguration, operation_mode_e mode);
operation_mode_e getOperationMode(engine_configuration_s const *engineConfiguration);
#define HW_MAX_ADC_INDEX 16
typedef struct {
@ -326,6 +347,14 @@ typedef struct {
brain_pin_e primaryLogicAnalyzerPin;
brain_pin_e secondaryLogicAnalyzerPin;
int idleThreadPeriod;
int consoleLoopPeriod;
int lcdThreadPeriod;
int tunerStudioThreadPeriod;
int generalPeriodicThreadPeriod;
int tunerStudioSerialSpeed;
} board_configuration_s;
typedef struct {
@ -350,6 +379,7 @@ 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(engine_configuration_s *engineConfiguration, float synchGap);
void incrementGlobalConfigurationVersion(void);
int getGlobalConfigurationVersion(void);

View File

@ -28,11 +28,17 @@ int warning(obd_code_e code, const char *fmt, ...);
* todo: better method name?
*/
void firmwareError(const char *fmt, ...);
bool_t hasFirmwareError(void);
bool hasFirmwareError(void);
bool_t hasFatalError(void);
void fatal3(char *msg, char *file, int line);
#define fatal(x) (fatal3(x, __FILE__, __LINE__));
/**
* declared as a macro so that this code does not use stack
* so that it would not crash the error handler in case of stack issues
*/
#if CH_DBG_SYSTEM_STATE_CHECK
#define hasFatalError() (dbg_panic_msg != NULL)
#else
#define hasFatalError() (FALSE)
#endif
void chDbgPanic3(const char *msg, const char * file, int line);
@ -45,7 +51,10 @@ int getRusEfiVersion(void);
* @deprecated Global panic is inconvenient because it's hard to deliver the error message while whole instance
* is stopped. Please use firmwareWarning() instead
*/
#define efiAssert(x, y) chDbgAssert(x, y, NULL)
#define efiAssert(condition, message, result) { if (!(condition)) { firmwareError(message); return result; } }
#define efiAssertVoid(condition, message) { if (!(condition)) { firmwareError(message); return; } }
#ifdef __cplusplus
}

View File

@ -1,61 +0,0 @@
/**
* @file event_registry.c
* @brief This data structure knows when to do what
*
* @date Nov 27, 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 <http://www.gnu.org/licenses/>.
*/
#include "event_registry.h"
#include "main.h"
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
//extern engine_configuration2_s *engineConfiguration2;
void resetEventList(ActuatorEventList *list) {
list->size = 0;
}
static void copyActuatorEvent(ActuatorEvent *source, ActuatorEvent*target) {
target->eventIndex = source->eventIndex;
target->actuator = source->actuator;
target->angleOffset = source->angleOffset;
}
void registerActuatorEvent(ActuatorEventList *list, int eventIndex, OutputSignal *actuator, float angleOffset) {
if (list->size == MAX_EVENT_COUNT) {
fatal("registerActuatorEvent() too many events");
return;
}
ActuatorEvent *e = &list->events[list->size++];
e->eventIndex = eventIndex;
e->actuator = actuator;
e->angleOffset = angleOffset;
}
void findEvents(int eventIndex, ActuatorEventList *source, ActuatorEventList *target) {
resetEventList(target);
// todo: implement something faster
for (int i = 0; i < source->size; i++) {
ActuatorEvent *s = &source->events[i];
if (s->eventIndex != eventIndex)
continue;
// todo: migrate to pointers instead of copying an object?
copyActuatorEvent(s, &target->events[target->size++]);
}
}

View File

@ -0,0 +1,34 @@
/**
* @file event_registry.cpp
* @brief This data structure knows when to do what
*
* @date Nov 27, 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 <http://www.gnu.org/licenses/>.
*/
#include "event_registry.h"
#include "main.h"
#include "engine_math.h"
void registerActuatorEvent(ActuatorEventList *list, int eventIndex, OutputSignal *actuator, float angleOffset) {
ActuatorEvent *e = list->getNextActuatorEvent();
if (e == NULL)
return; // error already reported
e->position.eventIndex = eventIndex;
e->actuator = actuator;
e->position.angleOffset = angleOffset;
}

View File

@ -13,24 +13,60 @@
#define MAX_EVENT_COUNT 40
/**
* This structure defines an angle position within the trigger
*/
typedef struct {
/**
* That's trigger event index
*/
int eventIndex;
OutputSignal *actuator;
float eventAngle;
/**
* Angle offset from the trigger event
*/
float angleOffset;
} event_trigger_position_s;
typedef struct {
event_trigger_position_s position;
OutputSignal *actuator;
scheduling_s signalTimer;
} ActuatorEvent;
typedef struct {
typedef struct IgnitionEvent_struct IgnitionEvent;
struct IgnitionEvent_struct {
ActuatorEvent actuator;
float advance;
event_trigger_position_s sparkPosition;
IgnitionEvent *next;
char *name;
};
template <class Type, int Dimention>
class ArrayList {
public:
int size;
ActuatorEvent events[MAX_EVENT_COUNT];
} ActuatorEventList;
Type events[Dimention];
void resetEventList(void);
Type *getNextActuatorEvent(void);
};
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
template <class Type, int Dimention>
void ArrayList< Type, Dimention>::resetEventList(void) {
size = 0;
}
template <class Type, int Dimention>
Type * ArrayList< Type, Dimention>::getNextActuatorEvent(void) {
efiAssert(size < Dimention, "registerActuatorEvent() too many events", NULL);
return &events[size++];
}
void resetEventList(ActuatorEventList *list);
typedef ArrayList<ActuatorEvent, MAX_EVENT_COUNT> ActuatorEventList;
typedef ArrayList<IgnitionEvent, MAX_EVENT_COUNT> IgnitionEventList;
/**
* this is an intermediate implementation of flexible event handling.
@ -42,11 +78,4 @@ void resetEventList(ActuatorEventList *list);
*/
void registerActuatorEvent(ActuatorEventList *list, int eventIndex, OutputSignal *actuator, float angleOffset);
void findEvents(int eventIndex, ActuatorEventList *source, ActuatorEventList *target);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* EVENT_REGISTRY_H_ */

View File

@ -40,19 +40,17 @@
#include "accel_enrichment.h"
#endif /* EFI_ACCEL_ENRICHMENT */
static float *fuel_ptrs[FUEL_LOAD_COUNT];
static int initialized = FALSE;
extern engine_configuration_s *engineConfiguration;
static Map3D1616 fuelMap;
/**
* @brief Initialize fuel map data structure
* @note this method has nothing to do with fuel map VALUES - it's job
* is to prepare the fuel map data structure for 3d interpolation
*/
void prepareFuelMap(void) {
for (int k = 0; k < FUEL_LOAD_COUNT; k++)
fuel_ptrs[k] = engineConfiguration->fuelTable[k];
initialized = TRUE;
fuelMap.init(engineConfiguration->fuelTable);
}
/**
@ -86,11 +84,9 @@ float getInjectorLag(float vBatt) {
}
float getBaseFuel(int rpm, float engineLoad) {
chDbgCheck(initialized, "fuel map initialized");
efiAssert(!cisnan(engineLoad), "invalid el");
efiAssert(!cisnan(engineLoad), "invalid rpm");
return interpolate3d(engineLoad, engineConfiguration->fuelLoadBins, FUEL_LOAD_COUNT, rpm,
engineConfiguration->fuelRpmBins, FUEL_RPM_COUNT, fuel_ptrs);
efiAssert(!cisnan(engineLoad), "invalid el", NAN);
return fuelMap.getValue(engineLoad, engineConfiguration->fuelLoadBins, rpm,
engineConfiguration->fuelRpmBins);
}
float getCrankingFuel(void) {
@ -157,7 +153,7 @@ inline static int getElectricalValue1(pin_output_mode_e mode) {
// todo: this method is here for unit test visibility. todo: move to a bette place!
int getElectricalValue(int logicalValue, pin_output_mode_e mode) {
chDbgCheck(mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e");
efiAssert(mode <= OM_OPENDRAIN_INVERTED, "invalid pin_output_mode_e", -1);
return logicalValue ? getElectricalValue1(mode) : getElectricalValue0(mode);
}

View File

@ -13,7 +13,7 @@
#define GPIO_NULL NULL
typedef enum {
LED_CRANKING, // Orange on-board LED
LED_WARNING, // Orange on-board LED
LED_RUNNING, // Green on-board LED
LED_ERROR, // Red on-board LED
LED_COMMUNICATION_1, // Blue on-board LED

View File

@ -15,14 +15,31 @@
#define MAX_INJECTOR_COUNT 12
#define MAX_IGNITER_COUNT 4
#ifdef __cplusplus
#include "engine_configuration.h"
#include "ec2.h"
#include "event_registry.h"
class MainTriggerCallback {
public:
// MainTriggerCallback();
void init(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
engine_configuration_s *engineConfiguration;
engine_configuration2_s *engineConfiguration2;
};
void initMainEventListener(engine_configuration_s *engineConfiguration, engine_configuration2_s *engineConfiguration2);
void onTriggerEvent(trigger_event_e ckpSignalType, int eventIndex, MainTriggerCallback *mainTriggerCallback);
#endif
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include "event_registry.h"
void initMainEventListener(void);
void showMainHistogram(void);
void onEveryMillisecondTimerSignal(void);
int isIgnitionTimingError(void);

View File

@ -55,6 +55,6 @@ void getErrorCodes(error_codes_set_s * copy) {
copy->error_codes[i] = error_codes_set.error_codes[i];
}
bool_t hasErrorCodes(void) {
bool hasErrorCodes(void) {
return error_codes_set.count > 0;
}

View File

@ -48,11 +48,10 @@ void setError(int flag, obd_code_e errorCode);
*/
void getErrorCodes(error_codes_set_s * buffer);
bool_t hasErrorCodes(void);
bool hasErrorCodes(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* MALFUNCTION_CENTRAL_H_ */

View File

@ -97,7 +97,7 @@ typedef enum {
SHAFT_PRIMARY_DOWN = 1,
SHAFT_SECONDARY_UP = 2,
SHAFT_SECONDARY_DOWN = 3,
} ShaftEvents;
} trigger_event_e;
/**
* This enum is used to select your desired Engine Load calculation algorithm
@ -179,6 +179,14 @@ typedef enum {
Internal_ForceMyEnumIntSize_firing_order = ENUM_SIZE_HACK,
} firing_order_e;
// todo: better enum name
typedef enum {
FOUR_STROKE_CRANK_SENSOR = 0,
FOUR_STROKE_CAM_SENSOR = 1,
Internal_ForceMyEnumIntSize_operation_mode_e = ENUM_SIZE_HACK,
} operation_mode_e;
/**
* @brief Ignition Mode
*/

View File

@ -56,12 +56,10 @@ void initOutputSignal(OutputSignal *signal, io_pin_e ioPin) {
}
void initOutputSignalBase(OutputSignal *signal) {
signal->status = IDLE;
// signal->last_scheduling_time = 0;
signal->initialized = TRUE;
}
static void turnHigh(OutputSignal *signal) {
void turnPinHigh(OutputSignal *signal) {
#if EFI_DEFAILED_LOGGING
// signal->hi_time = hTimeNow();
#endif /* EFI_DEFAILED_LOGGING */
@ -85,7 +83,7 @@ static void turnHigh(OutputSignal *signal) {
#endif /* EFI_WAVE_ANALYZER */
}
static void turnLow(OutputSignal *signal) {
void turnPinLow(OutputSignal *signal) {
// turn off the output
// todo: this XOR should go inside the setOutputPinValue method
setOutputPinValue(signal->io_pin, FALSE);
@ -126,8 +124,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) &turnHigh, (void *) signal);
scheduleTask(sDown, (int)MS2US(delayMs + durationMs), (schfunc_t) &turnLow, (void*) signal);
scheduleTask(sUp, (int)MS2US(delayMs), (schfunc_t) &turnPinHigh, (void *) signal);
scheduleTask(sDown, (int)MS2US(delayMs + durationMs), (schfunc_t) &turnPinLow, (void*) signal);
// signal->last_scheduling_time = now;
}
@ -137,7 +135,7 @@ void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs) {
* it's better to check for the exact 'TRUE' value since otherwise
* we would accept any memory garbage
*/
chDbgCheck(signal->initialized == TRUE, "Signal not initialized");
efiAssertVoid(signal->initialized == TRUE, "Signal not initialized");
// signal->offset = offset;
// signal->duration = duration;
}

View File

@ -23,10 +23,6 @@
#include "signal_executor_sleep.h"
#endif /* EFI_SIGNAL_EXECUTOR_SLEEP */
typedef enum {
IDLE = 0, ACTIVE
} executor_status_t;
/**
* @brief Asynchronous output signal data structure
*/
@ -40,19 +36,14 @@ struct OutputSignal_struct {
int initialized;
/**
* We are alternating instances so that events which extend into next revolution are not overriden while
* We are alternating instances so that events which extend into next revolution are not reused while
* scheduling next revolution events
*/
scheduling_s signalTimerUp[2];
scheduling_s signalTimerDown[2];
executor_status_t status;
#if EFI_SIGNAL_EXECUTOR_HW_TIMER
// todo
#endif
// OutputSignal *next;
scheduling_s triggerEvent;
float angleOffsetParam;
};
#ifdef __cplusplus
@ -65,6 +56,9 @@ void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs);
void initOutputSignalBase(OutputSignal *signal);
void scheduleOutputBase(OutputSignal *signal, float delayMs, float durationMs);
void turnPinHigh(OutputSignal *signal);
void turnPinLow(OutputSignal *signal);
void initSignalExecutor(void);
void initSignalExecutorImpl(void);
void scheduleByAngle(scheduling_s *timer, float angle, schfunc_t callback, void *param);

View File

@ -40,9 +40,11 @@
*/
#if EFI_PROD_CODE
static volatile int chartSize = 100;
#define WAVE_LOGGING_SIZE 5000
#else
// need more events for automated test
static volatile int chartSize = 200;
static volatile int chartSize = 400;
#define WAVE_LOGGING_SIZE 35000
#endif
static int isChartActive = TRUE;
@ -65,11 +67,7 @@ void resetWaveChart(WaveChart *chart) {
appendPrintf(&chart->logging, "wave_chart%s", DELIMETER);
}
#if defined __GNUC__
static char WAVE_LOGGING_BUFFER[5000] __attribute__((section(".ccm")));
#else
static char WAVE_LOGGING_BUFFER[5000];
#endif
static char WAVE_LOGGING_BUFFER[WAVE_LOGGING_SIZE] CCM_OPTIONAL;
static void printStatus(void) {
scheduleIntValue(&logger, "chart", isChartActive);
@ -113,13 +111,13 @@ void publishChart(WaveChart *chart) {
* @brief Register a change in sniffed signal
*/
void addWaveChartEvent3(WaveChart *chart, const char *name, const char * msg, const char * msg2) {
chDbgCheck(chart->isInitialized, "chart not initialized");
efiAssertVoid(chart->isInitialized, "chart not initialized");
#if DEBUG_WAVE
scheduleSimpleMsg(&debugLogging, "current", chart->counter);
#endif
if (isWaveChartFull(chart))
return;
bool_t alreadyLocked = lockOutputBuffer(); // we have multiple threads writing to the same output buffer
bool alreadyLocked = lockOutputBuffer(); // we have multiple threads writing to the same output buffer
appendPrintf(&chart->logging, "%s%s%s%s", name, CHART_DELIMETER, msg, CHART_DELIMETER);
int time100 = getTimeNowUs() / 10;
appendPrintf(&chart->logging, "%d%s%s", time100, msg2, CHART_DELIMETER);

View File

@ -24,7 +24,7 @@ extern board_configuration_s *boardConfiguration;
static PwmConfig alternatorControl;
static WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t AltCtrlThread(int param) {
chRegSetThreadName("AlternatorController");

View File

@ -2,12 +2,12 @@
CONTROLLERSSRC = \
controllers/ignition_central.c \
$(PROJECT_DIR)/controllers/malfunction_indicator.c \
$(PROJECT_DIR)/controllers/error_handling.c \
controllers/map_averaging.c \
controllers/map_multiplier_thread.c
$(PROJECT_DIR)/controllers/error_handling.c
CONTROLLERS_SRC_CPP = $(PROJECT_DIR)/controllers/settings.cpp \
controllers/electronic_throttle.cpp \
controllers/map_averaging.cpp \
controllers/map_multiplier_thread.cpp \
controllers/flash_main.cpp \
controllers/injector_central.cpp \
controllers/idle_thread.cpp \

View File

@ -7,6 +7,7 @@
#include "main.h"
#include "EfiWave.h"
#include "trigger_structure.h"
single_wave_s::single_wave_s() {
init(NULL);
@ -20,16 +21,40 @@ void single_wave_s::init(int *pinStates) {
this->pinStates = pinStates;
}
multi_wave_s::multi_wave_s() {
}
multi_wave_s::multi_wave_s(float *switchTimes, single_wave_s *waves) {
init(switchTimes, waves);
}
void multi_wave_s::init(float *switchTimes, single_wave_s *waves) {
this->switchTimes = switchTimes;
this->waves = waves;
}
void multi_wave_s::reset(void) {
phaseCount = 0;
waveCount = 0;
}
float multi_wave_s::getAngle(int index, engine_configuration_s const *engineConfiguration, trigger_shape_s * s) const {
if (getOperationMode(engineConfiguration) == FOUR_STROKE_CAM_SENSOR)
return getSwitchTime(index) * 720.0;
/**
* FOUR_STROKE_CRANK_SENSOR magic:
* We have two crank shaft revolutions for each engine cycle
* See also trigger_central.cpp
* See also getEngineCycleEventCount()
*/
int triggerEventCounter = s->getSize();
if (index < triggerEventCounter) {
return getSwitchTime(index) * 360.0;
} else {
return 360 + getSwitchTime(index - triggerEventCounter) * 360.0;
}
}
float multi_wave_s::getSwitchTime(int index) const {
return switchTimes[index];
}

View File

@ -7,7 +7,9 @@
#ifndef EFI_WAVE_H_
#define EFI_WAVE_H_
#define PWM_PHASE_MAX_COUNT 150
#include "engine_configuration.h"
#define PWM_PHASE_MAX_COUNT 250
#define PWM_PHASE_MAX_WAVE_PER_PWM 2
/**
@ -21,18 +23,19 @@ public:
int *pinStates;
};
class trigger_shape_s;
class multi_wave_s {
public:
multi_wave_s();
multi_wave_s(float *st, single_wave_s *waves);
void init(float *st, single_wave_s *waves);
void reset(void);
float getSwitchTime(int phaseIndex) const;
float getAngle(int phaseIndex, engine_configuration_s const *engineConfiguration, trigger_shape_s * s) const;
void setSwitchTime(int phaseIndex, float value);
void checkSwitchTimes(int size);
int getChannelState(int channelIndex, int phaseIndex) const;
/**
* Number of events in the cycle
*/
int phaseCount;
/**
* Number of signal wires
*/

View File

@ -1,6 +1,6 @@
CONTROLLERS_CORE_SRC = $(PROJECT_DIR)/controllers/core/interpolation.c \
$(PROJECT_DIR)/controllers/core/avg_values.c
CONTROLLERS_CORE_SRC = $(PROJECT_DIR)/controllers/core/avg_values.c
CONTROLLERS_CORE_SRC_CPP = $(PROJECT_DIR)/controllers/core/EfiWave.cpp
CONTROLLERS_CORE_SRC_CPP = $(PROJECT_DIR)/controllers/core/EfiWave.cpp \
$(PROJECT_DIR)/controllers/core/interpolation.cpp \

View File

@ -1,5 +1,5 @@
/**
* @file interpolation.c
* @file interpolation.cpp
* @brief Linear interpolation algorithms
*
* @date Oct 17, 2013
@ -14,12 +14,30 @@
#include "main.h"
#include "interpolation.h"
//#include "engine_math.h"
#define INTERPOLATION_A(x1, y1, x2, y2) ((y1 - y2) / (x1 - x2))
int needInterpolationLogging = TRUE;
FastInterpolation::FastInterpolation(float x1, float y1, float x2, float y2) {
init(x1, y1, x2, y2);
}
void FastInterpolation::init(float x1, float y1, float x2, float y2) {
if (x1 == x2) {
firmwareError("Same x1 and x2 in interpolate: %f/%f", x1, x2);
return;
}
a = INTERPOLATION_A(x1, y1, x2, y2);
b = y1 - a * x1;
}
float FastInterpolation::getValue(float x) {
return a * x + b;
}
/** @brief Linear interpolation by two points
*
* @param x1 key of the first point
@ -39,7 +57,7 @@ float interpolate(float x1, float y1, float x2, float y2, float x) {
// a*x1 + b = y1
// a*x2 + b = y2
// chDbgCheck(x1 != x2, "no way we can interpolate");
// efiAssertVoid(x1 != x2, "no way we can interpolate");
float a = INTERPOLATION_A(x1, y1, x2, y2);
float b = y1 - a * x1;
float result = a * x + b;
@ -55,8 +73,7 @@ float interpolate(float x1, float y1, float x2, float y2, float x) {
* @note If the parameter is smaller than the first element of the array, -1 is returned.
*/
int findIndex(float array[], int size, float value) {
if (cisnan(value))
fatal("NaN in findIndex\r\n");
efiAssert(!cisnan(value), "NaN in findIndex", 0);
if (value < array[0])
return -1;
@ -67,7 +84,7 @@ int findIndex(float array[], int size, float value) {
while (1) {
if (size-- == 0)
fatal("Unexpected state in binary search.");
efiAssert(FALSE, "Unexpected state in binary search", 0);
middle = (left + right) / 2;

View File

@ -8,19 +8,19 @@
#ifndef INTERPOLATION_3D_H_
#define INTERPOLATION_3D_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
int findIndex(float array[], int size, float value);
float interpolate(float x1, float y1, float x2, float y2, float x);
float interpolate2d(float value, float bin[], float values[], int size);
float interpolate3d(float x, float xBin[], int xBinSize, float y, float yBin[], int yBinSize, float* map[]);
void setTableValue(float bins[], float values[], int size, float key, float value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
class FastInterpolation {
public:
FastInterpolation(float x1, float y1, float x2, float y2);
void init(float x1, float y1, float x2, float y2);
float getValue(float x);
private:
float a, b;
};
#endif /* INTERPOLATION_3D_H_ */

View File

@ -38,11 +38,11 @@ static Logging logger;
/**
* @brief Control Thread stack
*/
static WORKING_AREA(etbTreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(etbTreadStack, UTILITY_THREAD_STACK_SIZE);
/**
* @brief Pulse-Width Modulation state
*/
static PwmConfig etbPwm;
static SimplePwm etbPwm;
static float prevTps;
@ -69,7 +69,7 @@ static msg_t etbThread(void *arg) {
static void setThrottleConsole(int level) {
scheduleMsg(&logger, "setting throttle=%d", level);
etbPwm.multiWave.switchTimes[0] = 0.01 + (min(level, 98)) / 100.0;
etbPwm.multiWave.switchTimes[0] = 0.01 + (minI(level, 98)) / 100.0;
print("st = %f\r\n", etbPwm.multiWave.switchTimes[0]);
}
@ -84,11 +84,11 @@ void initElectronicThrottle(void) {
// outputPinRegister("etb2", ELECTRONIC_THROTTLE_CONTROL_2, ETB_CONTROL_LINE_2_PORT, ETB_CONTROL_LINE_2_PIN);
// this line used for PWM
startSimplePwm(&etbPwm, "etb",
startSimplePwmExt(&etbPwm, "etb",
boardConfiguration->electronicThrottlePin1,
ELECTRONIC_THROTTLE_CONTROL_1,
0.80,
500);
500,
0.80);
addConsoleActionI("e", setThrottleConsole);
chThdCreateStatic(etbTreadStack, sizeof(etbTreadStack), NORMALPRIO, (tfunc_t) etbThread, NULL);

View File

@ -50,15 +50,11 @@
#include "efilib2.h"
#include "ec2.h"
#include "PwmTester.h"
#include "engine.h"
extern board_configuration_s *boardConfiguration;
#define _10_MILLISECONDS (10 * TICKS_IN_MS)
#if defined __GNUC__
persistent_config_container_s persistentState __attribute__((section(".ccm")));
#else
persistent_config_container_s persistentState;
#endif
persistent_config_container_s persistentState CCM_OPTIONAL;
engine_configuration_s *engineConfiguration = &persistentState.persistentConfiguration.engineConfiguration;
board_configuration_s *boardConfiguration = &persistentState.persistentConfiguration.boardConfiguration;
@ -73,11 +69,18 @@ static VirtualTimer fuelPumpTimer;
static Logging logger;
static engine_configuration2_s ec2;
static engine_configuration2_s ec2 CCM_OPTIONAL;
engine_configuration2_s * engineConfiguration2 = &ec2;
static configuration_s cfg = {&persistentState.persistentConfiguration.engineConfiguration, &ec2};
configuration_s * configuration = &cfg;
Engine engine;
static msg_t csThread(void) {
chRegSetThreadName("status");
#if EFI_SHAFT_POSITION_INPUT
while (TRUE) {
int is_cranking = isCranking();
int is_running = getRpm() > 0 && !is_cranking;
@ -93,6 +96,8 @@ static msg_t csThread(void) {
chThdSleepMilliseconds(100);
}
}
#endif /* EFI_SHAFT_POSITION_INPUT */
return -1;
}
static void updateErrorCodes(void) {
@ -129,14 +134,12 @@ static void fanRelayControl(void) {
Overflow64Counter halTime;
uint64_t getTimeNowUs(void) {
// todo: synchronization? multi-threading?
halTime.offer(hal_lld_get_counter_value());
return halTime.get() / (CORE_CLOCK / 1000000);
return halTime.get(hal_lld_get_counter_value(), false) / (CORE_CLOCK / 1000000);
}
uint64_t getHalTimer(void) {
return halTime.get();
}
//uint64_t getHalTimer(void) {
// return halTime.get();
//}
efitimems_t currentTimeMillis(void) {
// todo: migrate to getTimeNowUs? or not?
@ -147,23 +150,23 @@ int getTimeNowSeconds(void) {
return chTimeNow() / CH_FREQUENCY;
}
static void onEveny10Milliseconds(void *arg) {
static void onEvenyGeneralMilliseconds(void *arg) {
/**
* We need to push current value into the 64 bit counter often enough so that we do not miss an overflow
*/
halTime.offer(hal_lld_get_counter_value());
halTime.get(hal_lld_get_counter_value(), true);
updateErrorCodes();
fanRelayControl();
// schedule next invocation
chVTSetAny(&everyMsTimer, _10_MILLISECONDS, &onEveny10Milliseconds, 0);
chVTSetAny(&everyMsTimer, boardConfiguration->generalPeriodicThreadPeriod * TICKS_IN_MS, &onEvenyGeneralMilliseconds, 0);
}
static void initPeriodicEvents(void) {
// schedule first invocation
chVTSetAny(&everyMsTimer, _10_MILLISECONDS, &onEveny10Milliseconds, 0);
chVTSetAny(&everyMsTimer, boardConfiguration->generalPeriodicThreadPeriod * TICKS_IN_MS, &onEvenyGeneralMilliseconds, 0);
}
static void fuelPumpOff(void *arg) {
@ -173,7 +176,7 @@ static void fuelPumpOff(void *arg) {
turnOutputPinOff(FUEL_PUMP_RELAY);
}
static void fuelPumpOn(ShaftEvents signal, int index) {
static void fuelPumpOn(trigger_event_e signal, int index, void *arg) {
if (index != 0)
return; // let's not abuse the timer - one time per revolution would be enough
// todo: the check about GPIO_NONE should be somewhere else!
@ -191,26 +194,27 @@ static void fuelPumpOn(ShaftEvents signal, int index) {
}
static void initFuelPump(void) {
addTriggerEventListener(&fuelPumpOn, "fuel pump");
fuelPumpOn(SHAFT_PRIMARY_UP, 0);
addTriggerEventListener(&fuelPumpOn, "fuel pump", NULL);
fuelPumpOn(SHAFT_PRIMARY_UP, 0, NULL);
}
char * getPinNameByAdcChannel(int hwChannel, uint8_t *buffer) {
char * getPinNameByAdcChannel(int hwChannel, char *buffer) {
strcpy((char*) buffer, portname(getAdcChannelPort(hwChannel)));
itoa10(&buffer[2], getAdcChannelPin(hwChannel));
return (char*) buffer;
}
static uint8_t pinNameBuffer[16];
static char pinNameBuffer[16];
static void printAnalogChannelInfoExt(const char *name, int hwChannel,
float voltage) {
scheduleMsg(&logger, "%s ADC%d %s value=%fv", name, hwChannel,
getPinNameByAdcChannel(hwChannel, pinNameBuffer), voltage);
float adcVoltage) {
float voltage = adcVoltage * engineConfiguration->analogInputDividerCoefficient;
scheduleMsg(&logger, "%s ADC%d %s rawValue=%f/divided=%fv", name, hwChannel,
getPinNameByAdcChannel(hwChannel, pinNameBuffer), adcVoltage, voltage);
}
static void printAnalogChannelInfo(const char *name, int hwChannel) {
printAnalogChannelInfoExt(name, hwChannel, getVoltageDivided(hwChannel));
printAnalogChannelInfoExt(name, hwChannel, getVoltage(hwChannel));
}
static void printAnalogInfo(void) {
@ -225,7 +229,7 @@ static void printAnalogInfo(void) {
getVBatt());
}
static WORKING_AREA(csThreadStack, UTILITY_THREAD_STACK_SIZE);// declare thread stack
static THD_WORKING_AREA(csThreadStack, UTILITY_THREAD_STACK_SIZE);// declare thread stack
void initEngineContoller(void) {
if (hasFirmwareError())
@ -246,11 +250,13 @@ void initEngineContoller(void) {
initWaveAnalyzer();
#endif /* EFI_WAVE_ANALYZER */
#if EFI_SHAFT_POSITION_INPUT
/**
* there is an implicit dependency on the fact that 'tachometer' listener is the 1st listener - this case
* other listeners can access current RPM value
*/
initRpmCalculator();
#endif /* EFI_SHAFT_POSITION_INPUT */
#if EFI_TUNER_STUDIO
startTunerStudioConnectivity();
@ -283,7 +289,7 @@ void initEngineContoller(void) {
/**
* This method initialized the main listener which actually runs injectors & ignition
*/
initMainEventListener();
initMainEventListener(engineConfiguration, engineConfiguration2);
#endif /* EFI_ENGINE_CONTROL */
#if EFI_IDLE_CONTROL

View File

@ -18,7 +18,7 @@ extern "C"
{
#endif /* __cplusplus */
char * getPinNameByAdcChannel(int hwChannel, uint8_t *buffer);
char * getPinNameByAdcChannel(int hwChannel, char *buffer);
void initEngineContoller(void);
#ifdef __cplusplus

View File

@ -27,10 +27,14 @@ void chDbgPanic3(const char *msg, const char * file, int line) {
return;
dbg_panic_file = file;
dbg_panic_line = line;
#if CH_DBG_SYSTEM_STATE_CHECK
dbg_panic_msg = msg;
#endif /* CH_DBG_SYSTEM_STATE_CHECK */
setOutputPinValue(LED_ERROR, 1);
/**
* low-level function is used here to reduce stack usage
*/
palWritePad(LED_ERROR_PORT, LED_ERROR_PIN, 1);
#if EFI_HD44780_LCD
lcdShowFatalMessage((char *) msg);
#endif /* EFI_HD44780_LCD */

View File

@ -1,5 +1,5 @@
/**
* @file flash_main.c
* @file flash_main.cpp
* @brief Higher-level logic of saving data into internal flash memory
*
*
@ -52,6 +52,7 @@ crc_t flashStateCrc(persistent_config_container_s *state) {
}
void writeToFlash(void) {
#if EFI_INTERNAL_FLASH
persistentState.size = PERSISTENT_SIZE;
persistentState.version = FLASH_DATA_VERSION;
scheduleMsg(&logger, "FLASH_DATA_VERSION=%d", persistentState.version);
@ -64,6 +65,7 @@ void writeToFlash(void) {
result = flashWrite(FLASH_ADDR, (const char *) &persistentState, PERSISTENT_SIZE);
scheduleMsg(&logger, "Flash programmed in (ms): %d", currentTimeMillis() - nowMs);
scheduleMsg(&logger, "Flashed: %d", result);
#endif /* EFI_INTERNAL_FLASH */
}
static int isValidCrc(persistent_config_container_s *state) {

View File

@ -11,7 +11,7 @@
#include "engine_configuration.h"
#define FLASH_DATA_VERSION 3002
#define FLASH_DATA_VERSION 3601
#ifdef __cplusplus
extern "C"

View File

@ -31,10 +31,11 @@
#include "idle_thread.h"
#include "pin_repository.h"
#include "engine_configuration.h"
#include "engine.h"
#define IDLE_AIR_CONTROL_VALVE_PWM_FREQUENCY 200
static WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(ivThreadStack, UTILITY_THREAD_STACK_SIZE);
static volatile int isIdleControlActive = EFI_IDLE_CONTROL;
extern board_configuration_s *boardConfiguration;
@ -45,15 +46,9 @@ extern board_configuration_s *boardConfiguration;
static volatile int idleSwitchState;
static Logging logger;
extern Engine engine;
static float _switchTimes[PWM_PHASE_MAX_COUNT];
// todo: extract helper for simple PWM?
static int pinStates[2];
static single_wave_s wave(pinStates);
static single_wave_s sr[1] = {wave};
static PwmConfig idleValve(_switchTimes, sr);
static SimplePwm idleValve;
/**
* Idle level calculation algorithm lives in idle_controller.c
@ -80,10 +75,10 @@ static void setIdleValvePwm(int value) {
return;
scheduleMsg(&logger, "setting idle valve PWM %d", value);
/**
* currently IDEL level is an integer per mil (0-1000 range), and PWM takes a fioat in the 0..1 range
* currently idle level is an integer per mil (0-1000 range), and PWM takes a float in the 0..1 range
* todo: unify?
*/
setSimplePwmDutyCycle(&idleValve, 0.001 * value);
idleValve.setSimplePwmDutyCycle(0.001 * value);
}
static msg_t ivThread(int param) {
@ -91,7 +86,7 @@ static msg_t ivThread(int param) {
int currentIdleValve = -1;
while (TRUE) {
chThdSleepMilliseconds(100);
chThdSleepMilliseconds(boardConfiguration->idleThreadPeriod);
// this value is not used yet
idleSwitchState = palReadPad(getHwPort(boardConfiguration->idleSwitchPin), getHwPin(boardConfiguration->idleSwitchPin));
@ -122,12 +117,11 @@ static void setIdleRpmAction(int value) {
void startIdleThread() {
initLogging(&logger, "Idle Valve Control");
startSimplePwm(&idleValve, "Idle Valve",
startSimplePwmExt(&idleValve, "Idle Valve",
boardConfiguration->idleValvePin,
IDLE_VALVE,
0.5,
IDLE_AIR_CONTROL_VALVE_PWM_FREQUENCY,
TRUE);
0.5);
idleInit(&idle);
scheduleMsg(&logger, "initial idle %d", idle.value);

View File

@ -1,5 +1,5 @@
/**
* @file injector_central.c
* @file injector_central.cpp
* @brief Utility methods related to fuel injection.
*
*
@ -22,7 +22,6 @@
#include "injector_central.h"
#include "main.h"
#include "engines.h"
#include "io_pins.h"
#include "signal_executor.h"
#include "main_trigger_callback.h"
@ -38,17 +37,13 @@ extern board_configuration_s *boardConfiguration;
static int is_injector_enabled[MAX_INJECTOR_COUNT];
int isInjectionEnabled(void) {
return engineConfiguration2->isInjectionEnabledFlag;
}
void assertCylinderId(int cylinderId, char *msg) {
void assertCylinderId(int cylinderId, const char *msg) {
int isValid = cylinderId >= 1 && cylinderId <= engineConfiguration->cylindersCount;
if (!isValid) {
// we are here only in case of a fatal issue - at this point it is fine to make some blocking i-o
//scheduleSimpleMsg(&logger, "cid=", cylinderId);
print("ERROR [%s] cid=%d\r\n", msg, cylinderId);
chDbgAssert(TRUE, "Cylinder ID", null);
efiAssertVoid(FALSE, "Cylinder ID");
}
}
@ -76,7 +71,7 @@ static void printStatus(void) {
}
static void setInjectorEnabled(int id, int value) {
chDbgCheck(id >= 0 && id < engineConfiguration->cylindersCount, "injector id");
efiAssertVoid(id >= 0 && id < engineConfiguration->cylindersCount, "injector id");
is_injector_enabled[id] = value;
printStatus();
}
@ -121,14 +116,14 @@ static void sparkbench(char * onStr, char *offStr, char *countStr) {
needToRunBench = TRUE;
}
static WORKING_AREA(benchThreadStack, UTILITY_THREAD_STACK_SIZE);
static THD_WORKING_AREA(benchThreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t benchThread(int param) {
chRegSetThreadName("BenchThread");
while (TRUE) {
while (!needToRunBench) {
chThdSleepMilliseconds(50);
chThdSleepMilliseconds(200);
}
needToRunBench = FALSE;
runBench(brainPin, pin, onTime, offTime, count);

View File

@ -19,9 +19,8 @@ extern "C"
#endif /* __cplusplus */
void initInjectorCentral(void);
int isInjectionEnabled(void);
int isInjectorEnabled(int cylinderId);
void assertCylinderId(int cylinderId, char *msg);
void assertCylinderId(int cylinderId, const char *msg);
#ifdef __cplusplus
}

View File

@ -37,7 +37,7 @@
#define MFI_BLINK_SEPARATOR 400
#define MFI_CHECKENGINE_LIGHT 10000
static WORKING_AREA(mfiThreadStack, UTILITY_THREAD_STACK_SIZE); // declare thread
static THD_WORKING_AREA(mfiThreadStack, UTILITY_THREAD_STACK_SIZE); // declare thread
static void blink_digits(int digit, int duration) {
for (int iter = 0; iter < digit; iter++) {

View File

@ -1,183 +1,186 @@
/**
* @file map_averaging.c
*
* @date Dec 11, 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 <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#if EFI_MAP_AVERAGING
#include "map_averaging.h"
#include "trigger_central.h"
#include "adc_inputs.h"
#include "map.h"
#include "engine_state.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "signal_executor.h"
#if EFI_ANALOG_CHART
#include "analog_chart.h"
#endif /* EFI_ANALOG_CHART */
#define FAST_MAP_CHART_SKIP_FACTOR 16
static Logging logger;
/**
* Running counter of measurements per revolution
*/
static volatile int perRevolutionCounter = 0;
/**
* Number of measurements in previous shaft revolution
*/
static volatile int perRevolution = 0;
/**
* Running MAP accumulator
* v_ for Voltage
*/
static volatile float v_mapAccumulator = 0;
/**
* Running counter of measurements to consider for averaging
*/
static volatile int mapMeasurementsCounter = 0;
static float currentMaxPressure;
/**
* v_ for Voltage
*/
static float v_averagedMapValue;
extern engine_configuration_s *engineConfiguration;
static scheduling_s startTimer[2];
static scheduling_s endTimer[2];
static void startAveraging(void*arg) {
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_mapAccumulator = 0;
mapMeasurementsCounter = 0;
chSysUnlockFromIsr()
;
}
/**
* This method is invoked from ADC callback
*/
void mapAveragingCallback(adcsample_t value) {
/* Calculates the average values from the ADC samples.*/
perRevolutionCounter++;
float voltage = adcToVoltsDivided(value);
float currentPressure = getMapByVoltage(voltage);
if (engineConfiguration->analogChartMode == AC_MAP)
if (perRevolutionCounter % FAST_MAP_CHART_SKIP_FACTOR == 0)
acAddData(getCrankshaftAngle(getTimeNowUs()), currentPressure);
currentMaxPressure = maxF(currentMaxPressure, currentPressure);
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_mapAccumulator += voltage;
mapMeasurementsCounter++;
chSysUnlockFromIsr()
;
}
static void endAveraging(void *arg) {
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_averagedMapValue = v_mapAccumulator / mapMeasurementsCounter;
chSysUnlockFromIsr()
;
}
/**
* Shaft Position callback used to schedule start and end of MAP averaging
*/
static void shaftPositionCallback(ShaftEvents ckpEventType, int index) {
// this callback is invoked on interrupt thread
if (index != 0)
return;
int rpm = getRpm();
if(!isValidRpm(rpm))
return;
perRevolution = perRevolutionCounter;
perRevolutionCounter = 0;
currentMaxPressure = 0;
MAP_sensor_config_s * config = &engineConfiguration->map;
float startAngle = interpolate2d(rpm, config->samplingAngleBins, config->samplingAngle, MAP_ANGLE_SIZE);
float windowAngle = interpolate2d(rpm, config->samplingWindowBins, config->samplingWindow, MAP_WINDOW_SIZE);
int structIndex = getRevolutionCounter() % 2;
// todo: schedule this based on closest trigger event, same as ignition works
scheduleByAngle(&startTimer[structIndex], startAngle, startAveraging, NULL);
scheduleByAngle(&endTimer[structIndex], startAngle + windowAngle, endAveraging, NULL);
}
static void showMapStats(void) {
scheduleMsg(&logger, "per revolution %d", perRevolution);
}
float getMapVoltage(void) {
return v_averagedMapValue;
}
/**
* because of MAP window averaging, MAP is only available while engine is spinning
*/
float getMap(void) {
if (getRpm() == 0)
return getRawMap(); // maybe return NaN and have a
return getMapByVoltage(v_averagedMapValue);
}
void initMapAveraging(void) {
initLogging(&logger, "Map Averaging");
startTimer[0].name = "map start0";
startTimer[1].name = "map start1";
endTimer[0].name = "map end0";
endTimer[1].name = "map end1";
addTriggerEventListener(&shaftPositionCallback, "rpm reporter");
addConsoleAction("faststat", showMapStats);
}
#else
float getMap(void) {
return getRawMap();
}
#endif /* EFI_MAP_AVERAGING */
/**
* @file map_averaging.cpp
*
* @date Dec 11, 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 <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "map.h"
#if EFI_MAP_AVERAGING
#include "map_averaging.h"
#include "trigger_central.h"
#include "adc_inputs.h"
#include "engine_state.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "signal_executor.h"
#include "engine.h"
#if EFI_ANALOG_CHART
#include "analog_chart.h"
#endif /* EFI_ANALOG_CHART */
#define FAST_MAP_CHART_SKIP_FACTOR 16
static Logging logger;
/**
* Running counter of measurements per revolution
*/
static volatile int perRevolutionCounter = 0;
/**
* Number of measurements in previous shaft revolution
*/
static volatile int perRevolution = 0;
/**
* Running MAP accumulator
* v_ for Voltage
*/
static volatile float v_mapAccumulator = 0;
/**
* Running counter of measurements to consider for averaging
*/
static volatile int mapMeasurementsCounter = 0;
/**
* v_ for Voltage
*/
static float v_averagedMapValue;
extern Engine engine;
extern engine_configuration_s *engineConfiguration;
static scheduling_s startTimer[2];
static scheduling_s endTimer[2];
static void startAveraging(void*arg) {
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_mapAccumulator = 0;
mapMeasurementsCounter = 0;
chSysUnlockFromIsr()
;
}
/**
* This method is invoked from ADC callback.
* @note This method is invoked OFTEN, this method is a potential bottle-next - the implementation should be
* as fast as possible
*/
void mapAveragingCallback(adcsample_t value) {
/* Calculates the average values from the ADC samples.*/
perRevolutionCounter++;
float voltage = adcToVoltsDivided(value);
float currentPressure = getMapByVoltage(voltage);
#if EFI_ANALOG_CHART
if (engineConfiguration->analogChartMode == AC_MAP)
if (perRevolutionCounter % FAST_MAP_CHART_SKIP_FACTOR == 0)
acAddData(getCrankshaftAngle(getTimeNowUs()), currentPressure);
#endif /* EFI_ANALOG_CHART */
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_mapAccumulator += voltage;
mapMeasurementsCounter++;
chSysUnlockFromIsr()
;
}
static void endAveraging(void *arg) {
chSysLockFromIsr()
;
// with locking we would have a consistent state
v_averagedMapValue = v_mapAccumulator / mapMeasurementsCounter;
chSysUnlockFromIsr()
;
}
/**
* Shaft Position callback used to schedule start and end of MAP averaging
*/
static void shaftPositionCallback(trigger_event_e ckpEventType, int index, void *arg) {
// this callback is invoked on interrupt thread
if (index != 0)
return;
int rpm = getRpm();
if(!isValidRpm(rpm))
return;
perRevolution = perRevolutionCounter;
perRevolutionCounter = 0;
MAP_sensor_config_s * config = &engineConfiguration->map;
float startAngle = interpolate2d(rpm, config->samplingAngleBins, config->samplingAngle, MAP_ANGLE_SIZE);
float windowAngle = interpolate2d(rpm, config->samplingWindowBins, config->samplingWindow, MAP_WINDOW_SIZE);
int structIndex = getRevolutionCounter() % 2;
// todo: schedule this based on closest trigger event, same as ignition works
scheduleByAngle(&startTimer[structIndex], startAngle, startAveraging, NULL);
scheduleByAngle(&endTimer[structIndex], startAngle + windowAngle, endAveraging, NULL);
}
static void showMapStats(void) {
scheduleMsg(&logger, "per revolution %d", perRevolution);
}
float getMapVoltage(void) {
return v_averagedMapValue;
}
/**
* Because of MAP window averaging, MAP is only available while engine is spinning
* @return Manifold Absolute Pressure, in kPa
*/
float getMap(void) {
if (getRpm() == 0)
return getRawMap(); // maybe return NaN in case of stopped engine?
return getMapByVoltage(v_averagedMapValue);
}
void initMapAveraging(void) {
initLogging(&logger, "Map Averaging");
startTimer[0].name = "map start0";
startTimer[1].name = "map start1";
endTimer[0].name = "map end0";
endTimer[1].name = "map end1";
addTriggerEventListener(&shaftPositionCallback, "rpm reporter", NULL);
addConsoleAction("faststat", showMapStats);
}
#else
float getMap(void) {
return getRawMap();
}
#endif /* EFI_MAP_AVERAGING */

View File

@ -1,83 +1,86 @@
/*
* @brief dead code
*
*
* map_multiplier.c
*
* @date Jul 23, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "map_multiplier_thread.h"
#include "map_adjuster.h"
#include "rpm_calculator.h"
#include "main_trigger_callback.h"
#include "wave_math.h"
#include "allsensors.h"
#include "engine_math.h"
extern engine_configuration_s *engineConfiguration;
static Logging logger;
static WORKING_AREA(maThreadStack, UTILITY_THREAD_STACK_SIZE);
static void mapCallback(int rpm, float key, float value) {
Logging *logging = &logger;
appendPrintf(logging, "msg%s", DELIMETER);
appendPrintf(logging, "map_adjusted: ");
appendPrintf(logging, "%d", rpm);
appendPrintf(logging, " ");
appendPrintf(logging, "%d", 100 * key);
appendPrintf(logging, " ");
appendPrintf(logging, "%d", 100 * value);
appendMsgPostfix(logging);
scheduleLogging(logging);
}
static int timeAtNotRunning = 0;
static int isNewState = TRUE;
static void maThread(int param) {
chRegSetThreadName("map adjustment");
while (TRUE) {
chThdSleepMilliseconds(100);
systime_t now = chTimeNow();
if (!isRunning()) {
timeAtNotRunning = now;
continue;
}
int wasNotRunningRecently = overflowDiff(now, timeAtNotRunning) < 60 * CH_FREQUENCY;
if (!wasNotRunningRecently)
continue;
if (isNewState)
scheduleMsg(&logger, "starting fuel map adjustment at %d", now);
isNewState = FALSE;
// ideally this should be atomic, but hopefully it's good enough
int rpm = getRpm();
float load = getEngineLoad();
float afr = getAfr();
addAfr(rpm, load, afr);
int total = runMapAdjustments(mapCallback);
if (total > 0) {
// scheduleSimpleMsg(&logger, "map adjusted for maf ", 100 * key);
}
}
}
void initMapAdjusterThread(void) {
initLogging(&logger, "Map self learning thread");
initMapAdjuster();
chThdCreateStatic(maThreadStack, sizeof(maThreadStack), NORMALPRIO, (tfunc_t)maThread, NULL);
}
/*
* @brief dead code
*
*
* map_multiplier.cpp
*
* @date Jul 23, 2013
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#include "main.h"
#include "map_multiplier_thread.h"
#include "map_adjuster.h"
#include "rpm_calculator.h"
#include "main_trigger_callback.h"
#include "wave_math.h"
#include "allsensors.h"
#include "engine_math.h"
#include "engine.h"
extern engine_configuration_s *engineConfiguration;
static Logging logger;
extern Engine engine;
static THD_WORKING_AREA(maThreadStack, UTILITY_THREAD_STACK_SIZE);
static void mapCallback(int rpm, float key, float value) {
Logging *logging = &logger;
appendPrintf(logging, "msg%s", DELIMETER);
appendPrintf(logging, "map_adjusted: ");
appendPrintf(logging, "%d", rpm);
appendPrintf(logging, " ");
appendPrintf(logging, "%d", 100 * key);
appendPrintf(logging, " ");
appendPrintf(logging, "%d", 100 * value);
appendMsgPostfix(logging);
scheduleLogging(logging);
}
static int timeAtNotRunning = 0;
static int isNewState = TRUE;
static void maThread(int param) {
chRegSetThreadName("map adjustment");
while (TRUE) {
chThdSleepMilliseconds(100);
systime_t now = chTimeNow();
if (!isRunning()) {
timeAtNotRunning = now;
continue;
}
int wasNotRunningRecently = overflowDiff(now, timeAtNotRunning) < 60 * CH_FREQUENCY;
if (!wasNotRunningRecently)
continue;
if (isNewState)
scheduleMsg(&logger, "starting fuel map adjustment at %d", now);
isNewState = FALSE;
// ideally this should be atomic, but hopefully it's good enough
int rpm = getRpm();
float load = getEngineLoad();
float afr = getAfr();
addAfr(rpm, load, afr);
int total = runMapAdjustments(mapCallback);
if (total > 0) {
// scheduleSimpleMsg(&logger, "map adjusted for maf ", 100 * key);
}
}
}
void initMapAdjusterThread(void) {
initLogging(&logger, "Map self learning thread");
initMapAdjuster();
chThdCreateStatic(maThreadStack, sizeof(maThreadStack), NORMALPRIO, (tfunc_t)maThread, NULL);
}

View File

@ -19,14 +19,15 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine_math.h"
#include "main.h"
#include "engine_math.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "allsensors.h"
#include "io_pins.h"
#include "OutputSignalList.h"
#include "trigger_decoder.h"
#include "event_registry.h"
/*
* default Volumetric Efficiency
@ -36,42 +37,21 @@
// return interpolate(5000, 1.1, 8000, 1, rpm);
// return interpolate(500, 0.5, 5000, 1.1, rpm);
//}
//#define K_AT_MIN_RPM_MIN_TPS 0.25
//#define K_AT_MIN_RPM_MAX_TPS 0.25
//#define K_AT_MAX_RPM_MIN_TPS 0.25
//#define K_AT_MAX_RPM_MAX_TPS 0.9
//
//#define rpmMin 500
//#define rpmMax 8000
//
//#define tpMin 0
//#define tpMax 100
//
// http://rusefi.com/math/t_charge.html
// /
//float getTCharge(int rpm, int tps, float coolantTemp, float airTemp) {
// float minRpmKcurrentTPS = interpolate(tpMin, K_AT_MIN_RPM_MIN_TPS, tpMax,
// K_AT_MIN_RPM_MAX_TPS, tps);
// float maxRpmKcurrentTPS = interpolate(tpMin, K_AT_MAX_RPM_MIN_TPS, tpMax,
// K_AT_MAX_RPM_MAX_TPS, tps);
//
// float Tcharge_coff = interpolate(rpmMin, minRpmKcurrentTPS, rpmMax,
// maxRpmKcurrentTPS, rpm);
//
// float Tcharge = coolantTemp * (1 - Tcharge_coff) + airTemp * Tcharge_coff;
//
// return Tcharge;
//}
#define MAX_STARTING_FUEL 15
#define MIN_STARTING_FUEL 8
/**
* @return time needed to rotate crankshaft by one degree, in milliseconds.
* @deprecated
*/
float getOneDegreeTimeMs(int rpm) {
return 1000.0 * 60 / 360 / rpm;
}
/**
* @return time needed to rotate crankshaft by one degree, in microseconds.
*/
float getOneDegreeTimeUs(int rpm) {
return 1000000.0 * 60 / 360 / rpm;
}
/**
* @return number of milliseconds in one crankshaft revolution
*/
@ -136,34 +116,39 @@ int isCrankingRT(engine_configuration_s *engineConfiguration, int rpm) {
OutputSignalList ignitionSignals;
OutputSignalList injectonSignals;
static void registerSparkEvent(engine_configuration_s const *engineConfiguration, trigger_shape_s * s,
ActuatorEventList *list, OutputSignal *actuator, float angleOffset) {
IgnitionEventList *list, OutputSignal *actuator, float localAdvance, float dwell) {
registerActuatorEventExt(engineConfiguration, s, list,
actuator, angleOffset);
IgnitionEvent *event = list->getNextActuatorEvent();
if (event == NULL)
return; // error already reported
event->advance = localAdvance;
registerActuatorEventExt(engineConfiguration, s, &event->actuator, actuator, localAdvance - dwell);
}
void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2, float dwellMs, ActuatorEventList *list) {
chDbgCheck(engineConfiguration->cylindersCount > 0, "cylindersCount");
void initializeIgnitionActions(float advance, float dwellAngle, engine_configuration_s *engineConfiguration,
engine_configuration2_s *engineConfiguration2, IgnitionEventList *list) {
efiAssertVoid(engineConfiguration->cylindersCount > 0, "cylindersCount");
ignitionSignals.clear();
resetEventList(list);
list->resetEventList();
switch (engineConfiguration->ignitionMode) {
case IM_ONE_COIL:
for (int i = 0; i < engineConfiguration->cylindersCount; i++) {
// todo: extract method
float angle = baseAngle + 720.0 * i / engineConfiguration->cylindersCount;
float localAdvance = advance + 720.0 * i / engineConfiguration->cylindersCount;
registerSparkEvent(engineConfiguration, &engineConfiguration2->triggerShape, list,
ignitionSignals.add(SPARKOUT_1_OUTPUT), angle);
ignitionSignals.add(SPARKOUT_1_OUTPUT), localAdvance, dwellAngle);
}
break;
case IM_WASTED_SPARK:
for (int i = 0; i < engineConfiguration->cylindersCount; i++) {
float angle = baseAngle + 720.0 * i / engineConfiguration->cylindersCount;
float localAdvance = advance + 720.0 * i / engineConfiguration->cylindersCount;
int wastedIndex = i % (engineConfiguration->cylindersCount / 2);
@ -171,18 +156,18 @@ void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineCo
io_pin_e ioPin = (io_pin_e) (SPARKOUT_1_OUTPUT + id);
registerSparkEvent(engineConfiguration, &engineConfiguration2->triggerShape, list,
ignitionSignals.add(ioPin), angle);
ignitionSignals.add(ioPin), localAdvance, dwellAngle);
}
break;
case IM_INDIVIDUAL_COILS:
for (int i = 0; i < engineConfiguration->cylindersCount; i++) {
float angle = baseAngle + 720.0 * i / engineConfiguration->cylindersCount;
float localAdvance = advance + 720.0 * i / engineConfiguration->cylindersCount;
io_pin_e pin = (io_pin_e) ((int) SPARKOUT_1_OUTPUT + getCylinderId(engineConfiguration->firingOrder, i) - 1);
registerSparkEvent(engineConfiguration, &engineConfiguration2->triggerShape, list,
ignitionSignals.add(pin), angle);
registerSparkEvent(engineConfiguration, &engineConfiguration2->triggerShape, list, ignitionSignals.add(pin),
localAdvance, dwellAngle);
}
break;
@ -193,7 +178,7 @@ void initializeIgnitionActions(float baseAngle, engine_configuration_s *engineCo
void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *engineConfiguration2,
ActuatorEventList *list, injection_mode_e mode) {
resetEventList(list);
list->resetEventList();
trigger_shape_s *s = &engineConfiguration2->triggerShape;
@ -204,7 +189,7 @@ void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *eng
for (int i = 0; i < e->cylindersCount; i++) {
io_pin_e pin = (io_pin_e) ((int) INJECTOR_1_OUTPUT + getCylinderId(e->firingOrder, i) - 1);
float angle = baseAngle + i * 720.0 / e->cylindersCount;
registerActuatorEventExt(e, s, list, injectonSignals.add(pin), angle);
registerActuatorEventExt(e, s, list->getNextActuatorEvent(), injectonSignals.add(pin), angle);
}
break;
case IM_SIMULTANEOUS:
@ -213,7 +198,7 @@ void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *eng
for (int j = 0; j < e->cylindersCount; j++) {
io_pin_e pin = (io_pin_e) ((int) INJECTOR_1_OUTPUT + j);
registerActuatorEventExt(e, s, list, injectonSignals.add(pin), angle);
registerActuatorEventExt(e, s, list->getNextActuatorEvent(), injectonSignals.add(pin), angle);
}
}
break;
@ -221,7 +206,7 @@ void addFuelEvents(engine_configuration_s const *e, engine_configuration2_s *eng
for (int i = 0; i < e->cylindersCount; i++) {
io_pin_e pin = (io_pin_e) ((int) INJECTOR_1_OUTPUT + (i % 2));
float angle = baseAngle + i * 720.0 / e->cylindersCount;
registerActuatorEventExt(e, s, list, injectonSignals.add(pin), angle);
registerActuatorEventExt(e, s, list->getNextActuatorEvent(), injectonSignals.add(pin), angle);
}
break;
default:
@ -238,53 +223,76 @@ float getSparkDwellMsT(engine_configuration_s *engineConfiguration, int rpm) {
float angle = engineConfiguration->crankingChargeAngle;
return getOneDegreeTimeMs(rpm) * angle;
}
efiAssert(!cisnan(rpm), "invalid rpm");
efiAssert(!cisnan(rpm), "invalid rpm", NAN);
return interpolate2d(rpm, engineConfiguration->sparkDwellBins, engineConfiguration->sparkDwell, DWELL_CURVE_SIZE);
}
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s,
ActuatorEventList *list, OutputSignal *actuator, float angleOffset) {
chDbgCheck(s->getSize() > 0, "uninitialized trigger_shape_s");
/**
* Trigger event count equals engine cycle event count if we have a cam sensor.
* Two trigger cycles make one engine cycle in case of a four stroke engine If we only have a cranksensor.
*/
int getEngineCycleEventCount(engine_configuration_s const *engineConfiguration, trigger_shape_s * s) {
return getOperationMode(engineConfiguration) == FOUR_STROKE_CAM_SENSOR ? s->getSize() : 2 * s->getSize();
}
void findTriggerPosition(engine_configuration_s const *engineConfiguration, trigger_shape_s * s,
event_trigger_position_s *position, float angleOffset) {
angleOffset = fixAngle(angleOffset + engineConfiguration->globalTriggerAngleOffset);
int triggerIndexOfZeroEvent = s->triggerShapeSynchPointIndex;
// todo: migrate to crankAngleRange?
float firstAngle = s->wave.getSwitchTime(triggerIndexOfZeroEvent) * 720;
float firstAngle = s->wave.getAngle(s->triggerShapeSynchPointIndex, engineConfiguration, s);
int engineCycleEventCount = getEngineCycleEventCount(engineConfiguration, s);
// let's find the last trigger angle which is less or equal to the desired angle
int i;
for (i = 0; i < s->getSize() - 1; i++) {
for (i = 0; i < engineCycleEventCount - 1; i++) {
// todo: we need binary search here
float angle = fixAngle(
s->wave.getSwitchTime((triggerIndexOfZeroEvent + i + 1) % s->getSize()) * 720 - firstAngle);
s->wave.getAngle((s->triggerShapeSynchPointIndex + i + 1) % engineCycleEventCount, engineConfiguration, s)
- firstAngle);
if (angle > angleOffset)
break;
}
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
float angle =
i == 0 ?
0 :
fixAngle(s->wave.getSwitchTime((triggerIndexOfZeroEvent + i) % s->getSize()) * 720 - firstAngle);
float eventAngle;
if (i == 0) {
eventAngle = 0;
} else {
eventAngle = fixAngle(
s->wave.getAngle((s->triggerShapeSynchPointIndex + i) % engineCycleEventCount, engineConfiguration, s)
- firstAngle);
}
if (angleOffset < angle) {
firmwareError("angle constraint violation in registerActuatorEventExt(): %f/%f", angleOffset, angle);
if (angleOffset < eventAngle) {
firmwareError("angle constraint violation in registerActuatorEventExt(): %f/%f", angleOffset, eventAngle);
return;
}
registerActuatorEvent(list, i, actuator, angleOffset - angle);
position->eventIndex = i;
position->eventAngle = eventAngle;
position->angleOffset = angleOffset - eventAngle;
}
//float getTriggerEventAngle(int triggerEventIndex) {
// return 0;
//}
void registerActuatorEventExt(engine_configuration_s const *engineConfiguration, trigger_shape_s * s, ActuatorEvent *e,
OutputSignal *actuator, float angleOffset) {
efiAssertVoid(s->getSize() > 0, "uninitialized trigger_shape_s");
if (e == NULL)
return; // error already reported
e->actuator = actuator;
findTriggerPosition(engineConfiguration, s, &e->position, angleOffset);
}
static int order_1_THEN_3_THEN_4_THEN2[] = { 1, 3, 4, 2 };
static int order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4[] = { 1, 5, 3, 6, 2, 4 };
static int order_1_8_4_3_6_5_7_2[] = {1, 8, 4, 3, 6, 5, 7, 2};
/**
* @param index from zero to cylindersCount - 1
* @return cylinderId from one to cylindersCount
@ -298,6 +306,8 @@ int getCylinderId(firing_order_e firingOrder, int index) {
return order_1_THEN_3_THEN_4_THEN2[index];
case FO_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4:
return order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4[index];
case FO_1_8_4_3_6_5_7_2:
return order_1_8_4_3_6_5_7_2[index];
default:
firmwareError("getCylinderId not supported for %d", firingOrder);
@ -320,8 +330,13 @@ void prepareOutputSignals(engine_configuration_s *engineConfiguration, engine_co
}
void setTableBin(float array[], int size, float l, float r) {
for (int i = 0; i < size; i++)
array[i] = interpolate(0, l, size - 1, r, i);
for (int i = 0; i < size; i++) {
float value = interpolate(0, l, size - 1, r, i);
/**
* rounded values look nicer, also we want to avoid precision mismatch with Tuner Studio
*/
array[i] = efiRound(value, 0.01);
}
}
void setFuelRpmBin(engine_configuration_s *engineConfiguration, float l, float r) {
@ -339,3 +354,7 @@ void setTimingRpmBin(engine_configuration_s *engineConfiguration, float l, float
void setTimingLoadBin(engine_configuration_s *engineConfiguration, float l, float r) {
setTableBin(engineConfiguration->ignitionLoadBins, IGN_LOAD_COUNT, l, r);
}
int isInjectionEnabled(engine_configuration2_s const *engineConfiguration2) {
return engineConfiguration2->isInjectionEnabledFlag;
}

View File

@ -10,6 +10,54 @@
#include "engine_configuration.h"
#ifdef __cplusplus
#include "ec2.h"
#include "trigger_structure.h"
void findTriggerPosition(engine_configuration_s const *engineConfiguration, trigger_shape_s * s,
event_trigger_position_s *position, float angleOffset);
int isInjectionEnabled(engine_configuration2_s const *engineConfiguration2);
// 'random' value to be sure we are not treating any non-zero trash as TRUE
#define MAGIC_TRUE_VALUE 153351512
template<int RPM_BIN_SIZE, int LOAD_BIN_SIZE>
class Map3D {
public:
void init(float table[RPM_BIN_SIZE][LOAD_BIN_SIZE]);
float getValue(float x, float xBin[], float y, float yBin[]);
void setAll(float value);
private:
float *pointers[LOAD_BIN_SIZE];
int initialized;
};
template<int RPM_BIN_SIZE, int LOAD_BIN_SIZE>
void Map3D<RPM_BIN_SIZE, LOAD_BIN_SIZE>::init(float table[RPM_BIN_SIZE][LOAD_BIN_SIZE]) {
for (int k = 0; k < LOAD_BIN_SIZE; k++)
pointers[k] = table[k];
initialized = MAGIC_TRUE_VALUE;
}
template<int RPM_BIN_SIZE, int LOAD_BIN_SIZE>
float Map3D<RPM_BIN_SIZE, LOAD_BIN_SIZE>::getValue(float x, float xBin[], float y, float yBin[]) {
efiAssert(initialized == MAGIC_TRUE_VALUE, "fuel map initialized", NAN);
return interpolate3d(x, xBin, LOAD_BIN_SIZE, y, yBin, RPM_BIN_SIZE, pointers);
}
template<int RPM_BIN_SIZE, int LOAD_BIN_SIZE>
void Map3D<RPM_BIN_SIZE, LOAD_BIN_SIZE>::setAll(float value) {
for (int l = 0; l < LOAD_BIN_SIZE; l++) {
for (int r = 0; r < RPM_BIN_SIZE; r++) {
pointers[l][r] = value;
}
}
}
typedef Map3D<16, 16> Map3D1616;
#endif
#ifdef __cplusplus
extern "C"
{
@ -18,9 +66,9 @@ extern "C"
//float getDefaultVE(int rpm);
float getDefaultFuel(int rpm, float map);
//float getTCharge(int rpm, int tps, float coolantTemp, float airTemp);
float getOneDegreeTimeMs(int rpm);
float getOneDegreeTimeUs(int rpm);
float getCrankshaftRevolutionTimeMs(int rpm);
int isCrankingRT(engine_configuration_s *engineConfiguration, int rpm);
@ -35,6 +83,7 @@ float getEngineLoadT(engine_configuration_s *engineConfiguration);
float getSparkDwellMsT(engine_configuration_s *engineConfiguration, int rpm);
#define getSparkDwellMs(rpm) getSparkDwellMsT(engineConfiguration, rpm)
int getCylinderId(firing_order_e firingOrder, int index);
void setTableBin(float array[], int size, float l, float r);

View File

@ -1,4 +1,5 @@
CONTROLLERS_MATH_SRC =
CONTROLLERS_MATH_SRC_CPP = $(PROJECT_DIR)/controllers/math/engine_math.cpp
CONTROLLERS_MATH_SRC_CPP = $(PROJECT_DIR)/controllers/math/engine_math.cpp \
$(PROJECT_DIR)/controllers/math/speed_density.cpp

View File

@ -0,0 +1,78 @@
/**
* @file speed_density.cpp
*
* @date May 29, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#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"
#define K_AT_MIN_RPM_MIN_TPS 0.25
#define K_AT_MIN_RPM_MAX_TPS 0.25
#define K_AT_MAX_RPM_MIN_TPS 0.25
#define K_AT_MAX_RPM_MAX_TPS 0.9
#define rpmMin 500
#define rpmMax 8000
static Map3D1616 veMap;
static Map3D1616 afrMap;
#define tpMin 0
#define tpMax 100
// http://rusefi.com/math/t_charge.html
float getTCharge(int rpm, int tps, float coolantTemp, float airTemp) {
float minRpmKcurrentTPS = interpolate(tpMin, K_AT_MIN_RPM_MIN_TPS, tpMax,
K_AT_MIN_RPM_MAX_TPS, tps);
float maxRpmKcurrentTPS = interpolate(tpMin, K_AT_MAX_RPM_MIN_TPS, tpMax,
K_AT_MAX_RPM_MAX_TPS, tps);
float Tcharge_coff = interpolate(rpmMin, minRpmKcurrentTPS, rpmMax, maxRpmKcurrentTPS, rpm);
float Tcharge = coolantTemp * (1 - Tcharge_coff) + airTemp * Tcharge_coff;
return Tcharge;
}
/**
* is J/g*K
*/
#define GAS_R 0.28705
float sdMath(engine_configuration_s *engineConfiguration, float VE, float MAP, float AFR, float temp) {
float injectorFlowRate = cc_minute_to_gramm_second(engineConfiguration->injectorFlow);
float Vol = engineConfiguration->displacement / engineConfiguration->cylindersCount;
return (Vol * VE * MAP) / (AFR * injectorFlowRate * GAS_R * temp);
}
float getSpeedDensityFuel(Engine *engine) {
int rpm = engine->rpmCalculator->rpm();
float tps = getTPS();
float coolantC = getCoolantTemperature();
float intakeC = getIntakeAirTemperature();
float tChargeK = convertCelciusToKelvin(getTCharge(rpm, tps, coolantC, intakeC));
float MAP = getMap();
float VE = 0.8;//veMap.getValue(rpm)
float AFR = 14.7;
return sdMath(engine->engineConfiguration, VE, MAP, AFR, tChargeK);
}
void setDetaultVETable(engine_configuration_s *engineConfiguration) {
setTableBin(engineConfiguration->veRpmBins, FUEL_RPM_COUNT, 800, 7000);
veMap.setAll(0.8);
}
void initSpeedDensity(configuration_s *config) {
veMap.init(config->engineConfiguration->veTable);
afrMap.init(config->engineConfiguration->afrTable);
}

View File

@ -0,0 +1,23 @@
/**
* @file speed_density.h
*
* @date May 29, 2014
* @author Andrey Belomutskiy, (c) 2012-2014
*/
#ifndef SPEED_DENSITY_H_
#define SPEED_DENSITY_H_
#include "engine_configuration.h"
#include "ec2.h"
float getTCharge(int rpm, int tps, float coolantTemp, float airTemp);
void setDetaultVETable(engine_configuration_s *engineConfiguration);
float sdMath(engine_configuration_s *engineConfiguration, float VE, float MAP, float AFR, float temp);
#define gramm_second_to_cc_minute(gs) ((gs) / 0.0119997981)
#define cc_minute_to_gramm_second(ccm) ((ccm) * 0.0119997981)
void initSpeedDensity(configuration_s *config);
#endif /* SPEED_DENSITY_H_ */

View File

@ -1,15 +1,15 @@
#include "main.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "boards.h"
#include "adc_inputs.h"
extern engine_configuration_s *engineConfiguration;
float getAfr(void) {
afr_sensor_s * sensor = &engineConfiguration->afrSensor;
float volts = getVoltageDivided(sensor->afrAdcChannel);
return interpolate(sensor->v1, sensor->value1, sensor->v2, sensor->value2, volts);
}
#include "main.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "boards.h"
#include "adc_inputs.h"
extern engine_configuration_s *engineConfiguration;
float getAfr(void) {
afr_sensor_s * sensor = &engineConfiguration->afrSensor;
float volts = getVoltageDivided(sensor->afrAdcChannel);
return interpolate(sensor->v1, sensor->value1, sensor->v2, sensor->value2, volts);
}

View File

@ -12,15 +12,6 @@
#include "main.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
float getAfr(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -1,58 +1,58 @@
#include "main.h"
#include "boards.h"
#include "engine_configuration.h"
#include "engine_math.h"
#include "adc_inputs.h"
#include "interpolation.h"
#include "error_handling.h"
#include "map.h"
extern engine_configuration_s * engineConfiguration;
/**
* @brief MAP value decoded for a 1.83 Honda sensor
* -6.64kPa at zero volts
* 182.78kPa at 5 volts
*
* @returns kPa value
*/
float getMAPValueHonda_Denso183(float voltage) {
return interpolate(0, -6.64, 5, 182.78, voltage);
}
float getMAPValueMPX_4250(float voltage) {
return interpolate(0, 8, 5, 260, voltage);
}
float decodePressure(float voltage, air_pressure_sensor_config_s * config) {
switch (config->sensorType) {
case MT_CUSTOM:
return interpolate(0, config->Min, 5, config->Max, voltage);
case MT_DENSO183:
return getMAPValueHonda_Denso183(voltage);
case MT_MPX4250:
return getMAPValueMPX_4250(voltage);
default:
firmwareError("Unknown MAP type: %d", config->sensorType);
return NAN;
}
}
/**
* @brief MAP value decoded according to current settings
* @returns kPa value
*/
float getMapByVoltage(float voltage) {
air_pressure_sensor_config_s * config = &engineConfiguration->map.sensor;
return decodePressure(voltage, config);
}
float getRawMap(void) {
float voltage = getVoltageDivided(engineConfiguration->map.sensor.hwChannel);
return getMapByVoltage(voltage);
}
float getBaroPressure(void) {
float voltage = getVoltageDivided(engineConfiguration->baroSensor.hwChannel);
return decodePressure(voltage, &engineConfiguration->baroSensor);
}
#include "main.h"
#include "boards.h"
#include "engine_configuration.h"
#include "engine_math.h"
#include "adc_inputs.h"
#include "interpolation.h"
#include "error_handling.h"
#include "map.h"
extern engine_configuration_s * engineConfiguration;
/**
* @brief MAP value decoded for a 1.83 Honda sensor
* -6.64kPa at zero volts
* 182.78kPa at 5 volts
*
* @returns kPa value
*/
static FastInterpolation denso183(0, -6.64, 5, 182.78);
static FastInterpolation mpx4250(0, 8, 5, 260);
float decodePressure(float voltage, air_pressure_sensor_config_s * config) {
switch (config->sensorType) {
case MT_CUSTOM:
// todo: introduce 'FastInterpolation customMap'
return interpolate(0, config->Min, 5, config->Max, voltage);
case MT_DENSO183:
return denso183.getValue(voltage);
case MT_MPX4250:
return mpx4250.getValue(voltage);
default:
firmwareError("Unknown MAP type: %d", config->sensorType);
return NAN;
}
}
/**
* @brief MAP value decoded according to current settings
* @returns kPa value
*/
float getMapByVoltage(float voltage) {
air_pressure_sensor_config_s * config = &engineConfiguration->map.sensor;
return decodePressure(voltage, config);
}
/**
* @return Manifold Absolute Pressure, in kPa
*/
float getRawMap(void) {
float voltage = getVoltageDivided(engineConfiguration->map.sensor.hwChannel);
return getMapByVoltage(voltage);
}
float getBaroPressure(void) {
float voltage = getVoltageDivided(engineConfiguration->baroSensor.hwChannel);
return decodePressure(voltage, &engineConfiguration->baroSensor);
}

View File

@ -6,6 +6,8 @@ extern "C"
{
#endif /* __cplusplus */
#include "sensor_types.h"
/**
* @return Raw MAP sensor value right now
*/
@ -17,8 +19,7 @@ float getBaroPressure(void);
float getMap(void);
float getMapVoltage(void);
float getMapByVoltage(float voltage);
float getMAPValueHonda_Denso183(float volts);
float getMAPValueMPX_4250(float volts);
float decodePressure(float voltage, air_pressure_sensor_config_s * config);
#ifdef __cplusplus
}

View File

@ -14,6 +14,9 @@
#include "rusefi_enums.h"
typedef struct {
/**
* kPa value at zero volts
*/
float Min;
float Max;
air_pressure_sensor_type_e sensorType;

View File

@ -1,9 +1,9 @@
CONTROLLERS_SENSORS_SRC = $(PROJECT_DIR)/controllers/sensors/tps.c \
$(PROJECT_DIR)/controllers/sensors/allsensors.c \
CONTROLLERS_SENSORS_SRC = $(PROJECT_DIR)/controllers/sensors/allsensors.c \
$(PROJECT_DIR)/controllers/sensors/maf.c \
$(PROJECT_DIR)/controllers/sensors/map.c \
$(PROJECT_DIR)/controllers/sensors/ego.c \
$(PROJECT_DIR)/controllers/sensors/voltage.c
CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cpp
CONTROLLERS_SENSORS_SRC_CPP = $(PROJECT_DIR)/controllers/sensors/thermistors.cpp \
$(PROJECT_DIR)/controllers/sensors/map.cpp \
$(PROJECT_DIR)/controllers/sensors/tps.cpp \
$(PROJECT_DIR)/controllers/sensors/ego.cpp

View File

@ -52,7 +52,7 @@ float convertKelvinToC(float tempK) {
return tempK - KELV;
}
float convertCelciustoKelvin(float tempC) {
float convertCelciusToKelvin(float tempC) {
return tempC + KELV;
}
@ -81,7 +81,7 @@ float getKelvinTemperature(float resistance, ThermistorConf *thermistor) {
float getResistance(Thermistor *thermistor) {
float voltage = getVoltageDivided(thermistor->channel);
chDbgCheck(thermistor->config != NULL, "config is null");
efiAssert(thermistor->config != NULL, "config is null", NAN);
float resistance = getR2InVoltageDividor(voltage, _5_VOLTS, thermistor->config->bias_resistor);
return resistance;
}

View File

@ -29,7 +29,7 @@ float getTempK(float resistance);
* converts Kelvin temperature into Celcius temperature
*/
float convertKelvinToCelcius(float tempK);
float convertCelciustoKelvin(float tempC);
float convertCelciusToKelvin(float tempC);
float convertCelciustoF(float tempC);
float convertFtoCelcius(float tempF);

View File

@ -1,109 +1,109 @@
#include "main.h"
#include "boards.h"
#include "tps.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "adc_inputs.h"
#include "wave_math.h"
extern engine_configuration_s *engineConfiguration;
/**
* We are using one instance for read and another for modification, this is how we get lock-free thread-safety
*
*/
static tps_roc_s states[2];
static volatile int tpsRocIndex = 0;
/**
* this method is lock-free thread-safe if invoked only from one thread
*/
void saveTpsState(time_t now, float curValue) {
int tpsNextIndex = (tpsRocIndex + 1) % 2;
tps_roc_s *cur = &states[tpsRocIndex];
tps_roc_s *next = &states[tpsNextIndex];
next->prevTime = cur->curTime;
next->prevValue = cur->curValue;
next->curTime = now;
next->curValue = curValue;
int diffSysticks = overflowDiff(now, cur->curTime);
float diffSeconds = diffSysticks * 1.0 / CH_FREQUENCY;
next->rateOfChange = (curValue - cur->curValue) / diffSeconds;
// here we update volatile index
tpsRocIndex = tpsNextIndex;
}
/**
* this read-only method is lock-free thread-safe
*/
float getTpsRateOfChange(void) {
return states[tpsRocIndex].rateOfChange;
}
/*
* Return current TPS position based on configured ADC levels, and adc
*
* */
float getTpsValue(int adc) {
if (adc < engineConfiguration->tpsMin)
return 0;
if (adc > engineConfiguration->tpsMax)
return 100;
// todo: double comparison using EPS
if (engineConfiguration->tpsMin == engineConfiguration->tpsMax) {
firmwareError("Invalid TPS configuration: same value");
return 0;
}
return interpolate(engineConfiguration->tpsMin, 0, engineConfiguration->tpsMax, 100, adc);
}
/*
* Return voltage on TPS AND channel
* */
float getTPSVoltage(void) {
return getVoltageDivided(engineConfiguration->tpsAdcChannel);
}
/*
* Return TPS ADC readings.
* We need ADC value because TunerStudio has a nice TPS configuration wizard, and this wizard
* wants a TPS value.
*/
int getTPS10bitAdc(void) {
int adc = getAdcValue(engineConfiguration->tpsAdcChannel);
return (int) adc / 4; // Only for TunerStudio compatibility. Max TS adc value in 1023
}
/**
* @brief Position on physical primary TPS
*/
static float getPrimatyRawTPS(void) {
// blue, 1st board
/* PA7 - blue TP */
float tpsValue = getTpsValue(getTPS10bitAdc());
return tpsValue;
}
// todo: static float getSecondaryRawTPS
/*
* In case of dual TPS this function would return logical TPS position
*
* @return Current TPS position. 0 means idle and 100 means Wide Open Throttle
*/
float getTPS(void) {
// todo: if (config->isDualTps)
// todo: blah blah
// todo: if two TPS do not match - show OBD code via malfunction_central.c
return getPrimatyRawTPS();
}
int convertVoltageTo10bitADC(float voltage) {
// divided by 2 because of voltage divider, then converted into 10bit ADC value (TunerStudio format)
return (int)(voltage / 2 * 1024 / 3.3);
}
#include "main.h"
#include "boards.h"
#include "tps.h"
#include "engine_configuration.h"
#include "interpolation.h"
#include "adc_inputs.h"
#include "wave_math.h"
extern engine_configuration_s *engineConfiguration;
/**
* We are using one instance for read and another for modification, this is how we get lock-free thread-safety
*
*/
static tps_roc_s states[2];
static volatile int tpsRocIndex = 0;
/**
* this method is lock-free thread-safe if invoked only from one thread
*/
void saveTpsState(time_t now, float curValue) {
int tpsNextIndex = (tpsRocIndex + 1) % 2;
tps_roc_s *cur = &states[tpsRocIndex];
tps_roc_s *next = &states[tpsNextIndex];
next->prevTime = cur->curTime;
next->prevValue = cur->curValue;
next->curTime = now;
next->curValue = curValue;
int diffSysticks = overflowDiff(now, cur->curTime);
float diffSeconds = diffSysticks * 1.0 / CH_FREQUENCY;
next->rateOfChange = (curValue - cur->curValue) / diffSeconds;
// here we update volatile index
tpsRocIndex = tpsNextIndex;
}
/**
* this read-only method is lock-free thread-safe
*/
float getTpsRateOfChange(void) {
return states[tpsRocIndex].rateOfChange;
}
/*
* Return current TPS position based on configured ADC levels, and adc
*
* */
float getTpsValue(int adc) {
if (adc < engineConfiguration->tpsMin)
return 0;
if (adc > engineConfiguration->tpsMax)
return 100;
// todo: double comparison using EPS
if (engineConfiguration->tpsMin == engineConfiguration->tpsMax) {
firmwareError("Invalid TPS configuration: same value");
return 0;
}
return interpolate(engineConfiguration->tpsMin, 0, engineConfiguration->tpsMax, 100, adc);
}
/*
* Return voltage on TPS AND channel
* */
float getTPSVoltage(void) {
return getVoltageDivided(engineConfiguration->tpsAdcChannel);
}
/*
* Return TPS ADC readings.
* We need ADC value because TunerStudio has a nice TPS configuration wizard, and this wizard
* wants a TPS value.
*/
int getTPS10bitAdc(void) {
int adc = getAdcValue(engineConfiguration->tpsAdcChannel);
return (int) adc / 4; // Only for TunerStudio compatibility. Max TS adc value in 1023
}
/**
* @brief Position on physical primary TPS
*/
static float getPrimatyRawTPS(void) {
// blue, 1st board
/* PA7 - blue TP */
float tpsValue = getTpsValue(getTPS10bitAdc());
return tpsValue;
}
// todo: static float getSecondaryRawTPS
/*
* In case of dual TPS this function would return logical TPS position
*
* @return Current TPS position, percent of WOT. 0 means idle and 100 means Wide Open Throttle
*/
float getTPS(void) {
// todo: if (config->isDualTps)
// todo: blah blah
// todo: if two TPS do not match - show OBD code via malfunction_central.c
return getPrimatyRawTPS();
}
int convertVoltageTo10bitADC(float voltage) {
// divided by 2 because of voltage divider, then converted into 10bit ADC value (TunerStudio format)
return (int)(voltage / 2 * 1024 / 3.3);
}

View File

@ -12,11 +12,6 @@
#include "global.h"
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
float getTPS(void);
int convertVoltageTo10bitADC(float voltage);
int getTPS10bitAdc(void);
@ -39,8 +34,4 @@ typedef struct {
void saveTpsState(time_t now, float curValue);
float getTpsRateOfChange(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

View File

@ -1,5 +1,5 @@
/**
* @file settings.c
* @file settings.cpp
* @brief This file is about configuring engine via the human-readable protocol
*
* @date Dec 30, 2012
@ -18,6 +18,7 @@
#include "tps.h"
#include "ec2.h"
#include "map.h"
#include "trigger_decoder.h"
#if EFI_PROD_CODE
#include "rusefi.h"
@ -91,11 +92,32 @@ const char* getConfigurationName(engine_configuration_s *engineConfiguration) {
return "Ford Escort GT";
case CITROEN_TU3JP:
return "Citroen TU3JP";
case ROVER_V8:
return "Rover v8";
default:
return NULL;
}
}
static const char * pinModeToString(pin_output_mode_e mode) {
switch (mode) {
case OM_DEFAULT:
return "default";
case OM_INVERTED:
return "inverted";
case OM_OPENDRAIN:
return "open drain";
case OM_OPENDRAIN_INVERTED:
return "open drain inverted";
default:
return "unexpected";
}
}
static const char * boolToString(bool_t value) {
return value ? "Yes" : "No";
}
/**
* @brief Prints current engine configuration to human-readable console.
*/
@ -147,38 +169,41 @@ void printConfiguration(engine_configuration_s *engineConfiguration, engine_conf
// scheduleMsg(&logger, "crankingRpm: %d", engineConfiguration->crankingSettings.crankingRpm);
scheduleMsg(&logger, "idlePinMode: %d", boardConfiguration->idleValvePinMode);
scheduleMsg(&logger, "malfunctionIndicatorPinMode: %d", boardConfiguration->malfunctionIndicatorPinMode);
scheduleMsg(&logger, "idlePinMode: %s", pinModeToString(boardConfiguration->idleValvePinMode));
scheduleMsg(&logger, "malfunctionIndicatorPinMode: %s", pinModeToString(boardConfiguration->malfunctionIndicatorPinMode));
scheduleMsg(&logger, "analogInputDividerCoefficient: %f", engineConfiguration->analogInputDividerCoefficient);
scheduleMsg(&logger, "needSecondTriggerInput: %d", engineConfiguration->needSecondTriggerInput);
scheduleMsg(&logger, "needSecondTriggerInput: %s", boolToString(engineConfiguration->needSecondTriggerInput));
#if EFI_PROD_CODE
scheduleMsg(&logger, "idleValvePin: %s", hwPortname(boardConfiguration->idleValvePin));
scheduleMsg(&logger, "fuelPumpPin: mode %d @ %s", boardConfiguration->fuelPumpPinMode,
scheduleMsg(&logger, "fuelPumpPin: mode %s @ %s", pinModeToString(boardConfiguration->fuelPumpPinMode),
hwPortname(boardConfiguration->fuelPumpPin));
scheduleMsg(&logger, "injectionPins: mode %d", boardConfiguration->injectionPinMode);
scheduleMsg(&logger, "injectionPins: mode %s", pinModeToString(boardConfiguration->injectionPinMode));
for (int i = 0; i < engineConfiguration->cylindersCount; i++) {
brain_pin_e brainPin = boardConfiguration->injectionPins[i];
scheduleMsg(&logger, "injection %d @ %s", i, hwPortname(brainPin));
}
scheduleMsg(&logger, "ignitionPins: mode %d", boardConfiguration->ignitionPinMode);
scheduleMsg(&logger, "ignitionPins: mode %s", pinModeToString(boardConfiguration->ignitionPinMode));
// todo: calculate coils count based on ignition mode
for (int i = 0; i < 4; i++) {
brain_pin_e brainPin = boardConfiguration->ignitionPins[i];
scheduleMsg(&logger, "ignition %d @ %s", i, hwPortname(brainPin));
}
scheduleMsg(&logger, "primary trigger simulator: %s %d", hwPortname(boardConfiguration->triggerSimulatorPins[0]),
boardConfiguration->triggerSimulatorPinModes[0]);
scheduleMsg(&logger, "secondary trigger simulator: %s %d", hwPortname(boardConfiguration->triggerSimulatorPins[1]),
boardConfiguration->triggerSimulatorPinModes[1]);
scheduleMsg(&logger, "primary trigger simulator: %s %s", hwPortname(boardConfiguration->triggerSimulatorPins[0]),
pinModeToString(boardConfiguration->triggerSimulatorPinModes[0]));
scheduleMsg(&logger, "secondary trigger simulator: %s %s", hwPortname(boardConfiguration->triggerSimulatorPins[1]),
pinModeToString(boardConfiguration->triggerSimulatorPinModes[1]));
scheduleMsg(&logger, "primary trigger input: %s", hwPortname(boardConfiguration->primaryTriggerInputPin));
#endif /* EFI_PROD_CODE */
scheduleMsg(&logger, "isInjectionEnabledFlag %d", engineConfiguration2->isInjectionEnabledFlag);
scheduleMsg(&logger, "isInjectionEnabledFlag %s", boolToString(engineConfiguration2->isInjectionEnabledFlag));
// appendPrintf(&logger, DELIMETER);
// scheduleLogging(&logger);
@ -197,8 +222,9 @@ static void setTimingMode(int value) {
}
void setEngineType(int value) {
engineConfiguration->engineType = (engine_type_e)value;
resetConfigurationExt(&logger, (engine_type_e) value, engineConfiguration, engineConfiguration2, boardConfiguration);
engineConfiguration->engineType = (engine_type_e) value;
resetConfigurationExt(&logger, (engine_type_e) value, engineConfiguration, engineConfiguration2,
boardConfiguration);
#if EFI_INTERNAL_FLASH
writeToFlash();
// scheduleReset();
@ -259,9 +285,9 @@ static void setRpmMultiplier(int value) {
doPrintConfiguration();
}
static uint8_t pinNameBuffer[16];
static char pinNameBuffer[16];
static void printThermistor(char *msg, Thermistor *thermistor) {
static void printThermistor(const char *msg, Thermistor *thermistor) {
int adcChannel = thermistor->channel;
float voltage = getVoltageDivided(adcChannel);
float r = getResistance(thermistor);
@ -278,17 +304,15 @@ static void printThermistor(char *msg, Thermistor *thermistor) {
static void printMAPInfo(void) {
#if EFI_PROD_CODE
scheduleMsg(&logger, "map type=%d raw=%f MAP=%f", engineConfiguration->map.sensor.sensorType, getRawMap(), getMap());
scheduleMsg(&logger, "map type=%d raw=%f MAP=%f", engineConfiguration->map.sensor.sensorType, getRawMap(),
getMap());
if (engineConfiguration->map.sensor.sensorType == MT_CUSTOM) {
scheduleMsg(&logger, "min=%f max=%f", engineConfiguration->map.sensor.Min,
engineConfiguration->map.sensor.Max);
scheduleMsg(&logger, "min=%f max=%f", engineConfiguration->map.sensor.Min, engineConfiguration->map.sensor.Max);
}
scheduleMsg(&logger, "baro type=%d value=%f", engineConfiguration->baroSensor.sensorType, getBaroPressure());
if (engineConfiguration->baroSensor.sensorType == MT_CUSTOM) {
scheduleMsg(&logger, "min=%f max=%f", engineConfiguration->baroSensor.Min,
engineConfiguration->baroSensor.Max);
scheduleMsg(&logger, "min=%f max=%f", engineConfiguration->baroSensor.Min, engineConfiguration->baroSensor.Max);
}
#endif
}
@ -388,6 +412,13 @@ static void setIgnitionMode(int value) {
doPrintConfiguration();
}
static void setTotalToothCount(int value) {
engineConfiguration->triggerConfig.totalToothCount = value;
initializeTriggerShape(&logger, engineConfiguration, engineConfiguration2);
incrementGlobalConfigurationVersion();
doPrintConfiguration();
}
static void setCrankingChargeAngle(float value) {
engineConfiguration->crankingChargeAngle = value;
incrementGlobalConfigurationVersion();
@ -500,5 +531,6 @@ void initSettings(void) {
addConsoleAction("enable_injection", enableInjection);
addConsoleAction("disable_injection", disableInjection);
addConsoleActionI("set_total_tooth_count", setTotalToothCount);
}

View File

@ -17,9 +17,6 @@ extern "C"
void initSettings(void);
void pokeControl(void);
void setEngineType(int value);
int getInjectionPeriod(void);
int getInjectionOffset(void);
int getInjectionDivider(void);
#ifdef __cplusplus
}

Some files were not shown because too many files have changed in this diff Show More