rusEFI
The most advanced open source ECU
serial_sensor.cpp
Go to the documentation of this file.
1 /**
2  * @file serial_sensor.cpp
3  *
4  *
5  * @date Mar 19, 2020
6  * @author Konstantin Smola, (c) 2020
7  */
8 
9 #include "pch.h"
10 
11 #if EFI_AUX_SERIAL
12 #include "serial.h"
13 #include "serial_sensor.h"
14 
15 #define NUM_INNOVATE_O2_SENSORS 1
16 #define AFR_MULTIPLIER 147
17 
18 volatile float InnovateLC2AFR = AFR_ERROR;
19 
20 typedef enum
21 {
22  NO_ERROR = 0,
31  SUPP_V_LOW = 9
33 
34 struct sensor_data_t {
35  int function_code;
36  float AFR;
37  float AFR_multiplier;
38  float lambda;
39  float warmup;
40  sensor_error_code_t error_code;
41 };
42 
43 static sensor_data_t innovate_o2_sensor[NUM_INNOVATE_O2_SENSORS];
44 
45 static size_t tmsglen;
46 
47 void IdentifyInnovateSerialMsg() { //this identifies an innovate LC1/LC2 o2 sensor by it's first word (header)
49  if ((((ser_buffer[0]) & lc2_header_mask) != lc2_header_mask) && innovate_serial_id_state == IDENTIFIED) { //not serial header word
51  innovate_msg_len = 1;
52  sb = 0;
53  }
54 
55  switch (innovate_serial_id_state) {
56  case UNKNOWN:
57  InnovateLC2AFR = AFR_ERROR;
58  // read one byte, identify with mask, advance and read next byte
59  if (((ser_buffer[0]) & lc2_header_mask) == lc2_header_mask) { // check if it's the first byte of header
60  // first byte identified, now continue reading and advance statemachine
62  innovate_msg_len = 1;
63  sb = 1;
64  } else {
66  }
67  break;
68 
69  case HEADER_FOUND:
70  // now we should have both header bytes in array, and we can read the total packet length
71  tmsglen = (((ser_buffer[0] << 8) | ser_buffer[1]) & lc2_pcklen_mask); //0000000101111111 mask
72 
73  if (tmsglen) {
74  tmsglen += 1; // length in words including header (2 bytes)
75  tmsglen *= 2; // length in bytes (incl header)
77  sb = 2;
78  innovate_serial_id_state = IDENTIFIED; //advance state machine
79  } else {
81  }
82 
83  break;
84 
85  case IDENTIFIED:
87  sb = 0;
88  // serial packet fully identified
89  ParseInnovateSerialMsg(); //takes about 570ns
90  clear_ser_buffer = true;
91  break;
92 
93  default:
94  break;
95  }
96  }
97 }
98 
100  float raw_afr;
101  //get error code and afr
102 
103  // 000 Lambda valid and Aux data valid, normal operation.
104  // 001 Lambda value contains O2 level in 1/10%
105  // 010 Free air Calib in progress, Lambda data not valid
106  // 011 Need Free air Calibration Request, Lambda data not valid
107  // 100 Warming up, Lambda value is temp in 1/10% of operating temp.
108  // 101 Heater Calibration, Lambda value contains calibration countdown.
109  // 110 Error code in Lambda value
110  // 111 reserved
111 
112  for (size_t i = 0; i < ((tmsglen - 2) / 4) && i < NUM_INNOVATE_O2_SENSORS; i++) {
113  innovate_o2_sensor[i].function_code = (ser_buffer[2 + i * 4] >> 2 & 0x7);
114  // innovate_o2_sensor[i].AFR_multiplier = ((ser_buffer[2 + i * 4] << 7 | ser_buffer[3 + i * 4]) & 0xFF);
115  innovate_o2_sensor[i].AFR_multiplier = AFR_MULTIPLIER;
116 
117  switch (innovate_o2_sensor[i].function_code) {
118  case 0: //Lambda valid and aux data valid, normal operation
119  case 1: //Lambda value contains o2 level in 1/10%
120  innovate_o2_sensor[i].lambda = ((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
121  raw_afr = ((innovate_o2_sensor[i].lambda + 500) * innovate_o2_sensor[i].AFR_multiplier);
122 
123  if (innovate_o2_sensor[i].function_code) {//case 1
124  innovate_o2_sensor[i].AFR = raw_afr * 0.001;
125  } else { // case 0
126  innovate_o2_sensor[i].AFR = raw_afr * 0.0001;
127  }
128 
129  if (innovate_o2_sensor[i].AFR > AFRMAX) {
130  innovate_o2_sensor[i].AFR = AFRMAX;
131  } else if (innovate_o2_sensor[i].AFR < AFRMIN) {
132  innovate_o2_sensor[i].AFR = AFRMIN;
133  }
134 
135  InnovateLC2AFR = innovate_o2_sensor[0].AFR; //only using one sensor right now
136 
137  break;
138  // this is invalid o2 data, so we can ignore it:
139  // case 2: // Free air Calib in progress, Lambda data not valid
140  // break;
141  // case 3: // Need Free air Calibration Request, Lambda data not valid
142  // break;
143  case 4: // Warming up, Lambda value is temp in 1/10% of operating temp
144  InnovateLC2AFR = AFR_ERROR;
145  innovate_o2_sensor[i].warmup = ((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
146  //catch potential overflow:
147  if (innovate_o2_sensor[i].warmup >= 1023) {
148  innovate_o2_sensor[i].warmup = 1023;
149  } else if (innovate_o2_sensor[i].warmup <= 0) {
150  innovate_o2_sensor[i].warmup = 0;
151  }
152  break;
153  // case 5: // Heater Calibration, Lambda value contains calibration countdown
154  // break;
155  case 6: // Error code in Lambda value
156  InnovateLC2AFR = AFR_ERROR;
157  innovate_o2_sensor[i].error_code = (sensor_error_code_t)((ser_buffer[4 + i * 4] << 7 | ser_buffer[5 + i * 4]) & 0x1FFF);
158  //catch potential overflow:
159  if (innovate_o2_sensor[i].error_code >= (sensor_error_code_t)1023) {
160  innovate_o2_sensor[i].error_code = (sensor_error_code_t)1023;
161  } else if (innovate_o2_sensor[i].error_code <= 0) {
162  innovate_o2_sensor[i].error_code = (sensor_error_code_t)0;
163  }
164  break;
165  // case 7: // reserved
166  // break;
167  default:
168  InnovateLC2AFR = AFR_ERROR;
169  break;
170  }
171  }
172 }
173 
176  ParseSerialData();
177 }
178 
180  memset(ser_buffer, 0, sizeof(ser_buffer));
181 }
182 
186 }
187 
188 #endif
engine_configuration_s * engineConfiguration
size_t innovate_msg_len
Definition: serial_rx.cpp:20
@ UNKNOWN
Definition: serial.h:21
@ HEADER_FOUND
Definition: serial.h:21
@ IDENTIFIED
Definition: serial.h:21
uint8_t sb
Definition: serial_rx.cpp:22
constexpr uint8_t lc2_header_mask
Definition: serial.h:18
bool clear_ser_buffer
Definition: serial_rx.cpp:23
innovate_serial_id_state_t innovate_serial_id_state
Definition: serial_rx.cpp:21
uint8_t ser_buffer[SERBUFFLEN]
Definition: serial_rx.cpp:19
constexpr uint16_t lc2_pcklen_mask
Definition: serial.h:19
void ParseInnovateSerialMsg()
static sensor_data_t innovate_o2_sensor[NUM_INNOVATE_O2_SENSORS]
void IdentifyInnovateSerialMsg()
volatile float InnovateLC2AFR
void ResetSerialSensor()
void ParseSerialData()
sensor_error_code_t
@ REFCELL_SHORTED
@ SENSOR_TIMING_ERR
@ HEATER_OPEN
@ PUMPCELL_OPEN
@ SUPP_V_LOW
@ SYSTEM_ERROR
@ PUMPCELL_SHORTED
@ NO_ERROR
@ HEATER_SHORTED
@ REFCELL_OPEN
static size_t tmsglen
void ClearSerialBuffer()