169 lines
5.1 KiB
C++
169 lines
5.1 KiB
C++
/*
|
|
* @file CJ125_logic.cpp
|
|
*
|
|
* @date Feb 1, 2019
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
|
*/
|
|
|
|
#include "cj125_logic.h"
|
|
#include "engine.h"
|
|
#include "error_handling.h"
|
|
|
|
EXTERN_ENGINE;
|
|
|
|
#define LOW_VOLTAGE "Low Voltage"
|
|
|
|
CJ125::CJ125() : wboHeaterControl("wbo"),
|
|
heaterPid(&heaterPidConfig) {
|
|
}
|
|
|
|
void CJ125::SetHeater(float value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
// limit duty cycle for sensor safety
|
|
// todo: would be much nicer to have continuous function (vBatt)
|
|
float maxDuty = (engine->sensors.vBatt > CJ125_HEATER_LIMITING_VOLTAGE) ? CJ125_HEATER_LIMITING_RATE : 1.0f;
|
|
heaterDuty = (value < CJ125_HEATER_MIN_DUTY) ? 0.0f : minF(maxF(value, 0.0f), maxDuty);
|
|
#ifdef CJ125_DEBUG
|
|
scheduleMsg(logger, "cjSetHeater: %.2f", heaterDuty);
|
|
#endif
|
|
// a little trick to disable PWM if needed.
|
|
// todo: this should be moved to wboHeaterControl.setPwmDutyCycle()
|
|
// todo: is this really needed?!
|
|
wboHeaterControl.setFrequency(heaterDuty == 0.0f ? NAN : CJ125_HEATER_PWM_FREQ);
|
|
wboHeaterControl.setSimplePwmDutyCycle(heaterDuty);
|
|
}
|
|
|
|
void CJ125::SetIdleHeater(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
// small preheat for faster start & moisture anti-shock therapy for the sensor
|
|
SetHeater(CJ125_HEATER_IDLE_RATE PASS_ENGINE_PARAMETER_SUFFIX);
|
|
}
|
|
|
|
bool CJ125::isWorkingState(void) const {
|
|
return state != CJ125_ERROR && state != CJ125_INIT && state != CJ125_IDLE;
|
|
}
|
|
|
|
void CJ125::StartHeaterControl(pwm_gen_callback *stateChangeCallback DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
// todo: use custom pin state method, turn pin off while not running
|
|
startSimplePwmExt(&wboHeaterControl, "wboHeaterPin",
|
|
&engine->executor,
|
|
CONFIG(wboHeaterPin),
|
|
&wboHeaterPin, CJ125_HEATER_PWM_FREQ, 0.0f, stateChangeCallback);
|
|
SetIdleHeater(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
}
|
|
|
|
static void printDiagCode(Logging * logging, const char *msg, int code, const char *code1message) {
|
|
switch(code & 0x3) {
|
|
case 0:
|
|
scheduleMsg(logging, "%s Short to GND", msg);
|
|
return;
|
|
case 1:
|
|
scheduleMsg(logging, "%s %s", msg, code1message);
|
|
return;
|
|
case 2:
|
|
scheduleMsg(logging, "%s Short to Vbatt", msg);
|
|
return;
|
|
case 3:
|
|
scheduleMsg(logging, "%s LOOKS GOOD", msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void CJ125::printDiag() {
|
|
if (diag == CJ125_DIAG_NORM) {
|
|
scheduleMsg(logger, "cj125: diag Looks great!");
|
|
} else {
|
|
scheduleMsg(logger, "cj125: diag NOT GOOD");
|
|
printDiagCode(logger, "VM", diag, LOW_VOLTAGE);
|
|
printDiagCode(logger, "UN", diag >> 2, LOW_VOLTAGE);
|
|
printDiagCode(logger, "IA", diag >> 4, LOW_VOLTAGE);
|
|
printDiagCode(logger, "HR", diag >> 6, "open load");
|
|
/* todo: do we want to throw CRITICAL on diag start-up error? probably not?
|
|
firmwareError(CUSTOM_ERR_CJ125_DIAG, "CJ125 is not well");
|
|
*/
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return true in case of positive SPI identification
|
|
* false in case of unexpected SPI response
|
|
*/
|
|
bool CJ125::cjIdentify(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
efiAssert(OBD_PCM_Processor_Fault, spi!= NULL, "No SPI pointer", false);
|
|
// read Ident register
|
|
int ident = spi->ReadRegister(IDENT_REG_RD) & CJ125_IDENT_MASK;
|
|
|
|
// set initial registers
|
|
spi->WriteRegister(INIT_REG1_WR, CJ125_INIT1_NORMAL_17);
|
|
spi->WriteRegister(INIT_REG2_WR, CJ125_INIT2_DIAG);
|
|
// check if regs are ok
|
|
int init1 = spi->ReadRegister(INIT_REG1_RD);
|
|
int init2 = spi->ReadRegister(INIT_REG2_RD);
|
|
|
|
diag = spi->ReadRegister(DIAG_REG_RD);
|
|
scheduleMsg(logger, "cj125: Check ident=0x%x diag=0x%x init1=0x%x init2=0x%x", ident, diag, init1, init2);
|
|
if (ident != CJ125_IDENT) {
|
|
scheduleMsg(logger, "cj125: Error! Wrong ident! Cannot communicate with CJ125!");
|
|
setError(CJ125_ERROR_WRONG_IDENT PASS_ENGINE_PARAMETER_SUFFIX);
|
|
return false;
|
|
}
|
|
if (init1 != CJ125_INIT1_NORMAL_17 || init2 != CJ125_INIT2_DIAG) {
|
|
scheduleMsg(logger, "cj125: Error! Cannot set init registers! Cannot communicate with CJ125!");
|
|
setError(CJ125_ERROR_WRONG_IDENT PASS_ENGINE_PARAMETER_SUFFIX);
|
|
return false;
|
|
}
|
|
printDiag();
|
|
return true;
|
|
}
|
|
|
|
void CJ125::cjSetMode(cj125_mode_e m) {
|
|
if (mode == m)
|
|
return;
|
|
switch (m) {
|
|
case CJ125_MODE_NORMAL_8:
|
|
spi->WriteRegister(INIT_REG1_WR, CJ125_INIT1_NORMAL_8);
|
|
amplCoeff = 1.0f / 8.0f;
|
|
break;
|
|
case CJ125_MODE_NORMAL_17:
|
|
spi->WriteRegister(INIT_REG1_WR, CJ125_INIT1_NORMAL_17);
|
|
amplCoeff = 1.0f / 17.0f;
|
|
break;
|
|
case CJ125_MODE_CALIBRATION:
|
|
spi->WriteRegister(INIT_REG1_WR, CJ125_INIT1_CALBRT);
|
|
amplCoeff = 0.0f;
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
mode = m;
|
|
}
|
|
|
|
bool CJ125::isValidState() const {
|
|
// check if controller is functioning
|
|
if (!isWorkingState())
|
|
return false;
|
|
// check if amplification is turned on
|
|
if (amplCoeff == 0.0f)
|
|
return false;
|
|
// check if UA calibration value is valid
|
|
if (vUaCal < CJ125_UACAL_MIN || vUaCal > CJ125_UACAL_MAX)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void CJ125::cjInitPid(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
if (engineConfiguration->cj125isLsu49) {
|
|
heaterPidConfig.pFactor = CJ125_PID_LSU49_P;
|
|
heaterPidConfig.iFactor = CJ125_PID_LSU49_I;
|
|
} else {
|
|
heaterPidConfig.pFactor = CJ125_PID_LSU42_P;
|
|
heaterPidConfig.iFactor = CJ125_PID_LSU42_I;
|
|
}
|
|
heaterPidConfig.dFactor = 0.0f;
|
|
heaterPidConfig.minValue = 0;
|
|
heaterPidConfig.maxValue = 1;
|
|
heaterPidConfig.offset = 0;
|
|
/**
|
|
* See hard-coded CJ125_TICK_DELAY - we run PID at 50Hz
|
|
*/
|
|
heaterPid.reset();
|
|
}
|