rusefi/firmware/controllers/serial/serial_sensor.cpp

189 lines
5.5 KiB
C++

/**
* @file serial_sensor.cpp
*
*
* @date Mar 19, 2020
* @author Konstantin Smola, (c) 2020
*/
#include "pch.h"
#if EFI_AUX_SERIAL
#include "serial.h"
#include "serial_sensor.h"
#define NUM_INNOVATE_O2_SENSORS 1
#define AFR_MULTIPLIER 147
volatile float InnovateLC2AFR = AFR_ERROR;
typedef enum
{
NO_ERROR = 0,
HEATER_SHORTED = 1,
HEATER_OPEN = 2,
PUMPCELL_SHORTED = 3,
PUMPCELL_OPEN = 4,
REFCELL_SHORTED = 5,
REFCELL_OPEN = 6,
SYSTEM_ERROR = 7,
SENSOR_TIMING_ERR = 8,
SUPP_V_LOW = 9
} sensor_error_code_t;
struct sensor_data_t {
int function_code;
float AFR;
float AFR_multiplier;
float lambda;
float warmup;
sensor_error_code_t error_code;
};
static sensor_data_t innovate_o2_sensor[NUM_INNOVATE_O2_SENSORS];
static size_t tmsglen;
void IdentifyInnovateSerialMsg() { //this identifies an innovate LC1/LC2 o2 sensor by it's first word (header)
if (engineConfiguration->enableInnovateLC2) {
if ((((ser_buffer[0]) & lc2_header_mask) != lc2_header_mask) && innovate_serial_id_state == IDENTIFIED) { //not serial header word
innovate_serial_id_state = UNKNOWN;
innovate_msg_len = 1;
sb = 0;
}
switch (innovate_serial_id_state) {
case UNKNOWN:
InnovateLC2AFR = AFR_ERROR;
// read one byte, identify with mask, advance and read next byte
if (((ser_buffer[0]) & lc2_header_mask) == lc2_header_mask) { // check if it's the first byte of header
// first byte identified, now continue reading and advance statemachine
innovate_serial_id_state = HEADER_FOUND;
innovate_msg_len = 1;
sb = 1;
} else {
innovate_serial_id_state = UNKNOWN;
}
break;
case HEADER_FOUND:
// now we should have both header bytes in array, and we can read the total packet length
tmsglen = (((ser_buffer[0] << 8) | ser_buffer[1]) & lc2_pcklen_mask); //0000000101111111 mask
if (tmsglen) {
tmsglen += 1; // length in words including header (2 bytes)
tmsglen *= 2; // length in bytes (incl header)
innovate_msg_len = tmsglen - 2;
sb = 2;
innovate_serial_id_state = IDENTIFIED; //advance state machine
} else {
innovate_serial_id_state = UNKNOWN;
}
break;
case IDENTIFIED:
innovate_msg_len = tmsglen;
sb = 0;
// serial packet fully identified
ParseInnovateSerialMsg(); //takes about 570ns
clear_ser_buffer = true;
break;
default:
break;
}
}
}
void ParseInnovateSerialMsg() {
float raw_afr;
//get error code and afr
// 000 Lambda valid and Aux data valid, normal operation.
// 001 Lambda value contains O2 level in 1/10%
// 010 Free air Calib in progress, Lambda data not valid
// 011 Need Free air Calibration Request, Lambda data not valid
// 100 Warming up, Lambda value is temp in 1/10% of operating temp.
// 101 Heater Calibration, Lambda value contains calibration countdown.
// 110 Error code in Lambda value
// 111 reserved
for (size_t i = 0; i < ((tmsglen - 2) / 4) && i < NUM_INNOVATE_O2_SENSORS; i++) {
innovate_o2_sensor[i].function_code = (ser_buffer[2 + i * 4] >> 2 & 0x7);
// innovate_o2_sensor[i].AFR_multiplier = ((ser_buffer[2 + i * 4] << 7 | ser_buffer[3 + i * 4]) & 0xFF);
innovate_o2_sensor[i].AFR_multiplier = AFR_MULTIPLIER;
switch (innovate_o2_sensor[i].function_code) {
case 0: //Lambda valid and aux data valid, normal operation
case 1: //Lambda value contains o2 level in 1/10%
innovate_o2_sensor[i].lambda = ((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
raw_afr = ((innovate_o2_sensor[i].lambda + 500) * innovate_o2_sensor[i].AFR_multiplier);
if (innovate_o2_sensor[i].function_code) {//case 1
innovate_o2_sensor[i].AFR = raw_afr * 0.001;
} else { // case 0
innovate_o2_sensor[i].AFR = raw_afr * 0.0001;
}
if (innovate_o2_sensor[i].AFR > AFRMAX) {
innovate_o2_sensor[i].AFR = AFRMAX;
} else if (innovate_o2_sensor[i].AFR < AFRMIN) {
innovate_o2_sensor[i].AFR = AFRMIN;
}
InnovateLC2AFR = innovate_o2_sensor[0].AFR; //only using one sensor right now
break;
// this is invalid o2 data, so we can ignore it:
// case 2: // Free air Calib in progress, Lambda data not valid
// break;
// case 3: // Need Free air Calibration Request, Lambda data not valid
// break;
case 4: // Warming up, Lambda value is temp in 1/10% of operating temp
InnovateLC2AFR = AFR_ERROR;
innovate_o2_sensor[i].warmup = ((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
//catch potential overflow:
if (innovate_o2_sensor[i].warmup >= 1023) {
innovate_o2_sensor[i].warmup = 1023;
} else if (innovate_o2_sensor[i].warmup <= 0) {
innovate_o2_sensor[i].warmup = 0;
}
break;
// case 5: // Heater Calibration, Lambda value contains calibration countdown
// break;
case 6: // Error code in Lambda value
InnovateLC2AFR = AFR_ERROR;
innovate_o2_sensor[i].error_code = (sensor_error_code_t)((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
//catch potential overflow:
if (innovate_o2_sensor[i].error_code >= (sensor_error_code_t)1023) {
innovate_o2_sensor[i].error_code = (sensor_error_code_t)1023;
} else if (innovate_o2_sensor[i].error_code <= 0) {
innovate_o2_sensor[i].error_code = (sensor_error_code_t)0;
}
break;
// case 7: // reserved
// break;
default:
InnovateLC2AFR = AFR_ERROR;
break;
}
}
}
void ResetSerialSensor() {
ClearSerialBuffer();
ParseSerialData();
}
void ClearSerialBuffer() {
memset(ser_buffer, 0, sizeof(ser_buffer));
}
void ParseSerialData() {
if (engineConfiguration->enableInnovateLC2)
IdentifyInnovateSerialMsg();
}
#endif