diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 48bab1c4..0481ea76 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -949,16 +949,19 @@ page = 10 fuel2Mode = bits, U08, 122, [3:5], "Off", "Multiplied %", "Added", "Switched - Conditional", "Switched - Input based","INVALID","INVALID","INVALID" fuel2SwitchVariable = bits, U08, 122, [6:7], "RPM", "MAP", "TPS", "ETH%" fuel2SwitchValue = scalar, U16, 123, { bitStringValue(algorithmUnits, fuel2SwitchVariable) }, 1.0, 0.0, 0.0, 9000, 0 + fuel2InputPin = bits , U08, 125, [0:5], $IO_Pins_no_def + fuel2InputPolarity = bits , U08, 125, [6:6], "LOW", "HIGH" + fuel2InputPullup = bits , U08, 125, [7:7], "No", "Yes" ;All related to the closed loop VVT control - vvtCLholdDuty = scalar, U08, 125, "%", 1.0, 0.0, 0.0, 100.0, 0 - vvtCLKP = scalar, U08, 126, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) - vvtCLKI = scalar, U08, 127, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) - vvtCLKD = scalar, U08, 128, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) - vvtCLMinAng = scalar, U16, 129, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) - vvtCLMaxAng = scalar, U16, 131, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) + vvtCLholdDuty = scalar, U08, 126, "%", 1.0, 0.0, 0.0, 100.0, 0 + vvtCLKP = scalar, U08, 127, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) + vvtCLKI = scalar, U08, 128, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) + vvtCLKD = scalar, U08, 129, "%", 1.0, 0.0, 0.0, 200.0, 0 ; * ( 1 byte) + vvtCLMinAng = scalar, U16, 130, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) + vvtCLMaxAng = scalar, U16, 132, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) - unused11_122_191 = array, U08, 126, [58], "RPM", 100.0, 0.0, 100, 25500, 0 + unused11_122_191 = array, U08, 134, [57], "RPM", 100.0, 0.0, 100, 25500, 0 ;Page 11 is the fuel map and axis bins only page = 11 @@ -1676,9 +1679,20 @@ menuDialog = main panel = veTableDialog_north, North panel = veTableDialog_south, South + dialog = fuelTable2Dialog_switch, "Switch Conditions", xAxis + field = "Use secondary table when:", fuel2SwitchVariable + field = "is greater than:", fuel2SwitchValue + + dialog = fuelTable2Dialog_input, "Input Options", yAxis + field = "Use secondary table when pin", fuel2InputPin + field = "Is", fuel2InputPolarity + field = "Use internal pullup on pin", fuel2InputPullup, { fuel2InputPolarity == 0 } + dialog = fuelTable2Dialog_north, "" field = "Secondary fuel table mode", fuel2Mode field = "Load source", fuel2Algorithm, { fuel2Mode } + panel = fuelTable2Dialog_switch, { fuel2Mode == 3 } + panel = fuelTable2Dialog_input, { fuel2Mode == 4 } dialog = fuelTable2Dialog_south, "" panel = fuelTable2Tbl @@ -3197,7 +3211,7 @@ cmdtestspk450dc = "E\x03\x0C" ; you change it. ochGetCommand = "r\$tsCanId\x30%2o%2c" - ochBlockSize = 94 + ochBlockSize = 96 secl = scalar, U08, 0, "sec", 1.000, 0.000 status1 = scalar, U08, 1, "bits", 1.000, 0.000 @@ -3298,7 +3312,9 @@ cmdtestspk450dc = "E\x03\x0C" dwell = scalar, U16, 89, "ms", 0.001, 0.000 CLIdleTarget = scalar, U08, 91, "RPM", 10.00, 0.000 MAPdot = scalar, U08, 92, "kPa/s", 10.00, 0.000 - vvtAngle = scalar, U08, 93, "deg", 1.00, 0.000 + vvtAngle = scalar, S08, 93, "deg", 1.00, 0.000 + vvtTarget = scalar, U08, 94, "deg", 1.00, 0.000 + vvtDuty = scalar, U08, 95, "%", 1.00, 0.000 #if CELSIUS coolant = { coolantRaw - 40 } ; Temperature readings are offset by 40 to allow for negatives @@ -3414,6 +3430,8 @@ cmdtestspk450dc = "E\x03\x0C" entry = nitrousOn, "Nitrous", int, "onOff", { n2o_enable > 0 } entry = syncLossCounter, "Sync Loss #", int, "%d" entry = vvtAngle, "VVT Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvtTarget, "VVT Target Angle", int,"%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvtDuty, "VVT Duty", int, "%d", { vvtEnabled > 0 } entry = auxin_gauge0, "AuxIn CH0", int, "%d" entry = auxin_gauge1, "AuxIn CH1", int, "%d" diff --git a/speeduino/auxiliaries.h b/speeduino/auxiliaries.h index d1607cf3..d5a34c32 100644 --- a/speeduino/auxiliaries.h +++ b/speeduino/auxiliaries.h @@ -43,6 +43,7 @@ volatile unsigned int boost_pwm_cur_value; long boost_pwm_target_value; long boost_cl_target_boost; byte boostCounter; +byte vvtCounter; byte fanHIGH = HIGH; // Used to invert the cooling fan output byte fanLOW = LOW; // Used to invert the cooling fan output @@ -50,7 +51,9 @@ byte fanLOW = LOW; // Used to invert the cooling fan output volatile bool vvt_pwm_state; unsigned int vvt_pwm_max_count; //Used for variable PWM frequency volatile unsigned int vvt_pwm_cur_value; -long vvt_pwm_target_value; +long vvt_pwm_value; +long vvt_pid_target_angle; +//long vvt_pid_current_angle; static inline void boostInterrupt(); static inline void vvtInterrupt(); diff --git a/speeduino/auxiliaries.ino b/speeduino/auxiliaries.ino index d16f9baa..8dc63eec 100644 --- a/speeduino/auxiliaries.ino +++ b/speeduino/auxiliaries.ino @@ -11,6 +11,7 @@ A full copy of the license may be found in the projects root directory //Old PID method. Retained incase the new one has issues //integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT); integerPID_ideal boostPID(¤tStatus.MAP, ¤tStatus.boostDuty , ¤tStatus.boostTarget, &configPage10.boostSens, &configPage10.boostIntv, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call +integerPID vvtPID(¤tStatus.vvtAngle, &vvt_pwm_value, &vvt_pid_target_angle, configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call /* Fan control @@ -73,15 +74,38 @@ void initialiseAuxPWM() if(configPage10.n2o_pin_polarity == 1) { pinMode(configPage10.n2o_arming_pin, INPUT_PULLUP); } else { pinMode(configPage10.n2o_arming_pin, INPUT); } } - - ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt) boostPID.SetOutputLimits(configPage2.boostMinDuty, configPage2.boostMaxDuty); if(configPage6.boostMode == BOOST_MODE_SIMPLE) { boostPID.SetTunings(100, 100, 100); } else { boostPID.SetTunings(configPage6.boostKP, configPage6.boostKI, configPage6.boostKD); } + if( configPage6.vvtEnabled > 0) + { + currentStatus.vvtAngle = 0; + + #if defined(CORE_AVR) + vvt_pwm_max_count = 1000000L / (16 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz + #elif defined(CORE_TEENSY) + vvt_pwm_max_count = 1000000L / (32 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz + #endif + + if(configPage6.vvtMode == VVT_MODE_CLOSED_LOOP) + { + vvtPID.SetOutputLimits(0, percentage(80, vvt_pwm_max_count)); //80% is a completely arbitrary amount for the max duty cycle, but seems inline with most VVT documentation + vvtPID.SetTunings(configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD); + vvtPID.SetSampleTime(30); + vvtPID.SetMode(AUTOMATIC); //Turn PID on + } + + currentStatus.vvtDuty = 0; + vvt_pwm_value = 0; + } + ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt) + currentStatus.boostDuty = 0; boostCounter = 0; + currentStatus.vvtDuty = 0; + vvtCounter = 0; currentStatus.nitrous_status = NITROUS_OFF; @@ -166,32 +190,101 @@ void boostControl() void vvtControl() { - if( configPage6.vvtEnabled == 1 ) + if( (configPage6.vvtEnabled == 1) && (currentStatus.RPM > 0) ) { - byte vvtDuty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); + currentStatus.vvtDuty = 0; + if( (configPage6.vvtMode == VVT_MODE_OPEN_LOOP) || (configPage6.vvtMode == VVT_MODE_ONOFF) ) + { + //Lookup VVT duty based on either MAP or TPS + if(configPage6.vvtLoadSource == VVT_LOAD_TPS) + { + currentStatus.vvtDuty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); + } + else + { + currentStatus.vvtDuty = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); + } - //VVT table can be used for controlling on/off switching. If this is turned on, then disregard any interpolation or non-binary values - if( (configPage6.VVTasOnOff == true) && (vvtDuty < 100) ) { vvtDuty = 0; } + //VVT table can be used for controlling on/off switching. If this is turned on, then disregard any interpolation or non-binary values + if( (configPage6.VVTasOnOff == true) && (currentStatus.vvtDuty < 100) ) { currentStatus.vvtDuty = 0; } - if(vvtDuty == 0) + vvt_pwm_value = percentage(currentStatus.vvtDuty, vvt_pwm_max_count); + if(currentStatus.vvtDuty > 0) { ENABLE_VVT_TIMER(); } + + } //Open loop + else if( (configPage6.vvtMode == VVT_MODE_CLOSED_LOOP) ) + { + //Calculate the current cam angle + getCamAngle_Miata9905(); + + //Lookup VVT duty based on either MAP or TPS + if(configPage6.vvtLoadSource == VVT_LOAD_TPS) + { + currentStatus.vvtTargetAngle = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); + } + else + { + currentStatus.vvtTargetAngle = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); + } + + if( (vvtCounter & 31) == 1) { vvtPID.SetTunings(configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD); } //This only needs to be run very infrequently, once every 32 calls to vvtControl(). This is approx. once per second + + //Check that we're not already at the angle we want to be + if((configPage6.vvtCLUseHold > 0) && (currentStatus.vvtTargetAngle == currentStatus.vvtAngle) ) + { + currentStatus.vvtDuty = configPage10.vvtCLholdDuty; + vvt_pwm_value = percentage(currentStatus.vvtDuty, vvt_pwm_max_count); + vvtPID.Initialize(); + } + else + { + //If not already at target angle, calculate new value from PID + + //This is dumb, but need to convert the current angle into a long pointer + vvt_pid_target_angle = currentStatus.vvtTargetAngle; + + if(currentStatus.vvtTargetAngle > 0) + { + vvtPID.Compute(false); + //vvtPID.Compute2(currentStatus.vvtTargetAngle, currentStatus.vvtAngle, false); + //vvt_pwm_target_value = percentage(40, vvt_pwm_max_count); + //if (currentStatus.vvtAngle > currentStatus.vvtTargetAngle) { vvt_pwm_target_value = 0; } + currentStatus.vvtDuty = (vvt_pwm_value * 100) / vvt_pwm_max_count; + } + else + { + currentStatus.vvtDuty = 0; + } + } + + if(currentStatus.vvtDuty > 0) { ENABLE_VVT_TIMER(); } + + //currentStatus.vvtDuty = 0; + vvtCounter++; + } + + //Set the PWM state based on the above lookups + if(currentStatus.vvtDuty == 0) { //Make sure solenoid is off (0% duty) VVT_PIN_LOW(); DISABLE_VVT_TIMER(); } - else if (vvtDuty >= 100) + else if (currentStatus.vvtDuty >= 100) { //Make sure solenoid is on (100% duty) VVT_PIN_HIGH(); DISABLE_VVT_TIMER(); } - else - { - vvt_pwm_target_value = percentage(vvtDuty, vvt_pwm_max_count); - ENABLE_VVT_TIMER(); - } + } - else { DISABLE_VVT_TIMER(); } // Disable timer channel + else + { + // Disable timer channel + DISABLE_VVT_TIMER(); + currentStatus.vvtDuty = 0; + vvt_pwm_value = 0; + } } void nitrousControl() @@ -286,8 +379,8 @@ void boostDisable() else { VVT_PIN_HIGH(); // Switch pin high - VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_target_value; - vvt_pwm_cur_value = vvt_pwm_target_value; + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_value; + vvt_pwm_cur_value = vvt_pwm_value; vvt_pwm_state = true; } } diff --git a/speeduino/cancomms.ino b/speeduino/cancomms.ino index 125685a2..36105089 100644 --- a/speeduino/cancomms.ino +++ b/speeduino/cancomms.ino @@ -8,7 +8,7 @@ can_comms was originally contributed by Darren Siepka /* can_command is called when a command is received over serial3 from the Can interface It parses the command and calls the relevant function -sendcancommand is called when a comman d is to be sent via serial3 to the Can interface +sendcancommand is called when a command is to be sent via serial3 to the Can interface */ #include "globals.h" #include "cancomms.h" diff --git a/speeduino/comms.h b/speeduino/comms.h index d035f23c..900df89d 100644 --- a/speeduino/comms.h +++ b/speeduino/comms.h @@ -22,7 +22,7 @@ #define warmupPage 10 //Config Page 10 #define fuelMap2Page 11 -#define SERIAL_PACKET_SIZE 94 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ +#define SERIAL_PACKET_SIZE 96 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ byte currentPage = 1;//Not the same as the speeduino config page numbers bool isMap = true; /**< Whether or not the currentPage contains only a 3D map that would require translation */ diff --git a/speeduino/comms.ino b/speeduino/comms.ino index 862e357c..ddd1c0b3 100644 --- a/speeduino/comms.ino +++ b/speeduino/comms.ino @@ -608,7 +608,9 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum) fullStatus[90] = highByte(currentStatus.dwell); fullStatus[91] = currentStatus.CLIdleTarget; fullStatus[92] = currentStatus.mapDOT; - fullStatus[93] = currentStatus.vvtAngle; + fullStatus[93] = (int8_t)currentStatus.vvtAngle; + fullStatus[94] = currentStatus.vvtTargetAngle; + fullStatus[95] = currentStatus.vvtDuty; for(byte x=0; x + currentStatus.vvtAngle = 370 - fastTimeToAngle(lastVVTtime) - configPage10.vvtCLMinAng; + + return currentStatus.vvtAngle; +} + void triggerSetEndTeeth_Miata9905() { diff --git a/speeduino/globals.h b/speeduino/globals.h index 939ea008..0c31be0e 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -231,8 +231,8 @@ #define VVT_MODE_ONOFF 0 #define VVT_MODE_OPEN_LOOP 1 #define VVT_MODE_CLOSED_LOOP 2 -#define VVTCL_LOAD_MAP 0 -#define VVTCL_LOAD_TPS 1 +#define VVT_LOAD_MAP 0 +#define VVT_LOAD_TPS 1 #define FOUR_STROKE 0 #define TWO_STROKE 1 @@ -470,8 +470,10 @@ struct statuses { bool knockActive; bool toothLogEnabled; bool compositeLogEnabled; - byte vvtAngle; - byte targetVVTAngle; + //int8_t vvtAngle; + long vvtAngle; + byte vvtTargetAngle; + byte vvtDuty; }; struct statuses currentStatus; //The global status object @@ -946,6 +948,11 @@ struct config10 { byte fuel2SwitchVariable : 2; uint16_t fuel2SwitchValue; + //Byte 123 + byte fuel2InputPin : 6; + byte fuel2InputPolarity : 1; + byte fuel2InputPullup : 1; + byte vvtCLholdDuty; byte vvtCLKP; byte vvtCLKI; @@ -953,7 +960,7 @@ struct config10 { uint16_t vvtCLMinAng; uint16_t vvtCLMaxAng; - byte unused11_123_191[59]; + byte unused11_123_191[58]; #if defined(CORE_AVR) }; @@ -995,6 +1002,7 @@ byte pinFuelPump; //Fuel pump on/off byte pinIdle1; //Single wire idle control byte pinIdle2; //2 wire idle control (Not currently used) byte pinIdleUp; //Input for triggering Idle Up +byte pinFuel2Input; //Input for switching to the 2nd fuel table byte pinSpareTemp1; // Future use only byte pinSpareTemp2; // Future use only byte pinSpareOut1; //Generic output diff --git a/speeduino/idle.ino b/speeduino/idle.ino index ee96e6d6..07d9eb96 100644 --- a/speeduino/idle.ino +++ b/speeduino/idle.ino @@ -231,7 +231,7 @@ void idleControl() idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //Multiply the byte target value back out by 10 if( (idleCounter & 31) == 1) { idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); } //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second - idlePID.Compute(); + idlePID.Compute(true); idle_pwm_target_value = idle_pid_target_value; if( idle_pwm_target_value == 0 ) { @@ -294,7 +294,7 @@ void idleControl() currentStatus.CLIdleTarget = (byte)table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //All temps are offset by 40 degrees if(currentStatus.idleUpActive == true) { idle_pid_target_value += configPage2.idleUpAdder; } //Add Idle Up amount if active - idlePID.Compute(); + idlePID.Compute(true); idleStepper.targetIdleStep = idle_pid_target_value; doStep(); diff --git a/speeduino/init.ino b/speeduino/init.ino index 4d12df9b..62f4b325 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -1648,6 +1648,7 @@ void setPinMapping(byte boardID) if ( (configPage6.vvtPin != 0) && (configPage6.vvtPin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = pinTranslate(configPage6.vvtPin); } if ( (configPage6.useExtBaro != 0) && (configPage6.baroPin < BOARD_NR_GPIO_PINS) ) { pinBaro = configPage6.baroPin + A0; } if ( (configPage6.useEMAP != 0) && (configPage10.EMAPPin < BOARD_NR_GPIO_PINS) ) { pinEMAP = configPage10.EMAPPin + A0; } + if ( (configPage10.fuel2InputPin != 0) && (configPage10.fuel2InputPin < BOARD_NR_GPIO_PINS) ) { pinFuel2Input = pinTranslate(configPage10.fuel2InputPin); } //Currently there's no default pin for Idle Up pinIdleUp = pinTranslate(configPage2.idleUpPin); @@ -1769,6 +1770,11 @@ void setPinMapping(byte boardID) if (configPage2.idleUpPolarity == 0) { pinMode(pinIdleUp, INPUT_PULLUP); } //Normal setting else { pinMode(pinIdleUp, INPUT); } //inverted setting } + if(configPage10.fuel2Mode == FUEL2_MODE_INPUT_SWITCH) + { + if (configPage10.fuel2InputPullup == 1) { pinMode(pinfuel2Input, INPUT_PULLUP); } //Normal setting + else { pinMode(pinFuel2Input, INPUT); } //inverted setting + } //These must come after the above pinMode statements diff --git a/speeduino/sensors.ino b/speeduino/sensors.ino index 62caa7e2..50118b29 100644 --- a/speeduino/sensors.ino +++ b/speeduino/sensors.ino @@ -232,7 +232,7 @@ static inline void readMAP() //Minimum reading in a cycle if (currentStatus.RPM > 0 ) //If the engine isn't running, fall back to instantaneous reads { - if( (MAPcurRev == currentStatus.startRevolutions) || (MAPcurRev == (currentStatus.startRevolutions+1)) ) //2 revolutions are looked at for 4 stroke. 2 stroke not currently catered for. + if( (MAPcurRev == currentStatus.startRevolutions) || ((MAPcurRev+1) == currentStatus.startRevolutions) ) //2 revolutions are looked at for 4 stroke. 2 stroke not currently catered for. { #if defined(ANALOG_ISR_MAP) tempReading = AnChannel[pinMAP-A0]; diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 5e0cb1f6..32058f41 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -200,6 +200,8 @@ void loop() BIT_CLEAR(TIMER_mask, BIT_TIMER_30HZ); //Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough boostControl(); + //VVT may eventually need to be synced with the cam readings (ie run once per cam rev) but for now run at 30Hz + vvtControl(); } if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ)) { @@ -271,7 +273,6 @@ void loop() } //For loop going through each channel } //aux channels are enabled - vvtControl(); idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient. } //4Hz timer if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ)) //Once per second) @@ -290,10 +291,9 @@ void loop() BIT_CLEAR(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Clear the bit indicating that the 2nd fuel table is in use. if(configPage10.fuel2Mode > 0) { - currentStatus.VE2 = getVE2(); - if(configPage10.fuel2Mode == FUEL2_MODE_MULTIPLY) { + currentStatus.VE2 = getVE2(); //Fuel 2 table is treated as a % value. Table 1 and 2 are multiplied together and divded by 100 uint16_t combinedVE = ((uint16_t)currentStatus.VE * (uint16_t)currentStatus.VE2) / 100; if(combinedVE <= 255) { totalVE = combinedVE; } @@ -301,6 +301,7 @@ void loop() } else if(configPage10.fuel2Mode == FUEL2_MODE_ADD) { + currentStatus.VE2 = getVE2(); //Fuel tables are added together, but a check is made to make sure this won't overflow the 8-bit totalVE value uint16_t combinedVE = (uint16_t)currentStatus.VE + (uint16_t)currentStatus.VE2; if(combinedVE <= 255) { totalVE = combinedVE; } @@ -310,12 +311,44 @@ void loop() { if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_RPM) { - + if(currentStatus.RPM > configPage10.fuel2SwitchValue) + { + BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use. + currentStatus.VE2 = getVE2(); + } + } + else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_MAP) + { + if(currentStatus.MAP > configPage10.fuel2SwitchValue) + { + BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use. + currentStatus.VE2 = getVE2(); + } + } + else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_TPS) + { + if(currentStatus.TPS > configPage10.fuel2SwitchValue) + { + BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use. + currentStatus.VE2 = getVE2(); + } + } + else if(configPage10.fuel2SwitchVariable == FUEL2_CONDITION_ETH) + { + if(currentStatus.ethanolPct > configPage10.fuel2SwitchValue) + { + BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use. + currentStatus.VE2 = getVE2(); + } } } else if(configPage10.fuel2Mode == FUEL2_MODE_INPUT_SWITCH) { - + if(digitalRead(configPage10.fuel2InputPin) == configPage10.fuel2InputPolarity) + { + BIT_SET(currentStatus.status3, BIT_STATUS3_FUEL2_ACTIVE); //Set the bit indicating that the 2nd fuel table is in use. + currentStatus.VE2 = getVE2(); + } } } else { totalVE = currentStatus.VE; }