Sensors.cpp: MISRA fixes & reduce conditional compilation blocks (#1157)
* Bug fix - consistent #ifdef (ANALOG_ISR/ANALOG_ISR_MAP) Also replace multiple #ifdefs with inline function. * MISRA fixes for sensor.cpp * Conditional compile to allow MAP sensor read pin even when using analog ISR Useful for development testing * Remove unused global variables statuses::batADC fpPrimed - duplicate of statuses::fpPrimed injPrimed - duplicate of statuses::injPrimed * Replace duplicate filter macros with one inline function: LOW_PASS_FILTER (which is MISRA compliant). * Remove mapErrorCount - it's unused (only ever written to, never read) * Deduplicate MAP reading code * Encapsulate MAP variables * Add isEngineRunning() to capture duplicate code * Make readBaro() independent of instanteneousMAPReading() Removes a conditional and reduces module surafce area * Use structs to capture the MAP algorithm state. Also apply ATOMIC_BLOCK to prevent tearing of ISR modified variables. * Force loop() inline Reduces stack usage. * Use 16-bit comparisons * Remove validateMAP() - since we validate every sensor reading, it wasn't doing anything. * Unit test engineIsRunning * Apply SET_UNITY_FILENAME to K6A unit tests * Unit test LOW_PASS_FILTER * Unit test fastMap10Bit * Reduce scope of MAP ADC variables - only used in sensors.cpp * MAP: read the sensors in one place in the code & inject the values into the sampling algorithms * MAP: encapsulate reset of state structures * MAP: replace magic numbers wirth an enum * MAP algorithms return a flag indicting whether they recomputed MAP/EMAP * MAP sampling algorithms: push MAP value calculation up the call stack. * Remove errors.* - it's never called an uses up RAM * Unit Test: inject all MAP sampling algorithm dependencies * Unit test MAP sampling algorithms * Unit test validateFilterMapSensorReading * Prevent torn reads during comparisons * Don't skip readings on cycle/event boundaries
This commit is contained in:
parent
4c29faa739
commit
a4bbce63c3
|
@ -28,6 +28,7 @@ jobs:
|
|||
- build.extra_flags=-DPLATFORMIO -DUSE_LIBDIVIDE -O3 -ffast-math -fshort-enums -funroll-loops -Wall -Wextra -std=c99
|
||||
lib_deps: |
|
||||
- name: Time
|
||||
- name: SimplyAtomic
|
||||
- fqbn: teensy:avr:teensy35
|
||||
artifact-name-suffix: teensy-avr-teensy35
|
||||
platform: |
|
||||
|
@ -38,6 +39,7 @@ jobs:
|
|||
- build..extra_flags="-Wall"
|
||||
lib_deps: |
|
||||
- name: SDfat
|
||||
- name: SimplyAtomic
|
||||
- fqbn: teensy:avr:teensy41
|
||||
artifact-name-suffix: teensy-avr-teensy41
|
||||
platform: |
|
||||
|
@ -48,6 +50,7 @@ jobs:
|
|||
- build..extra_flags="-Wall"
|
||||
lib_deps: |
|
||||
- name: SDfat
|
||||
- name: SimplyAtomic
|
||||
- fqbn: STMicroelectronics:stm32:GenF4
|
||||
artifact-name-suffix: stm32-avr-stm32f4
|
||||
platform: |
|
||||
|
@ -61,6 +64,7 @@ jobs:
|
|||
- name: "STM32duino RTC"
|
||||
version: 1.2.0
|
||||
- name: SdFat
|
||||
- name: SimplyAtomic
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
|
|
@ -16,7 +16,7 @@ build_unflags = -Os
|
|||
build_flags = -DUSE_LIBDIVIDE -O3 -ffast-math -fshort-enums -funroll-loops -Wall -Wextra -std=c99
|
||||
; Note that fp64lib is only used by unit tests. It isn't referenced by the firmware & will be
|
||||
; ignored.
|
||||
lib_deps = EEPROM, Time, fp64lib
|
||||
lib_deps = EEPROM, Time, fp64lib, simplyatomic
|
||||
;test_build_project_src = true
|
||||
test_build_src = yes
|
||||
debug_tool = simavr
|
||||
|
@ -41,7 +41,7 @@ board=ATmega2561
|
|||
platform=https://github.com/platformio/platform-teensy.git
|
||||
board=teensy35
|
||||
framework=arduino
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time, SimplyAtomic
|
||||
test_build_src = yes
|
||||
test_ignore = test_table3d_native
|
||||
extra_scripts = post:post_extra_script.py
|
||||
|
@ -51,7 +51,7 @@ extra_scripts = post:post_extra_script.py
|
|||
platform=https://github.com/platformio/platform-teensy.git
|
||||
board=teensy36
|
||||
framework=arduino
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time, SimplyAtomic
|
||||
test_build_src = yes
|
||||
test_ignore = test_table3d_native
|
||||
|
||||
|
@ -60,7 +60,7 @@ test_ignore = test_table3d_native
|
|||
platform=https://github.com/platformio/platform-teensy.git
|
||||
board=teensy41
|
||||
framework=arduino
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time
|
||||
lib_deps = EEPROM, FlexCAN_T4, Time, SimplyAtomic
|
||||
test_build_src = yes
|
||||
test_ignore = test_table3d_native
|
||||
|
||||
|
@ -72,7 +72,7 @@ framework = arduino
|
|||
;board = genericSTM32F407VET6
|
||||
board = black_f407ve
|
||||
; RTC library fixed to 1.2.0, because in newer than that the RTC fails to keep up time. At least up to 1.3.7 version
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0, greiman/SdFat
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0, greiman/SdFat, SimplyAtomic
|
||||
board_build.core = stm32
|
||||
build_flags = -DUSE_LIBDIVIDE -std=gnu++11 -UBOARD_MAX_IO_PINS -DENABLE_HWSERIAL2 -DENABLE_HWSERIAL3 -DUSBCON -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC -DHAL_CAN_MODULE_ENABLED -DSERIAL_TX_BUFFER_SIZE=128 -DSERIAL_RX_BUFFER_SIZE=128
|
||||
upload_protocol = dfu
|
||||
|
@ -84,7 +84,7 @@ monitor_speed = 115200
|
|||
platform = ststm32
|
||||
framework = arduino
|
||||
board = blackpill_f401cc
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0, SimplyAtomic
|
||||
board_build.core = stm32
|
||||
build_flags = -DUSE_LIBDIVIDE -std=gnu++11 -UBOARD_MAX_IO_PINS -DUSBCON -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC -DHAL_DAC_MODULE_DISABLED -DHAL_ETH_MODULE_DISABLED -DHAL_SD_MODULE_DISABLED -DHAL_QSPI_MODULE_DISABLED
|
||||
upload_protocol = dfu
|
||||
|
@ -96,7 +96,7 @@ monitor_speed = 115200
|
|||
platform = ststm32
|
||||
framework = arduino
|
||||
board = blackpill_f411ce
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0, SimplyAtomic
|
||||
board_build.core = stm32
|
||||
build_flags = -DUSE_LIBDIVIDE -O3 -std=gnu++11 -UBOARD_MAX_IO_PINS
|
||||
upload_protocol = dfu
|
||||
|
@ -108,7 +108,7 @@ monitor_speed = 115200
|
|||
platform = ststm32
|
||||
framework = arduino
|
||||
board = blackpill_f411ce
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0
|
||||
lib_deps = stm32duino/STM32duino RTC @ 1.2.0, SimplyAtomic
|
||||
board_build.core = stm32
|
||||
build_flags = -DUSE_LIBDIVIDE -O3 -std=gnu++11 -UBOARD_MAX_IO_PINS -DUSBCON -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC
|
||||
upload_protocol = dfu
|
||||
|
@ -120,7 +120,7 @@ platform = ststm32
|
|||
framework = arduino
|
||||
; framework-arduinoststm32
|
||||
board = bluepill_f103c8_128k
|
||||
lib_deps = EEPROM, stm32duino/STM32duino RTC @ 1.2.0
|
||||
lib_deps = EEPROM, stm32duino/STM32duino RTC @ 1.2.0, SimplyAtomic
|
||||
;build_flags = -DUSE_LIBDIVIDE -fpermissive -std=gnu++11 -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-Map,output.map
|
||||
build_flags = -DUSE_LIBDIVIDE -fpermissive -std=gnu++11 -Os -DCORE_STM32_OFFICIAL -UBOARD_MAX_IO_PINS
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
#include BOARD_H //Note that this is not a real file, it is defined in globals.h.
|
||||
|
||||
#if defined(CORE_AVR)
|
||||
#include <util/atomic.h>
|
||||
#endif
|
||||
#include <SimplyAtomic.h>
|
||||
|
||||
void initialiseAuxPWM(void);
|
||||
void boostControl(void);
|
||||
|
@ -44,28 +42,22 @@ void wmiControl(void);
|
|||
#define FUEL_PUMP_ON() (digitalWrite(pinFuelPump, HIGH))
|
||||
#define FUEL_PUMP_OFF() (digitalWrite(pinFuelPump, LOW))
|
||||
|
||||
#define AIRCON_ON() { (((configPage15.airConCompPol==1)) ? AIRCON_PIN_LOW() : AIRCON_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_OFF() { (((configPage15.airConCompPol==1)) ? AIRCON_PIN_HIGH() : AIRCON_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_FAN_ON() { (((configPage15.airConFanPol==1)) ? AIRCON_FAN_PIN_LOW() : AIRCON_FAN_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
#define AIRCON_FAN_OFF() { (((configPage15.airConFanPol==1)) ? AIRCON_FAN_PIN_HIGH() : AIRCON_FAN_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
|
||||
#define FAN_ON() { ((configPage6.fanInv) ? FAN_PIN_LOW() : FAN_PIN_HIGH()); }
|
||||
#define FAN_OFF() { ((configPage6.fanInv) ? FAN_PIN_HIGH() : FAN_PIN_LOW()); }
|
||||
#else
|
||||
#define BOOST_PIN_LOW() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *boost_pin_port &= ~(boost_pin_mask); }
|
||||
#define BOOST_PIN_HIGH() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *boost_pin_port |= (boost_pin_mask); }
|
||||
#define VVT1_PIN_LOW() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *vvt1_pin_port &= ~(vvt1_pin_mask); }
|
||||
#define VVT1_PIN_HIGH() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *vvt1_pin_port |= (vvt1_pin_mask); }
|
||||
#define VVT2_PIN_LOW() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *vvt2_pin_port &= ~(vvt2_pin_mask); }
|
||||
#define VVT2_PIN_HIGH() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *vvt2_pin_port |= (vvt2_pin_mask); }
|
||||
#define N2O_STAGE1_PIN_LOW() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *n2o_stage1_pin_port &= ~(n2o_stage1_pin_mask); }
|
||||
#define N2O_STAGE1_PIN_HIGH() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *n2o_stage1_pin_port |= (n2o_stage1_pin_mask); }
|
||||
#define N2O_STAGE2_PIN_LOW() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *n2o_stage2_pin_port &= ~(n2o_stage2_pin_mask); }
|
||||
#define N2O_STAGE2_PIN_HIGH() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *n2o_stage2_pin_port |= (n2o_stage2_pin_mask); }
|
||||
#define FUEL_PUMP_ON() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *pump_pin_port |= (pump_pin_mask); }
|
||||
#define FUEL_PUMP_OFF() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *pump_pin_port &= ~(pump_pin_mask); }
|
||||
|
||||
//Note the below macros cannot use ATOMIC_BLOCK(ATOMIC_RESTORESTATE) as they are called from within ternary operators. The ATOMIC_BLOCK wrapped is instead placed around the ternary call below
|
||||
#define BOOST_PIN_LOW() ATOMIC() { *boost_pin_port &= ~(boost_pin_mask); }
|
||||
#define BOOST_PIN_HIGH() ATOMIC() { *boost_pin_port |= (boost_pin_mask); }
|
||||
#define VVT1_PIN_LOW() ATOMIC() { *vvt1_pin_port &= ~(vvt1_pin_mask); }
|
||||
#define VVT1_PIN_HIGH() ATOMIC() { *vvt1_pin_port |= (vvt1_pin_mask); }
|
||||
#define VVT2_PIN_LOW() ATOMIC() { *vvt2_pin_port &= ~(vvt2_pin_mask); }
|
||||
#define VVT2_PIN_HIGH() ATOMIC() { *vvt2_pin_port |= (vvt2_pin_mask); }
|
||||
#define N2O_STAGE1_PIN_LOW() ATOMIC() { *n2o_stage1_pin_port &= ~(n2o_stage1_pin_mask); }
|
||||
#define N2O_STAGE1_PIN_HIGH() ATOMIC() { *n2o_stage1_pin_port |= (n2o_stage1_pin_mask); }
|
||||
#define N2O_STAGE2_PIN_LOW() ATOMIC() { *n2o_stage2_pin_port &= ~(n2o_stage2_pin_mask); }
|
||||
#define N2O_STAGE2_PIN_HIGH() ATOMIC() { *n2o_stage2_pin_port |= (n2o_stage2_pin_mask); }
|
||||
#define FUEL_PUMP_ON() ATOMIC() { *pump_pin_port |= (pump_pin_mask); }
|
||||
#define FUEL_PUMP_OFF() ATOMIC() { *pump_pin_port &= ~(pump_pin_mask); }
|
||||
|
||||
//Note the below macros cannot use ATOMIC() as they are called from within ternary operators. The ATOMIC is instead placed around the ternary call below
|
||||
#define FAN_PIN_LOW() *fan_pin_port &= ~(fan_pin_mask)
|
||||
#define FAN_PIN_HIGH() *fan_pin_port |= (fan_pin_mask)
|
||||
#define AIRCON_PIN_LOW() *aircon_comp_pin_port &= ~(aircon_comp_pin_mask)
|
||||
|
@ -73,17 +65,17 @@ void wmiControl(void);
|
|||
#define AIRCON_FAN_PIN_LOW() *aircon_fan_pin_port &= ~(aircon_fan_pin_mask)
|
||||
#define AIRCON_FAN_PIN_HIGH() *aircon_fan_pin_port |= (aircon_fan_pin_mask)
|
||||
|
||||
#define AIRCON_ON() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((((configPage15.airConCompPol)==1)) ? AIRCON_PIN_LOW() : AIRCON_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_OFF() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((((configPage15.airConCompPol)==1)) ? AIRCON_PIN_HIGH() : AIRCON_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_FAN_ON() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((((configPage15.airConFanPol)==1)) ? AIRCON_FAN_PIN_LOW() : AIRCON_FAN_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
#define AIRCON_FAN_OFF() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((((configPage15.airConFanPol)==1)) ? AIRCON_FAN_PIN_HIGH() : AIRCON_FAN_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
|
||||
#define FAN_ON() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((configPage6.fanInv) ? FAN_PIN_LOW() : FAN_PIN_HIGH()); }
|
||||
#define FAN_OFF() ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { ((configPage6.fanInv) ? FAN_PIN_HIGH() : FAN_PIN_LOW()); }
|
||||
#endif
|
||||
|
||||
#define READ_N2O_ARM_PIN() ((*n2o_arming_pin_port & n2o_arming_pin_mask) ? true : false)
|
||||
#define AIRCON_ON() ATOMIC() { ((((configPage15.airConCompPol)==1)) ? AIRCON_PIN_LOW() : AIRCON_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_OFF() ATOMIC() { ((((configPage15.airConCompPol)==1)) ? AIRCON_PIN_HIGH() : AIRCON_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); }
|
||||
#define AIRCON_FAN_ON() ATOMIC() { ((((configPage15.airConFanPol)==1)) ? AIRCON_FAN_PIN_LOW() : AIRCON_FAN_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
#define AIRCON_FAN_OFF() ATOMIC() { ((((configPage15.airConFanPol)==1)) ? AIRCON_FAN_PIN_HIGH() : AIRCON_FAN_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_FAN); }
|
||||
|
||||
#define FAN_ON() ATOMIC() { ((configPage6.fanInv) ? FAN_PIN_LOW() : FAN_PIN_HIGH()); }
|
||||
#define FAN_OFF() ATOMIC() { ((configPage6.fanInv) ? FAN_PIN_HIGH() : FAN_PIN_LOW()); }
|
||||
|
||||
#define READ_N2O_ARM_PIN() ((*n2o_arming_pin_port & n2o_arming_pin_mask) ? true : false)
|
||||
|
||||
#define VVT1_PIN_ON() VVT1_PIN_HIGH();
|
||||
#define VVT1_PIN_OFF() VVT1_PIN_LOW();
|
||||
|
|
|
@ -14,7 +14,6 @@ A full copy of the license may be found in the projects root directory
|
|||
#include "utilities.h"
|
||||
#include "decoders.h"
|
||||
#include "TS_CommandButtonHandler.h"
|
||||
#include "errors.h"
|
||||
#include "pages.h"
|
||||
#include "page_crc.h"
|
||||
#include "logger.h"
|
||||
|
|
|
@ -15,7 +15,6 @@ A full copy of the license may be found in the projects root directory
|
|||
#include "utilities.h"
|
||||
#include "decoders.h"
|
||||
#include "TS_CommandButtonHandler.h"
|
||||
#include "errors.h"
|
||||
#include "pages.h"
|
||||
#include "page_crc.h"
|
||||
#include "logger.h"
|
||||
|
|
|
@ -20,7 +20,6 @@ sendcancommand is called when a command is to be sent either to serial3
|
|||
#include "comms_secondary.h"
|
||||
#include "comms_CAN.h"
|
||||
#include "maths.h"
|
||||
#include "errors.h"
|
||||
#include "utilities.h"
|
||||
#include "comms_legacy.h"
|
||||
#include "logger.h"
|
||||
|
|
|
@ -268,8 +268,8 @@ uint16_t correctionAccel(void)
|
|||
if(configPage2.aeMode == AE_MODE_MAP)
|
||||
{
|
||||
//Get the MAP rate change
|
||||
MAP_change = (currentStatus.MAP - MAPlast);
|
||||
currentStatus.mapDOT = (MICROS_PER_SEC / (MAP_time - MAPlast_time)) * MAP_change; //This is the % per second that the MAP has moved
|
||||
MAP_change = getMAPDelta();
|
||||
currentStatus.mapDOT = (MICROS_PER_SEC / getMAPDeltaTime()) * MAP_change; //This is the % per second that the MAP has moved
|
||||
//currentStatus.mapDOT = 15 * MAP_change; //This is the kpa per second that the MAP has moved
|
||||
}
|
||||
else if(configPage2.aeMode == AE_MODE_TPS)
|
||||
|
|
|
@ -35,6 +35,7 @@ A full copy of the license may be found in the projects root directory
|
|||
* - To compare Speeduino Doxyfile to default config, do: `doxygen -g Doxyfile.default ; diff Doxyfile.default Doxyfile`
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <SimplyAtomic.h>
|
||||
#include "globals.h"
|
||||
#include "decoders.h"
|
||||
#include "scheduledIO.h"
|
||||
|
@ -42,6 +43,7 @@ A full copy of the license may be found in the projects root directory
|
|||
#include "crankMaths.h"
|
||||
#include "timers.h"
|
||||
#include "schedule_calcs.h"
|
||||
#include "unit_testing.h"
|
||||
|
||||
void nullTriggerHandler (void){return;} //initialisation function for triggerhandlers, does exactly nothing
|
||||
uint16_t nullGetRPM(void){return 0;} //initialisation function for getRpm, returns safe value of 0
|
||||
|
@ -66,12 +68,12 @@ volatile unsigned long curGap3;
|
|||
volatile unsigned long lastGap;
|
||||
volatile unsigned long targetGap;
|
||||
|
||||
unsigned long MAX_STALL_TIME = MICROS_PER_SEC/2U; //The maximum time (in uS) that the system will continue to function before the engine is considered stalled/stopped. This is unique to each decoder, depending on the number of teeth etc. 500000 (half a second) is used as the default value, most decoders will be much less.
|
||||
TESTABLE_STATIC unsigned long MAX_STALL_TIME = MICROS_PER_SEC/2U; //The maximum time (in uS) that the system will continue to function before the engine is considered stalled/stopped. This is unique to each decoder, depending on the number of teeth etc. 500000 (half a second) is used as the default value, most decoders will be much less.
|
||||
volatile uint16_t toothCurrentCount = 0; //The current number of teeth (Once sync has been achieved, this can never actually be 0
|
||||
volatile byte toothSystemCount = 0; //Used for decoders such as Audi 135 where not every tooth is used for calculating crank angle. This variable stores the actual number of teeth, not the number being used to calculate crank angle
|
||||
static volatile byte toothSystemCount = 0; //Used for decoders such as Audi 135 where not every tooth is used for calculating crank angle. This variable stores the actual number of teeth, not the number being used to calculate crank angle
|
||||
volatile unsigned long toothSystemLastToothTime = 0; //As below, but used for decoders where not every tooth count is used for calculation
|
||||
volatile unsigned long toothLastToothTime = 0; //The time (micros()) that the last tooth was registered
|
||||
volatile unsigned long toothLastSecToothTime = 0; //The time (micros()) that the last tooth was registered on the secondary input
|
||||
TESTABLE_STATIC volatile unsigned long toothLastToothTime = 0; //The time (micros()) that the last tooth was registered
|
||||
static volatile unsigned long toothLastSecToothTime = 0; //The time (micros()) that the last tooth was registered on the secondary input
|
||||
volatile unsigned long toothLastThirdToothTime = 0; //The time (micros()) that the last tooth was registered on the second cam input
|
||||
volatile unsigned long toothLastMinusOneToothTime = 0; //The time (micros()) that the tooth before the last tooth was registered
|
||||
volatile unsigned long toothLastMinusOneSecToothTime = 0; //The time (micros()) that the tooth before the last tooth was registered on secondary input
|
||||
|
@ -84,7 +86,7 @@ volatile unsigned long toothOneMinusOneTime = 0; //The 2nd to last time (micros(
|
|||
volatile bool revolutionOne = 0; // For sequential operation, this tracks whether the current revolution is 1 or 2 (not 1)
|
||||
volatile bool revolutionLastOne = 0; // used to identify in the rover pattern which has a non unique primary trigger something unique - has the secondary tooth changed.
|
||||
|
||||
volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
||||
static volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
||||
volatile unsigned int secondaryLastToothCount = 0; // used to identify in the rover pattern which has a non unique primary trigger something unique - has the secondary tooth changed.
|
||||
volatile unsigned long secondaryLastToothTime = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
||||
volatile unsigned long secondaryLastToothTime1 = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
||||
|
@ -335,6 +337,23 @@ static inline bool IsCranking(const statuses &status) {
|
|||
return (status.RPM < status.crankRPM) && (status.startRevolutions == 0U);
|
||||
}
|
||||
|
||||
bool engineIsRunning(uint32_t curTime) {
|
||||
// Check how long ago the last tooth was seen compared to now.
|
||||
// If it was more than MAX_STALL_TIME then the engine is probably stopped.
|
||||
// toothLastToothTime can be greater than curTime if a pulse occurs between getting the latest time and doing the comparison
|
||||
ATOMIC() {
|
||||
return (toothLastToothTime > curTime) || ((curTime - toothLastToothTime) < MAX_STALL_TIME);
|
||||
}
|
||||
return false; // Just here to avoid compiler warning.
|
||||
}
|
||||
|
||||
void resetDecoder(void) {
|
||||
toothLastSecToothTime = 0;
|
||||
toothLastToothTime = 0;
|
||||
toothSystemCount = 0;
|
||||
secondaryToothCount = 0;
|
||||
}
|
||||
|
||||
#if defined(UNIT_TEST)
|
||||
bool SetRevolutionTime(uint32_t revTime)
|
||||
#else
|
||||
|
@ -739,7 +758,7 @@ static inline void triggerRecordVVT1Angle (void)
|
|||
curAngle -= configPage4.triggerAngle; //Value at TDC
|
||||
if( configPage6.vvtMode == VVT_MODE_CLOSED_LOOP ) { curAngle -= configPage10.vvtCL0DutyAng; }
|
||||
|
||||
currentStatus.vvt1Angle = ANGLE_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt1Angle);
|
||||
currentStatus.vvt1Angle = LOW_PASS_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt1Angle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -770,7 +789,7 @@ void triggerThird_missingTooth(void)
|
|||
curAngle -= configPage4.triggerAngle; //Value at TDC
|
||||
if( configPage6.vvtMode == VVT_MODE_CLOSED_LOOP ) { curAngle -= configPage4.vvt2CL0DutyAng; }
|
||||
//currentStatus.vvt2Angle = int8_t (curAngle); //vvt1Angle is only int8, but +/-127 degrees is enough for VVT control
|
||||
currentStatus.vvt2Angle = ANGLE_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt2Angle);
|
||||
currentStatus.vvt2Angle = LOW_PASS_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt2Angle);
|
||||
|
||||
toothLastThirdToothTime = curTime3;
|
||||
} //Trigger filter
|
||||
|
@ -2655,7 +2674,7 @@ int getCamAngle_Miata9905(void)
|
|||
//lastVVTtime is the time between tooth #1 (10* BTDC) and the single cam tooth.
|
||||
//All cam angles in in BTDC, so the actual advance angle is 370 - timeToAngleDegPerMicroSec(lastVVTtime) - <the angle of the cam at 0 advance>
|
||||
curAngle = 370 - timeToAngleDegPerMicroSec(lastVVTtime) - configPage10.vvtCL0DutyAng;
|
||||
currentStatus.vvt1Angle = ANGLE_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt1Angle);
|
||||
currentStatus.vvt1Angle = LOW_PASS_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, currentStatus.vvt1Angle);
|
||||
|
||||
return currentStatus.vvt1Angle;
|
||||
}
|
||||
|
@ -4400,7 +4419,7 @@ void triggerSec_FordST170(void)
|
|||
while(curAngle > 360) { curAngle -= 360; }
|
||||
if( configPage6.vvtMode == VVT_MODE_CLOSED_LOOP )
|
||||
{
|
||||
curAngle = ANGLE_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, curAngle);
|
||||
curAngle = LOW_PASS_FILTER( (curAngle << 1), configPage4.ANGLEFILTER_VVT, curAngle);
|
||||
currentStatus.vvt1Angle = 360 - curAngle - configPage10.vvtCL0DutyAng;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,17 @@
|
|||
//220 bytes free
|
||||
extern volatile uint8_t decoderState;
|
||||
|
||||
/**
|
||||
* @brief Is the engine running?
|
||||
*
|
||||
* This is based on whether or not the decoder has detected a tooth recently
|
||||
*
|
||||
* @param curTime The time in µS to use for the liveness check. Typically the result of a recent call to micros()
|
||||
* @return true If the engine is turning
|
||||
* @return false If the engine is not turning
|
||||
*/
|
||||
bool engineIsRunning(uint32_t curTime);
|
||||
|
||||
/*
|
||||
extern volatile bool validTrigger; //Is set true when the last trigger (Primary or secondary) was valid (ie passed filters)
|
||||
extern volatile bool triggerToothAngleIsCorrect; //Whether or not the triggerToothAngle variable is currently accurate. Some patterns have times when the triggerToothAngle variable cannot be accurately set.
|
||||
|
@ -67,9 +78,6 @@ extern bool decoderHasSecondary; //Whether or not the pattern uses a secondary i
|
|||
extern bool decoderHasFixedCrankingTiming;
|
||||
*/
|
||||
|
||||
//This isn't to to filter out wrong pulses on triggers, but just to smooth out the cam angle reading for better closed loop VVT control.
|
||||
#define ANGLE_FILTER(input, alpha, prior) (((long)(input) * (256 - (alpha)) + ((long)(prior) * (alpha)))) >> 8
|
||||
|
||||
void loggerPrimaryISR(void);
|
||||
void loggerSecondaryISR(void);
|
||||
void loggerTertiaryISR(void);
|
||||
|
@ -262,7 +270,12 @@ uint16_t getRPM_SuzukiK6A(void);
|
|||
int getCrankAngle_SuzukiK6A(void);
|
||||
void triggerSetEndTeeth_SuzukiK6A(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is called when the engine is stopped, or when the engine is started. It resets the decoder state and the tooth tracking variables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void resetDecoder(void);
|
||||
|
||||
extern void (*triggerHandler)(void); //Pointer for the trigger function (Gets pointed to the relevant decoder)
|
||||
extern void (*triggerSecondaryHandler)(void); //Pointer for the secondary trigger function (Gets pointed to the relevant decoder)
|
||||
|
@ -279,12 +292,8 @@ extern volatile unsigned long curGap2;
|
|||
extern volatile unsigned long lastGap;
|
||||
extern volatile unsigned long targetGap;
|
||||
|
||||
extern unsigned long MAX_STALL_TIME; //The maximum time (in uS) that the system will continue to function before the engine is considered stalled/stopped. This is unique to each decoder, depending on the number of teeth etc. 500000 (half a second) is used as the default value, most decoders will be much less.
|
||||
extern volatile uint16_t toothCurrentCount; //The current number of teeth (Once sync has been achieved, this can never actually be 0
|
||||
extern volatile byte toothSystemCount; //Used for decoders such as Audi 135 where not every tooth is used for calculating crank angle. This variable stores the actual number of teeth, not the number being used to calculate crank angle
|
||||
extern volatile unsigned long toothSystemLastToothTime; //As below, but used for decoders where not every tooth count is used for calculation
|
||||
extern volatile unsigned long toothLastToothTime; //The time (micros()) that the last tooth was registered
|
||||
extern volatile unsigned long toothLastSecToothTime; //The time (micros()) that the last tooth was registered on the secondary input
|
||||
extern volatile unsigned long toothLastThirdToothTime; //The time (micros()) that the last tooth was registered on the second cam input
|
||||
extern volatile unsigned long toothLastMinusOneToothTime; //The time (micros()) that the tooth before the last tooth was registered
|
||||
extern volatile unsigned long toothLastMinusOneSecToothTime; //The time (micros()) that the tooth before the last tooth was registered on secondary input
|
||||
|
@ -294,7 +303,6 @@ extern volatile unsigned long toothOneTime; //The time (micros()) that tooth 1 l
|
|||
extern volatile unsigned long toothOneMinusOneTime; //The 2nd to last time (micros()) that tooth 1 last triggered
|
||||
extern volatile bool revolutionOne; // For sequential operation, this tracks whether the current revolution is 1 or 2 (not 1)
|
||||
|
||||
extern volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
||||
extern volatile unsigned long secondaryLastToothTime; //The time (micros()) that the last tooth was registered (Cam input)
|
||||
extern volatile unsigned long secondaryLastToothTime1; //The time (micros()) that the last tooth was registered (Cam input)
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
Speeduino - Simple engine management for the Arduino Mega 2560 platform
|
||||
Copyright (C) Josh Stewart
|
||||
A full copy of the license may be found in the projects root directory
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sets the next available error
|
||||
* Returns the error number or 0 if there is no more room for errors
|
||||
*/
|
||||
#include "globals.h"
|
||||
#include "errors.h"
|
||||
|
||||
byte errorCount = 0;
|
||||
byte errorCodes[4];
|
||||
|
||||
byte setError(byte errorID)
|
||||
{
|
||||
if(errorCount < MAX_ERRORS)
|
||||
{
|
||||
errorCodes[errorCount] = errorID;
|
||||
errorCount++;
|
||||
if(errorCount == 1) { BIT_SET(currentStatus.status2, BIT_STATUS2_ERROR); } //Enable the error indicator
|
||||
}
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
void clearError(byte errorID)
|
||||
{
|
||||
byte clearedError = 255;
|
||||
|
||||
if (errorID == errorCodes[0]) { clearedError = 0; }
|
||||
else if(errorID == errorCodes[1]) { clearedError = 1; }
|
||||
else if(errorID == errorCodes[2]) { clearedError = 2; }
|
||||
else if(errorID == errorCodes[3]) { clearedError = 3; }
|
||||
|
||||
if(clearedError < MAX_ERRORS)
|
||||
{
|
||||
errorCodes[clearedError] = ERR_NONE;
|
||||
//Clear the required error and move any from above it 'down' in the error array
|
||||
for (byte x=clearedError; x < (errorCount-1); x++)
|
||||
{
|
||||
errorCodes[x] = errorCodes[x+1];
|
||||
errorCodes[x+1] = ERR_NONE;
|
||||
}
|
||||
|
||||
errorCount--;
|
||||
if(errorCount == 0) { BIT_CLEAR(currentStatus.status2, BIT_STATUS2_ERROR); } //Enable the error indicator
|
||||
}
|
||||
}
|
||||
|
||||
byte getNextError(void)
|
||||
{
|
||||
packedError currentError;
|
||||
byte currentErrorNum = 0;
|
||||
|
||||
if(errorCount > 0)
|
||||
{
|
||||
//We alternate through the errors once per second
|
||||
currentErrorNum = currentStatus.secl % errorCount; //Which error number will be returned. This changes once per second.
|
||||
|
||||
currentError.errorNum = currentErrorNum;
|
||||
currentError.errorID = errorCodes[currentErrorNum];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentError.errorNum = 0;
|
||||
currentError.errorID = 0;
|
||||
}
|
||||
|
||||
|
||||
return *(byte*)¤tError; //Ugly, but this forces the cast of the currentError struct to a byte.
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#ifndef ERRORS_H
|
||||
#define ERRORS_H
|
||||
|
||||
/*
|
||||
* Up to 64 different error codes may be defined (6 bits)
|
||||
*/
|
||||
#define ERR_NONE 0 //No error
|
||||
#define ERR_UNKNOWN 1 //Unknown error
|
||||
#define ERR_IAT_SHORT 2 //Inlet sensor shorted
|
||||
#define ERR_IAT_GND 3 //Inlet sensor grounded
|
||||
#define ERR_CLT_SHORT 4 //Coolant sensor shorted
|
||||
#define ERR_CLT_GND 5 //Coolant Sensor grounded
|
||||
#define ERR_O2_SHORT 6 //O2 sensor shorted
|
||||
#define ERR_O2_GND 7 //O2 sensor grounded
|
||||
#define ERR_TPS_SHORT 8 //TPS shorted (Is potentially valid)
|
||||
#define ERR_TPS_GND 9 //TPS grounded (Is potentially valid)
|
||||
#define ERR_BAT_HIGH 10 //Battery voltage is too high
|
||||
#define ERR_BAT_LOW 11 //Battery voltage is too low
|
||||
#define ERR_MAP_HIGH 12 //MAP output is too high
|
||||
#define ERR_MAP_LOW 13 //MAP output is too low
|
||||
|
||||
#define ERR_DEFAULT_IAT_SHORT 80 //Note that the default is 40C. 80 is used due to the -40 offset
|
||||
#define ERR_DEFAULT_IAT_GND 80 //Note that the default is 40C. 80 is used due to the -40 offset
|
||||
#define ERR_DEFAULT_CKT_SHORT 80 //Note that the default is 40C. 80 is used due to the -40 offset
|
||||
#define ERR_DEFAULT_CLT_GND 80 //Note that the default is 40C. 80 is used due to the -40 offset
|
||||
#define ERR_DEFAULT_O2_SHORT 147 //14.7
|
||||
#define ERR_DEFAULT_O2_GND 147 //14.7
|
||||
#define ERR_DEFAULT_TPS_SHORT 50 //50%
|
||||
#define ERR_DEFAULT_TPS_GND 50 //50%
|
||||
#define ERR_DEFAULT_BAT_HIGH 130 //13v
|
||||
#define ERR_DEFAULT_BAT_LOW 130 //13v
|
||||
#define ERR_DEFAULT_MAP_HIGH 240
|
||||
#define ERR_DEFAULT_MAP_LOW 80
|
||||
|
||||
|
||||
#define MAX_ERRORS 4 //The number of errors the system can hold simultaneously. Should be a power of 2
|
||||
|
||||
/*
|
||||
* This struct is a single byte in length and is sent to TS
|
||||
* The first 2 bits are used to define the current error (0-3)
|
||||
* The remaining 6 bits are used to give the error number
|
||||
*/
|
||||
struct packedError
|
||||
{
|
||||
byte errorNum : 2;
|
||||
byte errorID : 6;
|
||||
};
|
||||
|
||||
byte getNextError(void);
|
||||
byte setError(byte errorID);
|
||||
void clearError(byte errorID);
|
||||
|
||||
extern byte errorCount;
|
||||
|
||||
#endif
|
|
@ -107,7 +107,6 @@ volatile PORT_TYPE *triggerThird_pin_port;
|
|||
volatile PINMASK_TYPE triggerThird_pin_mask;
|
||||
|
||||
//These are variables used across multiple files
|
||||
bool initialisationComplete = false; ///< Tracks whether the setup() function has run completely (true = has run)
|
||||
byte fpPrimeTime = 0; ///< The time (in seconds, based on @ref statuses.secl) that the fuel pump started priming
|
||||
uint8_t softLimitTime = 0; //The time (in 0.1 seconds, based on seclx10) that the soft limiter started
|
||||
volatile uint16_t mainLoopCount; //Main loop counter (incremented at each main loop rev., used for maintaining currentStatus.loopsPerSecond)
|
||||
|
@ -119,8 +118,6 @@ bool clutchTrigger;
|
|||
bool previousClutchTrigger;
|
||||
volatile uint32_t toothHistory[TOOTH_LOG_SIZE]; ///< Tooth trigger history - delta time (in uS) from last tooth (Indexed by @ref toothHistoryIndex)
|
||||
volatile uint8_t compositeLogHistory[TOOTH_LOG_SIZE];
|
||||
volatile bool fpPrimed = false; ///< Tracks whether or not the fuel pump priming has been completed yet
|
||||
volatile bool injPrimed = false; ///< Tracks whether or not the injectors priming has been completed yet
|
||||
volatile unsigned int toothHistoryIndex = 0; ///< Current index to @ref toothHistory array
|
||||
unsigned long currentLoopTime; /**< The time (in uS) that the current mainloop started */
|
||||
volatile uint16_t ignitionCount; /**< The count of ignition events that have taken place since the engine started */
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
#ifndef GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
#include <Arduino.h>
|
||||
#include <SimplyAtomic.h>
|
||||
#include "table2d.h"
|
||||
#include "table3d.h"
|
||||
#include <assert.h>
|
||||
#include "src/FastCRC/FastCRC.h"
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
||||
|
@ -205,9 +205,6 @@
|
|||
#define BIT_AIRCON_FAN 6 //Indicates whether the A/C fan is running
|
||||
#define BIT_AIRCON_UNUSED8 7
|
||||
|
||||
#define VALID_MAP_MAX 1022 //The largest ADC value that is valid for the MAP sensor
|
||||
#define VALID_MAP_MIN 2 //The smallest ADC value that is valid for the MAP sensor
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
#define TOOTH_LOG_SIZE 127U
|
||||
#else
|
||||
|
@ -304,9 +301,9 @@ static_assert(TOOTH_LOG_SIZE<UINT8_MAX, "Check all uses of TOOTH_LOG_SIZE");
|
|||
#define AE_MODE_MULTIPLIER 0
|
||||
#define AE_MODE_ADDER 1
|
||||
|
||||
#define KNOCK_MODE_OFF 0
|
||||
#define KNOCK_MODE_DIGITAL 1
|
||||
#define KNOCK_MODE_ANALOG 2
|
||||
#define KNOCK_MODE_OFF 0U
|
||||
#define KNOCK_MODE_DIGITAL 1U
|
||||
#define KNOCK_MODE_ANALOG 2U
|
||||
|
||||
#define KNOCK_TRIGGER_HIGH 0
|
||||
#define KNOCK_TRIGGER_LOW 1
|
||||
|
@ -589,14 +586,12 @@ struct statuses {
|
|||
uint16_t RPM; ///< RPM - Current Revs per minute
|
||||
byte RPMdiv100; ///< RPM value scaled (divided by 100) to fit a byte (0-255, e.g. 12000 => 120)
|
||||
long longRPM; ///< RPM as long int (gets assigned to / maintained in statuses.RPM as well)
|
||||
uint16_t mapADC;
|
||||
int baroADC;
|
||||
uint16_t baroADC;
|
||||
long MAP; ///< Manifold absolute pressure. Has to be a long for PID calcs (Boost control)
|
||||
int16_t EMAP; ///< EMAP ... (See @ref config6.useEMAP for EMAP enablement)
|
||||
uint16_t EMAPADC;
|
||||
byte baro; ///< Barometric pressure is simply the initial MAP reading, taken before the engine is running. Alternatively, can be taken from an external sensor
|
||||
byte TPS; /**< The current TPS reading (0% - 100%). Is the tpsADC value after the calibration is applied */
|
||||
byte tpsADC; /**< byte (valued: 0-255) representation of the TPS. Downsampled from the original 10-bit (0-1023) reading, but before any calibration is applied */
|
||||
uint8_t baro; ///< Barometric pressure is simply the initial MAP reading, taken before the engine is running. Alternatively, can be taken from an external sensor
|
||||
uint8_t TPS; /**< The current TPS reading (0% - 100%). Is the tpsADC value after the calibration is applied */
|
||||
uint8_t tpsADC; /**< byte (valued: 0-255) representation of the TPS. Downsampled from the original 10-bit (0-1023) reading, but before any calibration is applied */
|
||||
int16_t tpsDOT; /**< TPS delta over time. Measures the % per second that the TPS is changing. Note that is signed value, because TPSdot can be also negative */
|
||||
byte TPSlast; /**< The previous TPS reading */
|
||||
int16_t mapDOT; /**< MAP delta over time. Measures the kpa per second that the MAP is changing. Note that is signed value, because MAPdot can be also negative */
|
||||
|
@ -604,15 +599,14 @@ struct statuses {
|
|||
byte VE; /**< The current VE value being used in the fuel calculation. Can be the same as VE1 or VE2, or a calculated value of both. */
|
||||
byte VE1; /**< The VE value from fuel table 1 */
|
||||
byte VE2; /**< The VE value from fuel table 2, if in use (and required conditions are met) */
|
||||
byte O2; /**< Primary O2 sensor reading */
|
||||
byte O2_2; /**< Secondary O2 sensor reading */
|
||||
uint8_t O2; /**< Primary O2 sensor reading */
|
||||
uint8_t O2_2; /**< Secondary O2 sensor reading */
|
||||
int coolant; /**< Coolant temperature reading */
|
||||
int cltADC;
|
||||
uint16_t cltADC;
|
||||
int IAT; /**< Inlet air temperature reading */
|
||||
int iatADC;
|
||||
int batADC;
|
||||
int O2ADC;
|
||||
int O2_2ADC;
|
||||
uint16_t iatADC;
|
||||
uint16_t O2ADC;
|
||||
uint16_t O2_2ADC;
|
||||
uint16_t dwell; ///< dwell (coil primary winding/circuit on) time (in ms * 10 ? See @ref correctionsDwell)
|
||||
volatile uint16_t actualDwell; ///< actual dwell time if new ignition mode is used (in uS)
|
||||
byte dwellCorrection; /**< The amount of correction being applied to the dwell time (in unit ...). */
|
||||
|
@ -704,10 +698,28 @@ struct statuses {
|
|||
byte airConStatus;
|
||||
};
|
||||
|
||||
static inline bool HasAnySync(const statuses &status) {
|
||||
/**
|
||||
* @brief Non-atomic version of HasAnySync. **Should only be called in an ATOMIC() block***
|
||||
*
|
||||
*/
|
||||
static inline bool HasAnySyncUnsafe(const statuses &status) {
|
||||
return status.hasSync || BIT_CHECK(status.status3, BIT_STATUS3_HALFSYNC);
|
||||
}
|
||||
|
||||
static inline bool HasAnySync(const statuses &status) {
|
||||
ATOMIC() {
|
||||
return HasAnySyncUnsafe(status);
|
||||
}
|
||||
return false; // Just here to avoid compiler warning.
|
||||
}
|
||||
|
||||
enum MAPSamplingMethod {
|
||||
MAPSamplingInstantaneous = 0,
|
||||
MAPSamplingCycleAverage = 1,
|
||||
MAPSamplingCycleMinimum = 2,
|
||||
MAPSamplingIgnitionEventAverage= 3,
|
||||
};
|
||||
|
||||
/** Page 2 of the config - mostly variables that are required for fuel.
|
||||
* These are "non-live" EFI setting, engine and "system" variables that remain fixed once sent
|
||||
* (and stored to e.g. EEPROM) from configuration/tuning SW (from outside by USBserial/bluetooth).
|
||||
|
@ -754,7 +766,7 @@ struct config2 {
|
|||
uint16_t injAng[4];
|
||||
|
||||
//config1 in ini
|
||||
byte mapSample : 2; ///< MAP sampling method (0=Instantaneous, 1=Cycle Average, 2=Cycle Minimum, 4=Ign. event average, See sensors.ino)
|
||||
MAPSamplingMethod mapSample : 2; ///< MAP sampling method (0=Instantaneous, 1=Cycle Average, 2=Cycle Minimum, 4=Ign. event average, See sensors.ino)
|
||||
byte strokes : 1; ///< Engine cycle type: four-stroke (0) / two-stroke (1)
|
||||
byte injType : 1; ///< Injector type 0=Port (INJ_TYPE_PORT), 1=Throttle Body / TBI (INJ_TYPE_TBODY)
|
||||
byte nCylinders : 4; ///< Number of cylinders
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
#include "table2d.h"
|
||||
#include BOARD_H //Note that this is not a real file, it is defined in globals.h.
|
||||
|
||||
#define IAC_ALGORITHM_NONE 0
|
||||
#define IAC_ALGORITHM_ONOFF 1
|
||||
#define IAC_ALGORITHM_PWM_OL 2
|
||||
#define IAC_ALGORITHM_PWM_CL 3
|
||||
#define IAC_ALGORITHM_STEP_OL 4
|
||||
#define IAC_ALGORITHM_STEP_CL 5
|
||||
#define IAC_ALGORITHM_PWM_OLCL 6 //Openloop plus closedloop IAC control
|
||||
#define IAC_ALGORITHM_STEP_OLCL 7 //Openloop plus closedloop IAC control
|
||||
#define IAC_ALGORITHM_NONE 0U
|
||||
#define IAC_ALGORITHM_ONOFF 1U
|
||||
#define IAC_ALGORITHM_PWM_OL 2U
|
||||
#define IAC_ALGORITHM_PWM_CL 3U
|
||||
#define IAC_ALGORITHM_STEP_OL 4U
|
||||
#define IAC_ALGORITHM_STEP_CL 5U
|
||||
#define IAC_ALGORITHM_PWM_OLCL 6U //Openloop plus closedloop IAC control
|
||||
#define IAC_ALGORITHM_STEP_OLCL 7U //Openloop plus closedloop IAC control
|
||||
|
||||
#define IDLE_PIN_LOW() *idle_pin_port &= ~(idle_pin_mask)
|
||||
#define IDLE_PIN_HIGH() *idle_pin_port |= (idle_pin_mask)
|
||||
|
|
|
@ -236,6 +236,7 @@ void initialiseAll(void)
|
|||
initialiseCorrections();
|
||||
BIT_CLEAR(currentStatus.engineProtectStatus, PROTECT_IO_ERROR); //Clear the I/O error bit. The bit will be set in initialiseADC() if there is problem in there.
|
||||
initialiseADC();
|
||||
initialiseMAPBaro();
|
||||
initialiseProgrammableIO();
|
||||
|
||||
//Check whether the flex sensor is enabled and if so, attach an interrupt for it
|
||||
|
@ -309,11 +310,7 @@ void initialiseAll(void)
|
|||
fixedCrankingOverride = 0;
|
||||
timer5_overflow_count = 0;
|
||||
toothHistoryIndex = 0;
|
||||
toothLastToothTime = 0;
|
||||
|
||||
//Lookup the current MAP reading for barometric pressure
|
||||
instanteneousMAPReading();
|
||||
readBaro();
|
||||
resetDecoder();
|
||||
|
||||
noInterrupts();
|
||||
initialiseTriggers();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "globals.h"
|
||||
#include "logger.h"
|
||||
#include "errors.h"
|
||||
#include "decoders.h"
|
||||
#include "init.h"
|
||||
#include "maths.h"
|
||||
|
@ -120,7 +119,7 @@ byte getTSLogEntry(uint16_t byteNum)
|
|||
case 73: statusValue = highByte(currentStatus.canin[15]); break;
|
||||
|
||||
case 74: statusValue = currentStatus.tpsADC; break;
|
||||
case 75: statusValue = getNextError(); break;
|
||||
case 75: statusValue = 0U /*getNextError()*/; break;
|
||||
|
||||
case 76: statusValue = lowByte(currentStatus.PW1); break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
|
||||
case 77: statusValue = highByte(currentStatus.PW1); break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
|
||||
|
@ -258,7 +257,7 @@ int16_t getReadableLogEntry(uint16_t logIndex)
|
|||
case 50: statusValue = currentStatus.canin[15]; break;
|
||||
|
||||
case 51: statusValue = currentStatus.tpsADC; break;
|
||||
case 52: statusValue = getNextError(); break;
|
||||
case 52: statusValue = 0U /*getNextError()*/; break;
|
||||
|
||||
case 53: statusValue = currentStatus.PW1; break; //Pulsewidth 1 multiplied by 10 in ms. Have to convert from uS to mS.
|
||||
case 54: statusValue = currentStatus.PW2; break; //Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
|
||||
|
@ -425,7 +424,7 @@ uint8_t getLegacySecondarySerialLogEntry(uint16_t byteNum)
|
|||
case 72: statusValue = highByte(currentStatus.canin[15]); break;
|
||||
|
||||
case 73: statusValue = currentStatus.tpsADC; break;
|
||||
case 74: statusValue = getNextError(); break; // errorNum (0:1), currentError(2:7)
|
||||
case 74: statusValue = 0U /*getNextError()*/; break; // errorNum (0:1), currentError(2:7)
|
||||
|
||||
case 75: statusValue = currentStatus.launchCorrection; break;
|
||||
case 76: statusValue = lowByte(currentStatus.PW2); break; //Pulsewidth 2 multiplied by 10 in ms. Have to convert from uS to mS.
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "src/libdivide/constant_fast_div.h"
|
||||
#endif
|
||||
|
||||
extern uint8_t random1to100(void);
|
||||
uint8_t random1to100(void);
|
||||
|
||||
/**
|
||||
* @defgroup group-rounded-div Rounding integer division
|
||||
|
@ -215,12 +215,6 @@ static inline int16_t nudge(int16_t min, int16_t max, int16_t value, int16_t nud
|
|||
return value;
|
||||
}
|
||||
|
||||
//This is a dedicated function that specifically handles the case of mapping 0-1023 values into a 0 to X range
|
||||
//This is a common case because it means converting from a standard 10-bit analog input to a byte or 10-bit analog into 0-511 (Eg the temperature readings)
|
||||
#define fastMap1023toX(x, out_max) ( rshift<10>((uint32_t)(x) * (out_max)) )
|
||||
//This is a new version that allows for out_min
|
||||
#define fastMap10Bit(x, out_min, out_max) ( rshift<10>( (uint32_t)(x) * ((out_max)-(out_min)) ) + (out_min))
|
||||
|
||||
#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
|
||||
|
||||
static inline bool udiv_is16bit_result(uint32_t dividend, uint16_t divisor) {
|
||||
|
@ -300,4 +294,55 @@ static inline uint16_t udiv_32_16_closest(uint32_t dividend, uint16_t divisor)
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief clamps a given value between the minimum and maximum thresholds.
|
||||
*
|
||||
* Uses operator< to compare the values.
|
||||
*
|
||||
* @tparam T Any type that supports operator<
|
||||
* @param v The value to clamp
|
||||
* @param lo The minimum threshold
|
||||
* @param hi The maximum threshold
|
||||
* @return if v compares less than lo, returns lo; otherwise if hi compares less than v, returns hi; otherwise returns v.
|
||||
*/
|
||||
template<class T>
|
||||
constexpr const T& clamp(const T& v, const T& lo, const T& hi){
|
||||
return v<lo ? lo : hi<v ? hi : v;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
|
||||
template <typename T, typename TPrime>
|
||||
static inline T LOW_PASS_FILTER_8BIT(T input, uint8_t alpha, T prior) {
|
||||
// Intermediate steps are for MISRA compliance
|
||||
// Equivalent to: (input * (256 - alpha) + (prior * alpha)) >> 8
|
||||
static constexpr T ALPHA_MAX = (T)256;
|
||||
T inv_alpha = ALPHA_MAX - (T)alpha;
|
||||
TPrime prior_alpha = (prior * (TPrime)alpha);
|
||||
TPrime preshift = (input * (TPrime)inv_alpha) + prior_alpha;
|
||||
return (T)(preshift / ALPHA_MAX); // Division should resolve to a shift & avoids a MISRA violation
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* @brief Simple low pass IIR filter 16-bit values
|
||||
*
|
||||
* This is effectively implementing the smooth filter from playground.arduino.cc/Main/Smooth
|
||||
* But removes the use of floats and uses 8 bits of fixed precision.
|
||||
*
|
||||
* @param input incoming unfiltered value
|
||||
* @param alpha filter factor. 0=off, 255=full smoothing (0.00 to 0.99 in float, 0-99%)
|
||||
* @param prior previous *filtered* value.
|
||||
* @return uint16_t The filtered input
|
||||
*/
|
||||
static inline uint16_t LOW_PASS_FILTER(uint16_t input, uint8_t alpha, uint16_t prior) {
|
||||
return LOW_PASS_FILTER_8BIT<uint16_t, uint32_t>(input, alpha, prior);
|
||||
}
|
||||
|
||||
/** @brief Simple low pass IIR filter for S16 values */
|
||||
static inline int16_t LOW_PASS_FILTER(int16_t input, uint8_t alpha, int16_t prior) {
|
||||
return LOW_PASS_FILTER_8BIT<int16_t, int32_t>(input, alpha, prior);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -47,7 +47,7 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
|||
#define IGNITION_REFRESH_THRESHOLD 30 //Time in uS that the refresh functions will check to ensure there is enough time before changing the end compare
|
||||
|
||||
#define DWELL_AVERAGE_ALPHA 30
|
||||
#define DWELL_AVERAGE(input) (((long)input * (256 - DWELL_AVERAGE_ALPHA) + ((long)currentStatus.actualDwell * DWELL_AVERAGE_ALPHA))) >> 8
|
||||
#define DWELL_AVERAGE(input) LOW_PASS_FILTER((input), DWELL_AVERAGE_ALPHA, currentStatus.actualDwell)
|
||||
//#define DWELL_AVERAGE(input) (currentStatus.dwell) //Can be use to disable the above for testing
|
||||
|
||||
void initialiseSchedulers(void);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,29 +5,25 @@
|
|||
|
||||
// The following are alpha values for the ADC filters.
|
||||
// Their values are from 0 to 240, with 0 being no filtering and 240 being maximum
|
||||
#define ADCFILTER_TPS_DEFAULT 50
|
||||
#define ADCFILTER_CLT_DEFAULT 180
|
||||
#define ADCFILTER_IAT_DEFAULT 180
|
||||
#define ADCFILTER_O2_DEFAULT 128
|
||||
#define ADCFILTER_BAT_DEFAULT 128
|
||||
#define ADCFILTER_MAP_DEFAULT 20 //This is only used on Instantaneous MAP readings and is intentionally very weak to allow for faster response
|
||||
#define ADCFILTER_BARO_DEFAULT 64
|
||||
#define ADCFILTER_TPS_DEFAULT 50U
|
||||
#define ADCFILTER_CLT_DEFAULT 180U
|
||||
#define ADCFILTER_IAT_DEFAULT 180U
|
||||
#define ADCFILTER_O2_DEFAULT 128U
|
||||
#define ADCFILTER_BAT_DEFAULT 128U
|
||||
#define ADCFILTER_MAP_DEFAULT 20U //This is only used on Instantaneous MAP readings and is intentionally very weak to allow for faster response
|
||||
#define ADCFILTER_BARO_DEFAULT 64U
|
||||
|
||||
#define ADCFILTER_PSI_DEFAULT 150 //not currently configurable at runtime, used for misc pressure sensors, oil, fuel, etc.
|
||||
#define ADCFILTER_PSI_DEFAULT 150U //not currently configurable at runtime, used for misc pressure sensors, oil, fuel, etc.
|
||||
|
||||
#define FILTER_FLEX_DEFAULT 75
|
||||
#define FILTER_FLEX_DEFAULT 75U
|
||||
|
||||
#define BARO_MIN 65
|
||||
#define BARO_MAX 108
|
||||
|
||||
#define VSS_GEAR_HYSTERESIS 10
|
||||
#define VSS_SAMPLES 4 //Must be a power of 2 and smaller than 255
|
||||
#define VSS_GEAR_HYSTERESIS 10U
|
||||
#define VSS_SAMPLES 4U //Must be a power of 2 and smaller than 255
|
||||
|
||||
#define TPS_READ_FREQUENCY 30 //ONLY VALID VALUES ARE 15 or 30!!!
|
||||
|
||||
extern volatile byte flexCounter;
|
||||
extern volatile unsigned long flexStartTime;
|
||||
extern volatile unsigned long flexPulseWidth;
|
||||
extern volatile uint32_t flexPulseWidth;
|
||||
|
||||
#if defined(CORE_AVR)
|
||||
#define READ_FLEX() ((*flex_pin_port & flex_pin_mask) ? true : false)
|
||||
|
@ -35,21 +31,7 @@ extern volatile unsigned long flexPulseWidth;
|
|||
#define READ_FLEX() digitalRead(pinFlex)
|
||||
#endif
|
||||
|
||||
#define ADMUX_DEFAULT_CONFIG 0x40 //AVCC reference, ADC0 input, right adjusted, ADC enabled
|
||||
|
||||
extern unsigned int MAPcount; //Number of samples taken in the current MAP cycle
|
||||
extern uint32_t MAPcurRev; //Tracks which revolution we're sampling on
|
||||
extern bool auxIsEnabled;
|
||||
extern uint16_t MAPlast; /**< The previous MAP reading */
|
||||
extern unsigned long MAP_time; //The time the MAP sample was taken
|
||||
extern unsigned long MAPlast_time; //The time the previous MAP sample was taken
|
||||
|
||||
/**
|
||||
* @brief Simple low pass IIR filter macro for the analog inputs
|
||||
* This is effectively implementing the smooth filter from playground.arduino.cc/Main/Smooth
|
||||
* But removes the use of floats and uses 8 bits of fixed precision.
|
||||
*/
|
||||
#define ADC_FILTER(input, alpha, prior) (((long)input * (256 - alpha) + ((long)prior * alpha))) >> 8
|
||||
|
||||
void initialiseADC(void);
|
||||
void readTPS(bool useFilter=true); //Allows the option to override the use of the filter
|
||||
|
@ -69,8 +51,18 @@ void readIAT(void);
|
|||
void readO2(void);
|
||||
void readBat(void);
|
||||
void readBaro(void);
|
||||
|
||||
/** @brief Initialize the MAP calculation & Baro values */
|
||||
void initialiseMAPBaro(void);
|
||||
|
||||
void readMAP(void);
|
||||
void instanteneousMAPReading(void);
|
||||
|
||||
uint8_t getAnalogKnock(void);
|
||||
|
||||
/** @brief Get the MAP change between the last 2 readings */
|
||||
int16_t getMAPDelta(void);
|
||||
|
||||
/** @brief Get the time in µS between the last 2 MAP readings */
|
||||
uint32_t getMAPDeltaTime(void);
|
||||
|
||||
#endif // SENSORS_H
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
/// @cond
|
||||
#include <stdint.h>
|
||||
|
||||
// These are private to the MAP sampling algorithms but are broken out here
|
||||
// to support unit testing of the algorithm implementations
|
||||
|
||||
struct map_last_read_t {
|
||||
uint16_t lastMAPValue; // kPA
|
||||
uint32_t currentReadingTime; // µS
|
||||
#if defined(__UINT24_MAX__)
|
||||
// Maximum time between readings is ~3s (at min RPM). 24 bits is enough for that
|
||||
__uint24 timeDeltaReadings;
|
||||
#else
|
||||
uint32_t timeDeltaReadings;
|
||||
#endif
|
||||
};
|
||||
|
||||
// A pair of ADC sensor readings
|
||||
struct map_adc_readings_t {
|
||||
uint16_t mapADC;
|
||||
uint16_t emapADC;
|
||||
};
|
||||
|
||||
// Working state for the cycle average sampling algorithm
|
||||
struct map_cycle_average_t {
|
||||
uint8_t cycleStartIndex;
|
||||
#if defined(__UINT24_MAX__)
|
||||
// Maximum revolution time is ~1.5s (at min RPM). At a 1KHz sampling rate & 2 revolutions,
|
||||
// we'll store 3000 readings each at maximum of 1023 (~3000000 max). So a 24-bit value
|
||||
// should be plenty.
|
||||
__uint24 mapAdcRunningTotal;
|
||||
__uint24 emapAdcRunningTotal;
|
||||
#else
|
||||
uint32_t mapAdcRunningTotal;
|
||||
uint32_t emapAdcRunningTotal;
|
||||
#endif
|
||||
uint16_t sampleCount;
|
||||
};
|
||||
|
||||
// Working state for the cycle minimum sampling algorithm
|
||||
struct map_cycle_min_t {
|
||||
uint8_t cycleStartIndex;
|
||||
uint16_t mapMinimum;
|
||||
};
|
||||
|
||||
// Working state for the event average sampling algorithm
|
||||
struct map_event_average_t {
|
||||
#if defined(__UINT24_MAX__)
|
||||
__uint24 mapAdcRunningTotal;
|
||||
#else
|
||||
uint32_t mapAdcRunningTotal;
|
||||
#endif
|
||||
uint16_t sampleCount;
|
||||
uint8_t eventStartIndex;
|
||||
};
|
||||
|
||||
// The overall MAP sampling system working state
|
||||
struct map_algorithm_t {
|
||||
map_last_read_t lastReading;
|
||||
map_adc_readings_t sensorReadings;
|
||||
|
||||
union {
|
||||
map_cycle_average_t cycle_average;
|
||||
map_cycle_min_t cycle_min;
|
||||
map_event_average_t event_average;
|
||||
};
|
||||
};
|
||||
|
||||
/// @endcond
|
|
@ -88,7 +88,16 @@ inline uint16_t applyFuelTrimToPW(trimTable3d *pTrimTable, int16_t fuelLoad, int
|
|||
* - Can be tested for certain frequency interval being expired by (eg) BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)
|
||||
*
|
||||
*/
|
||||
void loop(void)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
// Sometimes loop() is inlined by LTO & sometimes not
|
||||
// When not inlined, there is a huge difference in stack usage: 60+ bytes
|
||||
// That eats into available RAM.
|
||||
// Adding __attribute__((always_inline)) forces the LTO process to inline.
|
||||
//
|
||||
// Since the function is declared in an Arduino header, we can't change
|
||||
// it to inline, so we need to suppress the resulting warning.
|
||||
void __attribute__((always_inline)) loop(void)
|
||||
{
|
||||
mainLoopCount++;
|
||||
LOOP_TIMER = TIMER_mask;
|
||||
|
@ -138,8 +147,7 @@ void loop(void)
|
|||
}
|
||||
|
||||
currentLoopTime = micros_safe();
|
||||
uint32_t timeToLastTooth = (currentLoopTime - toothLastToothTime);
|
||||
if ( (timeToLastTooth < MAX_STALL_TIME) || (toothLastToothTime > currentLoopTime) ) //Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped. toothLastToothTime can be greater than currentLoopTime if a pulse occurs between getting the latest time and doing the comparison
|
||||
if ( engineIsRunning(currentLoopTime) )
|
||||
{
|
||||
currentStatus.longRPM = getRPM(); //Long RPM is included here
|
||||
currentStatus.RPM = currentStatus.longRPM;
|
||||
|
@ -158,17 +166,12 @@ void loop(void)
|
|||
currentStatus.PW1 = 0;
|
||||
currentStatus.VE = 0;
|
||||
currentStatus.VE2 = 0;
|
||||
toothLastToothTime = 0;
|
||||
toothLastSecToothTime = 0;
|
||||
//toothLastMinusOneToothTime = 0;
|
||||
resetDecoder();
|
||||
currentStatus.hasSync = false;
|
||||
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC);
|
||||
currentStatus.runSecs = 0; //Reset the counter for number of seconds running.
|
||||
currentStatus.startRevolutions = 0;
|
||||
toothSystemCount = 0;
|
||||
secondaryToothCount = 0;
|
||||
MAPcurRev = 0;
|
||||
MAPcount = 0;
|
||||
initialiseMAPBaro();
|
||||
currentStatus.rpmDOT = 0;
|
||||
AFRnextCycle = 0;
|
||||
ignitionCount = 0;
|
||||
|
@ -1197,6 +1200,8 @@ void loop(void)
|
|||
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
|
||||
}
|
||||
} //loop()
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif //Unit test guard
|
||||
|
||||
/**
|
||||
|
|
|
@ -300,22 +300,22 @@ void oneMSInterval(void) //Most ARM chips can simply call a function
|
|||
byte tempEthPct = 0;
|
||||
if(flexCounter < configPage2.flexFreqLow)
|
||||
{
|
||||
tempEthPct = 0; //Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
|
||||
flexCounter = 0;
|
||||
tempEthPct = 0U; //Standard GM Continental sensor reads from 50Hz (0 ethanol) to 150Hz (Pure ethanol). Subtracting 50 from the frequency therefore gives the ethanol percentage.
|
||||
flexCounter = 0U;
|
||||
}
|
||||
else if (flexCounter > (configPage2.flexFreqHigh + 1) ) //1 pulse buffer
|
||||
{
|
||||
|
||||
if(flexCounter < (configPage2.flexFreqLow + 19)) //20Hz above the max freq is considered an error condition. Everything below that should be treated as max value
|
||||
{
|
||||
tempEthPct = 100;
|
||||
flexCounter = 0;
|
||||
tempEthPct = 100U;
|
||||
flexCounter = 0U;
|
||||
}
|
||||
else
|
||||
{
|
||||
//This indicates an error condition. Spec of the sensor is that errors are above 170Hz)
|
||||
tempEthPct = 0;
|
||||
flexCounter = 0;
|
||||
tempEthPct = 0U;
|
||||
flexCounter = 0U;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -325,9 +325,9 @@ void oneMSInterval(void) //Most ARM chips can simply call a function
|
|||
}
|
||||
|
||||
//Off by 1 error check
|
||||
if (tempEthPct == 1) { tempEthPct = 0; }
|
||||
if (tempEthPct == 1U) { tempEthPct = 0U; }
|
||||
|
||||
currentStatus.ethanolPct = ADC_FILTER(tempEthPct, configPage4.FILTER_FLEX, currentStatus.ethanolPct);
|
||||
currentStatus.ethanolPct = (uint8_t)LOW_PASS_FILTER((uint16_t)tempEthPct, configPage4.FILTER_FLEX, (uint16_t)currentStatus.ethanolPct);
|
||||
|
||||
//Continental flex sensor fuel temperature can be read with following formula: (Temperature = (41.25 * pulse width(ms)) - 81.25). 1000μs = -40C and 5000μs = 125C
|
||||
flexPulseWidth = constrain(flexPulseWidth, 1000UL, 5000UL);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Unit testability support
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(UNIT_TEST)
|
||||
/**
|
||||
* @brief Mark an entity as having static (internal) linkage, unless a unit
|
||||
* test is in progress - then the entity is given external linkage so the test can access it.
|
||||
*
|
||||
* Most useful for translation unit scoped variables. I.e. static within a CPP file
|
||||
*
|
||||
*/
|
||||
#define TESTABLE_STATIC static
|
||||
#else
|
||||
#define TESTABLE_STATIC
|
||||
#endif
|
||||
|
||||
#if !defined(UNIT_TEST)
|
||||
/**
|
||||
* @brief Mark an entity as having static (internal) linkage & inlined, unless a unit
|
||||
* test is in progress - then the entity is given external linkage so the test can access it.
|
||||
*
|
||||
* Most useful for translation unit scoped functions. I.e. "static inline" within a CPP file
|
||||
*
|
||||
*/
|
||||
#define TESTABLE_INLINE_STATIC static inline
|
||||
#else
|
||||
#define TESTABLE_INLINE_STATIC
|
||||
#endif
|
|
@ -1,4 +1,5 @@
|
|||
#include <unity.h>
|
||||
#include "../../test_utils.h"
|
||||
#include "decoders.h"
|
||||
#include "init.h"
|
||||
|
||||
|
@ -6,6 +7,7 @@ static void test_k6a_getCrankAngle_tooth(uint8_t toothNum, uint16_t expectedCran
|
|||
triggerSetup_SuzukiK6A();
|
||||
configPage4.triggerAngle = 0U;
|
||||
|
||||
extern volatile unsigned long toothLastToothTime;
|
||||
toothLastToothTime = micros() - 150U;
|
||||
toothCurrentCount = toothNum;
|
||||
// Allow some variance since the algorithm relies on calling micros();
|
||||
|
@ -54,6 +56,8 @@ static void test_k6a_getCrankAngle_tooth8(void) {
|
|||
|
||||
void testSuzukiK6A_getCrankAngle()
|
||||
{
|
||||
SET_UNITY_FILENAME() {
|
||||
|
||||
RUN_TEST(test_k6a_getCrankAngle_tooth0);
|
||||
RUN_TEST(test_k6a_getCrankAngle_tooth1);
|
||||
RUN_TEST(test_k6a_getCrankAngle_tooth2);
|
||||
|
@ -63,4 +67,6 @@ void testSuzukiK6A_getCrankAngle()
|
|||
RUN_TEST(test_k6a_getCrankAngle_tooth6);
|
||||
RUN_TEST(test_k6a_getCrankAngle_tooth7);
|
||||
RUN_TEST(test_k6a_getCrankAngle_tooth8);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <decoders.h>
|
||||
#include <globals.h>
|
||||
#include <unity.h>
|
||||
#include "decoders.h"
|
||||
#include "globals.h"
|
||||
#include "../../test_utils.h"
|
||||
#include "schedule_calcs.h"
|
||||
|
||||
static void test_setup_SuzukiK6A()
|
||||
|
@ -271,6 +272,8 @@ void test_K6A_newIgn_trigNeg366()
|
|||
|
||||
void testSuzukiK6A_setEndTeeth()
|
||||
{
|
||||
SET_UNITY_FILENAME() {
|
||||
|
||||
RUN_TEST(test_k6A_newIgn_trig0_1);
|
||||
RUN_TEST(test_k6A_newIgn_trig90_1);
|
||||
RUN_TEST(test_k6A_newIgn_trig180_1);
|
||||
|
@ -291,3 +294,4 @@ void testSuzukiK6A_setEndTeeth()
|
|||
RUN_TEST(test_k6A_newIgn_trigNeg270_2);
|
||||
RUN_TEST(test_K6A_newIgn_trigNeg366);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include <unity.h>
|
||||
#include "../test_utils.h"
|
||||
#include "decoders.h"
|
||||
|
||||
static void test_engineIsRunning(void)
|
||||
{
|
||||
extern volatile unsigned long toothLastToothTime;
|
||||
extern unsigned long MAX_STALL_TIME;
|
||||
|
||||
MAX_STALL_TIME = 1000;
|
||||
toothLastToothTime = 0;
|
||||
TEST_ASSERT_TRUE(engineIsRunning(toothLastToothTime+MAX_STALL_TIME-1UL));
|
||||
TEST_ASSERT_FALSE(engineIsRunning(toothLastToothTime+MAX_STALL_TIME));
|
||||
TEST_ASSERT_FALSE(engineIsRunning(toothLastToothTime+MAX_STALL_TIME+1UL));
|
||||
|
||||
// Simulate an interrupt for a pulse being triggered between a call
|
||||
// to micros() (1000) and the call to engineIsRunning()
|
||||
toothLastToothTime = 2500;
|
||||
TEST_ASSERT_TRUE(engineIsRunning(1000UL));
|
||||
|
||||
TEST_ASSERT_TRUE(engineIsRunning(2499UL));
|
||||
TEST_ASSERT_TRUE(engineIsRunning(2500UL));
|
||||
TEST_ASSERT_TRUE(engineIsRunning(2501UL));
|
||||
|
||||
TEST_ASSERT_FALSE(engineIsRunning(toothLastToothTime+MAX_STALL_TIME));
|
||||
}
|
||||
|
||||
void testDecoder_General()
|
||||
{
|
||||
SET_UNITY_FILENAME() {
|
||||
RUN_TEST(test_engineIsRunning);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@
|
|||
#include "NGC/test_ngc.h"
|
||||
#include "SuzukiK6A/SuzukiK6A.h"
|
||||
|
||||
extern void testDecoder_General(void);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
@ -29,6 +31,7 @@ void setup()
|
|||
testNGC();
|
||||
testSuzukiK6A_setEndTeeth();
|
||||
testSuzukiK6A_getCrankAngle();
|
||||
testDecoder_General();
|
||||
|
||||
UNITY_END(); // stop unit testing
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include <unity.h>
|
||||
#include "../test_utils.h"
|
||||
#include "globals.h"
|
||||
#include "corrections.h"
|
||||
#include "test_corrections.h"
|
||||
#include "../test_utils.h"
|
||||
#include "init.h"
|
||||
#include "sensors.h"
|
||||
#include "speeduino.h"
|
||||
#include "../test_utils.h"
|
||||
#include "sensors_map_structs.h"
|
||||
|
||||
extern void construct2dTables(void);
|
||||
|
||||
|
@ -1175,6 +1175,7 @@ static void test_corrections_TAE()
|
|||
RUN_TEST_P(test_corrections_TAE_timout);
|
||||
}
|
||||
|
||||
extern map_last_read_t& getMapLast(void);
|
||||
|
||||
//**********************************************************************************************************************
|
||||
//Setup a basic MAE enrichment curve, threshold etc that are common to all tests. Specifica values maybe updated in each individual test
|
||||
|
@ -1198,9 +1199,8 @@ static void test_corrections_MAE_negative_mapdot()
|
|||
disable_AE_taper();
|
||||
|
||||
configPage2.decelAmount = 50;
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 50;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 50;
|
||||
currentStatus.MAP = 40;
|
||||
|
||||
uint16_t accelValue = correctionAccel(); //Run the AE calcs
|
||||
|
@ -1216,9 +1216,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
setup_MAE();
|
||||
disable_AE_taper();
|
||||
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 50;
|
||||
uint16_t accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(400, currentStatus.mapDOT);
|
||||
|
@ -1228,9 +1227,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
|
||||
// No change
|
||||
reset_AE();
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 1000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 1000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 40;
|
||||
accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(0, currentStatus.mapDOT);
|
||||
|
@ -1240,9 +1238,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
|
||||
// Small change over small time period
|
||||
reset_AE();
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 1000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 1000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 41;
|
||||
accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(1000, currentStatus.mapDOT);
|
||||
|
@ -1252,9 +1249,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
|
||||
// Small change over long (>UINT16_MAX) time period
|
||||
reset_AE();
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + UINT16_MAX*2UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = UINT16_MAX*2UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 41;
|
||||
accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(7, currentStatus.mapDOT);
|
||||
|
@ -1264,9 +1260,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
|
||||
// Large change over small time period
|
||||
reset_AE();
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 1000UL;
|
||||
MAPlast = 10;
|
||||
getMapLast().timeDeltaReadings = 1000UL;
|
||||
getMapLast().lastMAPValue = 10;
|
||||
currentStatus.MAP = 1000;
|
||||
accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(6960, currentStatus.mapDOT);
|
||||
|
@ -1276,9 +1271,8 @@ static void test_corrections_MAE_no_rpm_taper()
|
|||
|
||||
// Large change over long (>UINT16_MAX) time period
|
||||
reset_AE();
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + UINT16_MAX*2UL;
|
||||
MAPlast = 10;
|
||||
getMapLast().timeDeltaReadings = UINT16_MAX*2UL;
|
||||
getMapLast().lastMAPValue = 10;
|
||||
currentStatus.MAP = 1000;
|
||||
accelValue = correctionAccel(); //Run the AE calcs
|
||||
TEST_ASSERT_EQUAL(6930, currentStatus.mapDOT);
|
||||
|
@ -1296,9 +1290,8 @@ static void test_corrections_MAE_50pc_rpm_taper()
|
|||
configPage2.aeTaperMin = 10; //1000
|
||||
configPage2.aeTaperMax = 50; //5000
|
||||
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 50;
|
||||
|
||||
uint16_t accelValue = correctionAccel(); //Run the AE calcs
|
||||
|
@ -1317,9 +1310,8 @@ static void test_corrections_MAE_110pc_rpm_taper()
|
|||
configPage2.aeTaperMin = 10; //1000
|
||||
configPage2.aeTaperMax = 50; //5000
|
||||
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 50;
|
||||
|
||||
uint16_t accelValue = correctionAccel(); //Run the AE calcs
|
||||
|
@ -1338,9 +1330,8 @@ static void test_corrections_MAE_under_threshold()
|
|||
configPage2.aeTaperMin = 10; //1000
|
||||
configPage2.aeTaperMax = 50; //5000
|
||||
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 0;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 0;
|
||||
currentStatus.MAP = 6;
|
||||
configPage2.maeThresh = 241; //Above the reading of 240%/s
|
||||
|
||||
|
@ -1356,9 +1347,8 @@ static void test_corrections_MAE_50pc_warmup_taper()
|
|||
setup_MAE();
|
||||
disable_AE_taper();
|
||||
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 50;
|
||||
|
||||
//Set a cold % of 50% increase
|
||||
|
@ -1381,9 +1371,8 @@ static void test_corrections_MAE_timout()
|
|||
disable_AE_taper();
|
||||
|
||||
// Confirm MAE is on
|
||||
MAPlast_time = UINT16_MAX*2UL;
|
||||
MAP_time = MAPlast_time + 25000UL;
|
||||
MAPlast = 40;
|
||||
getMapLast().timeDeltaReadings = 25000UL;
|
||||
getMapLast().lastMAPValue = 40;
|
||||
currentStatus.MAP = 50;
|
||||
configPage2.aeTime = 0; // This should cause the current cycle to expire & the next one to not occur.
|
||||
TEST_ASSERT_EQUAL((100+132), correctionAccel());
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
extern void testPercent(void);
|
||||
extern void testDivision(void);
|
||||
extern void testBitShift(void);
|
||||
extern void test_LOW_PASS_FILTER(void);
|
||||
|
||||
#define UNITY_EXCLUDE_DETAILS
|
||||
|
||||
|
@ -22,6 +23,7 @@ void setup()
|
|||
testPercent();
|
||||
testDivision();
|
||||
testBitShift();
|
||||
test_LOW_PASS_FILTER();
|
||||
|
||||
UNITY_END(); // stop unit testing
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include <unity.h>
|
||||
#include "maths.h"
|
||||
#include "../test_utils.h"
|
||||
|
||||
static void test_U16_min(void) {
|
||||
// Passing zero for the filter value should return the input value
|
||||
TEST_ASSERT_EQUAL_UINT16(0, LOW_PASS_FILTER(0U, 0U, 0U));
|
||||
TEST_ASSERT_EQUAL_UINT16(1234U, LOW_PASS_FILTER(1234U, 0U, 0U));
|
||||
TEST_ASSERT_EQUAL_UINT16(1234U, LOW_PASS_FILTER(1234U, 0U, 9999U));
|
||||
}
|
||||
|
||||
static void test_U16_max(void) {
|
||||
// Passing UINT8_MAX for the filter value should make the input close to the previous value
|
||||
TEST_ASSERT_EQUAL_UINT16(0, LOW_PASS_FILTER(0U, UINT8_MAX, 0U));
|
||||
TEST_ASSERT_EQUAL_UINT16(4U, LOW_PASS_FILTER(1234U, UINT8_MAX, 0U));
|
||||
TEST_ASSERT_EQUAL_UINT16(9964U, LOW_PASS_FILTER(1234U, UINT8_MAX, 9999U));
|
||||
}
|
||||
|
||||
static void test_S16_min(void) {
|
||||
// Passing zero for the filter value should return the input value
|
||||
TEST_ASSERT_EQUAL_INT16(0, LOW_PASS_FILTER(0, 0U, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(1234, LOW_PASS_FILTER(1234, 0U, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(-1234, LOW_PASS_FILTER(-1234, 0U, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(1234, LOW_PASS_FILTER(1234, 0U, 9999));
|
||||
TEST_ASSERT_EQUAL_INT16(-1234, LOW_PASS_FILTER(-1234, 0U, 9999));
|
||||
}
|
||||
|
||||
static void test_S16_max(void) {
|
||||
// Passing UINT8_MAX for the filter value should make the input close to the previous value
|
||||
TEST_ASSERT_EQUAL_INT16(0, LOW_PASS_FILTER(0, UINT8_MAX, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(4, LOW_PASS_FILTER(1234, UINT8_MAX, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(-4, LOW_PASS_FILTER(-1234, UINT8_MAX, 0));
|
||||
TEST_ASSERT_EQUAL_INT16(9964, LOW_PASS_FILTER(1234, UINT8_MAX, 9999));
|
||||
TEST_ASSERT_EQUAL_INT16(-9964, LOW_PASS_FILTER(-1234, UINT8_MAX, -9999));
|
||||
}
|
||||
|
||||
void test_LOW_PASS_FILTER(void) {
|
||||
SET_UNITY_FILENAME() {
|
||||
RUN_TEST(test_U16_min);
|
||||
RUN_TEST(test_U16_max);
|
||||
RUN_TEST(test_S16_min);
|
||||
RUN_TEST(test_S16_max);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#include <Arduino.h>
|
||||
#include <unity.h>
|
||||
|
||||
|
||||
#define UNITY_EXCLUDE_DETAILS
|
||||
|
||||
extern void test_fastMap10Bit(void);
|
||||
extern void test_map_sampling(void);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
// NOTE!!! Wait for >2 secs
|
||||
// if board doesn't support software reset via Serial.DTR/RTS
|
||||
delay(2000);
|
||||
|
||||
UNITY_BEGIN(); // IMPORTANT LINE!
|
||||
|
||||
test_fastMap10Bit();
|
||||
test_map_sampling();
|
||||
|
||||
UNITY_END(); // stop unit testing
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Blink to indicate end of test
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(250);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(250);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include <unity.h>
|
||||
#include "../test_utils.h"
|
||||
|
||||
extern int16_t fastMap10Bit(uint16_t value, int16_t rangeMin, int16_t rangeMax);
|
||||
|
||||
static void test_fastMap10Bit_negative_range(void) {
|
||||
TEST_ASSERT_EQUAL_INT(-1500, fastMap10Bit(0, -1500, -500));
|
||||
TEST_ASSERT_EQUAL_INT(-501, fastMap10Bit(1023, -1500, -500));
|
||||
// Greater than 10-bit input
|
||||
TEST_ASSERT_NOT_EQUAL_INT(-501, fastMap10Bit(1023*2, -1500, -500));
|
||||
}
|
||||
|
||||
static void test_fastMap10Bit_positive_range(void) {
|
||||
TEST_ASSERT_EQUAL_INT(500, fastMap10Bit(0, 500, 1500));
|
||||
TEST_ASSERT_EQUAL_INT(1499, fastMap10Bit(1023, 500, 1500));
|
||||
// Greater than 10-bit input
|
||||
TEST_ASSERT_NOT_EQUAL_INT(1499, fastMap10Bit(1023*2, 500, 1500));
|
||||
}
|
||||
|
||||
void test_fastMap10Bit(void) {
|
||||
SET_UNITY_FILENAME() {
|
||||
RUN_TEST(test_fastMap10Bit_negative_range);
|
||||
RUN_TEST(test_fastMap10Bit_positive_range);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
#include <unity.h>
|
||||
#include "../test_utils.h"
|
||||
#include "sensors_map_structs.h"
|
||||
|
||||
static void test_instantaneous(void) {
|
||||
extern bool instanteneousMAPReading(void);
|
||||
|
||||
TEST_ASSERT_TRUE(instanteneousMAPReading());
|
||||
}
|
||||
|
||||
extern bool cycleAverageMAPReading(const statuses ¤t, const config2 &page2, map_cycle_average_t &cycle_average, map_adc_readings_t &sensorReadings);
|
||||
extern bool canUseCycleAverage(const statuses ¤t, const config2 &page2);
|
||||
|
||||
static void enable_cycle_average(statuses ¤t, config2 &page2) {
|
||||
current.RPMdiv100 = 43;
|
||||
page2.mapSwitchPoint = 15;
|
||||
current.startRevolutions = 55;
|
||||
current.hasSync = true;
|
||||
current.status3 = 0U;
|
||||
}
|
||||
|
||||
static void test_canUseCycleAverge(void) {
|
||||
statuses current;
|
||||
config2 page2;
|
||||
enable_cycle_average(current, page2);
|
||||
|
||||
TEST_ASSERT_TRUE(canUseCycleAverage(current, page2));
|
||||
|
||||
current.hasSync = false;
|
||||
TEST_ASSERT_FALSE(canUseCycleAverage(current, page2));
|
||||
current.hasSync = true;
|
||||
|
||||
current.startRevolutions = 1;
|
||||
TEST_ASSERT_FALSE(canUseCycleAverage(current, page2));
|
||||
current.startRevolutions = 55;
|
||||
|
||||
current.RPMdiv100 = page2.mapSwitchPoint-1;
|
||||
TEST_ASSERT_FALSE(canUseCycleAverage(current, page2));
|
||||
current.RPMdiv100 = page2.mapSwitchPoint;
|
||||
TEST_ASSERT_FALSE(canUseCycleAverage(current, page2));
|
||||
current.RPMdiv100 = page2.mapSwitchPoint+1;
|
||||
TEST_ASSERT_TRUE(canUseCycleAverage(current, page2));
|
||||
}
|
||||
|
||||
struct cycleAverageMAPReading_test_data {
|
||||
statuses current;
|
||||
config2 page2;
|
||||
map_cycle_average_t cycle_average;
|
||||
map_adc_readings_t sensorReadings;
|
||||
};
|
||||
|
||||
static void setup_cycle_average(cycleAverageMAPReading_test_data &test_data) {
|
||||
enable_cycle_average(test_data.current, test_data.page2);
|
||||
test_data.cycle_average.cycleStartIndex = 0;
|
||||
test_data.cycle_average.sampleCount = 0;
|
||||
test_data.cycle_average.emapAdcRunningTotal = 0;
|
||||
test_data.cycle_average.mapAdcRunningTotal = 0;
|
||||
}
|
||||
|
||||
static void test_cycleAverageMAPReading_fallback_instantaneous(void) {
|
||||
cycleAverageMAPReading_test_data test_data;
|
||||
setup_cycle_average(test_data);
|
||||
|
||||
test_data.current.hasSync = false;
|
||||
test_data.sensorReadings.mapADC = 0x1234;
|
||||
test_data.sensorReadings.emapADC = 0x1234;
|
||||
|
||||
TEST_ASSERT_TRUE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.emapADC, test_data.cycle_average.emapAdcRunningTotal);
|
||||
|
||||
// Repeat - should get same result.
|
||||
TEST_ASSERT_TRUE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.emapADC, test_data.cycle_average.emapAdcRunningTotal);
|
||||
}
|
||||
|
||||
static void test_cycleAverageMAPReading(void) {
|
||||
cycleAverageMAPReading_test_data test_data;
|
||||
setup_cycle_average(test_data);
|
||||
|
||||
test_data.cycle_average.cycleStartIndex = test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 100;
|
||||
test_data.sensorReadings.emapADC = 200;
|
||||
// Accumulate a few samples
|
||||
TEST_ASSERT_FALSE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.emapADC, test_data.cycle_average.emapAdcRunningTotal);
|
||||
test_data.sensorReadings.mapADC = 300;
|
||||
test_data.sensorReadings.emapADC = 500;
|
||||
TEST_ASSERT_FALSE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(2, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(400, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(700, test_data.cycle_average.emapAdcRunningTotal);
|
||||
++test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 500;
|
||||
test_data.sensorReadings.emapADC = 700;
|
||||
TEST_ASSERT_FALSE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(3, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(900, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(1400, test_data.cycle_average.emapAdcRunningTotal);
|
||||
|
||||
// Leave the current cycle
|
||||
++test_data.current.startRevolutions;
|
||||
TEST_ASSERT_TRUE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(900/3, test_data.sensorReadings.mapADC);
|
||||
TEST_ASSERT_EQUAL_UINT(1400/3, test_data.sensorReadings.emapADC);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_NOT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(500, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_NOT_EQUAL_UINT(test_data.sensorReadings.emapADC, test_data.cycle_average.emapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(700, test_data.cycle_average.emapAdcRunningTotal);
|
||||
}
|
||||
|
||||
static void test_cycleAverageMAPReading_nosamples(void) {
|
||||
cycleAverageMAPReading_test_data test_data;
|
||||
setup_cycle_average(test_data);
|
||||
|
||||
test_data.cycle_average.cycleStartIndex = test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 100;
|
||||
test_data.sensorReadings.emapADC = 200;
|
||||
|
||||
++test_data.current.startRevolutions;
|
||||
++test_data.current.startRevolutions;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(0, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_TRUE(cycleAverageMAPReading(test_data.current, test_data.page2, test_data.cycle_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(100, test_data.sensorReadings.mapADC);
|
||||
TEST_ASSERT_EQUAL_UINT(200, test_data.sensorReadings.emapADC);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.cycle_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.emapADC, test_data.cycle_average.emapAdcRunningTotal);
|
||||
}
|
||||
|
||||
extern bool cycleMinimumMAPReading(const statuses ¤t, const config2 &page2, map_cycle_min_t &cycle_min, map_adc_readings_t &sensorReadings);
|
||||
|
||||
struct cycleMinmumMAPReading_test_data {
|
||||
statuses current;
|
||||
config2 page2;
|
||||
map_cycle_min_t cycle_min;
|
||||
map_adc_readings_t sensorReadings;
|
||||
};
|
||||
|
||||
static void setup_cycle_minimum(cycleMinmumMAPReading_test_data &test_data) {
|
||||
test_data.current.RPMdiv100 = 43;
|
||||
test_data.page2.mapSwitchPoint = 15;
|
||||
test_data.cycle_min.cycleStartIndex = 0;
|
||||
test_data.cycle_min.mapMinimum = UINT16_MAX;
|
||||
}
|
||||
|
||||
// static void test_cycleMinimumMAPReading_fallback_instantaneous(void) {
|
||||
// cycleMinmumMAPReading_test_data test_data;
|
||||
// setup_cycle_minimum(test_data);
|
||||
|
||||
// test_data.current.RPMdiv100 = test_data.page2.mapSwitchPoint - 1U;
|
||||
// test_data.sensorReadings.mapADC = 300;
|
||||
// test_data.sensorReadings.emapADC = 500;
|
||||
|
||||
// TEST_ASSERT_TRUE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
// TEST_ASSERT_EQUAL_UINT(UINT16_MAX, test_data.cycle_min.mapMinimum);
|
||||
|
||||
// // Repeat - should get same result.
|
||||
// TEST_ASSERT_TRUE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
// TEST_ASSERT_EQUAL_UINT(UINT16_MAX, test_data.cycle_min.mapMinimum);
|
||||
// }
|
||||
|
||||
static void test_cycleMinimumMAPReading(void) {
|
||||
cycleMinmumMAPReading_test_data test_data;
|
||||
setup_cycle_minimum(test_data);
|
||||
|
||||
|
||||
test_data.cycle_min.cycleStartIndex = test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 100;
|
||||
test_data.sensorReadings.emapADC = 200;
|
||||
// Accumulate a few samples
|
||||
TEST_ASSERT_FALSE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_min.mapMinimum);
|
||||
test_data.sensorReadings.mapADC = 300;
|
||||
test_data.sensorReadings.emapADC = 500;
|
||||
TEST_ASSERT_FALSE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(100, test_data.cycle_min.mapMinimum);
|
||||
++test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 50;
|
||||
test_data.sensorReadings.emapADC = 170;
|
||||
TEST_ASSERT_FALSE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_min.mapMinimum);
|
||||
|
||||
// Leave the current cycle
|
||||
++test_data.current.startRevolutions;
|
||||
test_data.sensorReadings.mapADC = 300;
|
||||
test_data.sensorReadings.emapADC = 500;
|
||||
TEST_ASSERT_TRUE(cycleMinimumMAPReading(test_data.current, test_data.page2, test_data.cycle_min, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(50U, test_data.sensorReadings.mapADC);
|
||||
|
||||
TEST_ASSERT_NOT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.cycle_min.mapMinimum);
|
||||
TEST_ASSERT_EQUAL_UINT(300, test_data.cycle_min.mapMinimum);
|
||||
TEST_ASSERT_EQUAL_UINT8(test_data.current.startRevolutions, test_data.cycle_min.cycleStartIndex);
|
||||
}
|
||||
|
||||
extern bool canUseEventAverage(const statuses ¤t, const config2 &page2);
|
||||
extern bool eventAverageMAPReading(const statuses ¤t, const config2 &page2, map_event_average_t &eventAverage, map_adc_readings_t &sensorReadings);
|
||||
|
||||
static void enable_event_average(statuses ¤t, config2 &page2) {
|
||||
current.RPMdiv100 = 43;
|
||||
page2.mapSwitchPoint = 15;
|
||||
current.startRevolutions = 55;
|
||||
current.hasSync = true;
|
||||
current.status3 = 0U;
|
||||
current.engineProtectStatus = 0U;
|
||||
}
|
||||
|
||||
static void test_canUseEventAverage(void) {
|
||||
statuses current;
|
||||
config2 page2;
|
||||
enable_event_average(current, page2);
|
||||
|
||||
TEST_ASSERT_TRUE(canUseEventAverage(current, page2));
|
||||
|
||||
current.hasSync = false;
|
||||
TEST_ASSERT_FALSE(canUseEventAverage(current, page2));
|
||||
current.hasSync = true;
|
||||
|
||||
current.startRevolutions = 1;
|
||||
TEST_ASSERT_FALSE(canUseEventAverage(current, page2));
|
||||
current.startRevolutions = 55;
|
||||
|
||||
current.RPMdiv100 = page2.mapSwitchPoint-1;
|
||||
TEST_ASSERT_FALSE(canUseEventAverage(current, page2));
|
||||
current.RPMdiv100 = page2.mapSwitchPoint;
|
||||
TEST_ASSERT_FALSE(canUseEventAverage(current, page2));
|
||||
current.RPMdiv100 = page2.mapSwitchPoint+1;
|
||||
TEST_ASSERT_TRUE(canUseEventAverage(current, page2));
|
||||
|
||||
current.engineProtectStatus = 1;
|
||||
TEST_ASSERT_FALSE(canUseEventAverage(current, page2));
|
||||
current.engineProtectStatus = 0;
|
||||
}
|
||||
|
||||
|
||||
struct eventAverageMAPReading_test_data {
|
||||
statuses current;
|
||||
config2 page2;
|
||||
map_event_average_t event_average;
|
||||
map_adc_readings_t sensorReadings;
|
||||
};
|
||||
|
||||
static void setup_event_average(eventAverageMAPReading_test_data &test_data) {
|
||||
enable_event_average(test_data.current, test_data.page2);
|
||||
test_data.event_average.eventStartIndex = 0;
|
||||
test_data.event_average.sampleCount = 0;
|
||||
test_data.event_average.mapAdcRunningTotal = 0;
|
||||
ignitionCount = 0;
|
||||
}
|
||||
|
||||
static void test_eventAverageMAPReading_fallback_instantaneous(void) {
|
||||
eventAverageMAPReading_test_data test_data;
|
||||
setup_event_average(test_data);
|
||||
|
||||
test_data.current.hasSync = false;
|
||||
test_data.sensorReadings.mapADC = 0x1234;
|
||||
test_data.sensorReadings.emapADC = 0x1234;
|
||||
|
||||
TEST_ASSERT_TRUE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.event_average.mapAdcRunningTotal);
|
||||
|
||||
// Repeat - should get same result.
|
||||
TEST_ASSERT_TRUE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.event_average.mapAdcRunningTotal);
|
||||
}
|
||||
|
||||
|
||||
static void test_eventAverageMAPReading(void) {
|
||||
eventAverageMAPReading_test_data test_data;
|
||||
setup_event_average(test_data);
|
||||
|
||||
test_data.event_average.eventStartIndex = (uint8_t)ignitionCount;
|
||||
test_data.sensorReadings.mapADC = 100;
|
||||
test_data.sensorReadings.emapADC = 200;
|
||||
// Accumulate a few samples
|
||||
TEST_ASSERT_FALSE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.event_average.mapAdcRunningTotal);
|
||||
test_data.sensorReadings.mapADC = 300;
|
||||
test_data.sensorReadings.emapADC = 500;
|
||||
TEST_ASSERT_FALSE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(2, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(400, test_data.event_average.mapAdcRunningTotal);
|
||||
test_data.sensorReadings.mapADC = 500;
|
||||
test_data.sensorReadings.emapADC = 700;
|
||||
TEST_ASSERT_FALSE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(3, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(900, test_data.event_average.mapAdcRunningTotal);
|
||||
|
||||
// Leave the current cycle
|
||||
++ignitionCount;
|
||||
TEST_ASSERT_TRUE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(900/3, test_data.sensorReadings.mapADC);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_NOT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.event_average.mapAdcRunningTotal);
|
||||
TEST_ASSERT_EQUAL_UINT(500, test_data.event_average.mapAdcRunningTotal);
|
||||
}
|
||||
|
||||
static void test_eventAverageMAPReading_nosamples(void) {
|
||||
eventAverageMAPReading_test_data test_data;
|
||||
setup_event_average(test_data);
|
||||
|
||||
test_data.event_average.eventStartIndex = (uint8_t)ignitionCount;
|
||||
test_data.sensorReadings.mapADC = 100;
|
||||
test_data.sensorReadings.emapADC = 200;
|
||||
|
||||
++ignitionCount;
|
||||
++ignitionCount;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(0, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_TRUE(eventAverageMAPReading(test_data.current, test_data.page2, test_data.event_average, test_data.sensorReadings));
|
||||
TEST_ASSERT_EQUAL_UINT(100, test_data.sensorReadings.mapADC);
|
||||
TEST_ASSERT_EQUAL_UINT(200, test_data.sensorReadings.emapADC);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT(1, test_data.event_average.sampleCount);
|
||||
TEST_ASSERT_EQUAL_UINT(test_data.sensorReadings.mapADC, test_data.event_average.mapAdcRunningTotal);
|
||||
}
|
||||
|
||||
extern uint16_t validateFilterMapSensorReading(uint16_t reading, uint8_t alpha, uint16_t prior);
|
||||
|
||||
static void test_validateFilterMapSensorReading(void) {
|
||||
TEST_ASSERT_EQUAL_UINT(0, validateFilterMapSensorReading(0, 0, 0));
|
||||
TEST_ASSERT_EQUAL_UINT(100, validateFilterMapSensorReading(0, 0, 100));
|
||||
TEST_ASSERT_EQUAL_UINT(333, validateFilterMapSensorReading(333, 0, 100));
|
||||
TEST_ASSERT_EQUAL_UINT(217, validateFilterMapSensorReading(333, 127, 100));
|
||||
}
|
||||
|
||||
void test_map_sampling(void) {
|
||||
SET_UNITY_FILENAME() {
|
||||
RUN_TEST(test_instantaneous);
|
||||
RUN_TEST(test_canUseCycleAverge);
|
||||
RUN_TEST(test_cycleAverageMAPReading_fallback_instantaneous);
|
||||
RUN_TEST(test_cycleAverageMAPReading);
|
||||
RUN_TEST(test_cycleAverageMAPReading_nosamples);
|
||||
// RUN_TEST(test_cycleMinimumMAPReading_fallback_instantaneous);
|
||||
RUN_TEST(test_cycleMinimumMAPReading);
|
||||
RUN_TEST(test_canUseEventAverage);
|
||||
RUN_TEST(test_eventAverageMAPReading_fallback_instantaneous);
|
||||
RUN_TEST(test_eventAverageMAPReading);
|
||||
RUN_TEST(test_eventAverageMAPReading_nosamples);
|
||||
RUN_TEST(test_validateFilterMapSensorReading);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue