rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
AemXSeriesLambda.cpp
Go to the documentation of this file.
1#include "pch.h"
2#include "ego.h"
3
4#if EFI_CAN_SUPPORT || EFI_UNIT_TEST
5#include "AemXSeriesLambda.h"
6#include "wideband_firmware/for_rusefi/wideband_can.h"
7#include "rusefi_wideband.h"
8
9static constexpr uint32_t aem_base = 0x180;
10static constexpr uint32_t rusefi_base = WB_DATA_BASE_ADDR;
11// sensor transmits at 100hz, allow a frame to be missed
12static constexpr efidur_t sensor_timeout = MS2NT(3 * WBO_TX_PERIOD_MS);
13
16 0, // ID passed here doesn't matter since we override acceptFrame
17 type,
19 )
20 , m_sensorIndex(sensorIndex)
21{
22 faultCode = m_faultCode = static_cast<uint8_t>(wbo::Fault::CanSilent);// silent, initial state is "no one has spoken to us so far"
23 isValid = m_isFault = m_afrIsValid = false;
24 // wait for first rusEFI WBO standard frame with protocol version field
25 fwUnsupported = true;
26 // Do not light "FW: need update" indicator until we get some data from WBO
27 fwOutdated = false;
28}
29
33
35 // 0th sensor is 0x190 and 0x191, 1st sensor is 0x192 and 0x193
37}
38
40 // 0th sensor is 0x00000180, 1st sensor is 0x00000181, etc
42}
43
44bool AemXSeriesWideband::acceptFrame(const size_t busIndex, const CANRxFrame& frame) const {
45#if !EFI_UNIT_TEST
46 if (busIndex != getWidebandBus()) {
47 return false;
48 }
49#endif
50
51 if (frame.DLC != 8) {
52 return false;
53 }
54
56
57 if (type == DISABLED) {
58 return false;
59 }
60
61 // RusEFI wideband uses standard CAN IDs
62 if ((!CAN_ISX(frame)) && (type == RUSEFI)) {
63 // 0th sensor is 0x190 and 0x191, 1st sensor is 0x192 and 0x193
64 uint32_t rusefiBaseId = getReCanId();
65 return ((CAN_SID(frame) == rusefiBaseId) || (CAN_SID(frame) == rusefiBaseId + 1));
66 }
67
68 // AEM uses extended CAN ID
69 if ((CAN_ISX(frame)) && (type == AEM)) {
70 // 0th sensor is 0x00000180, 1st sensor is 0x00000181, etc
71 uint32_t aemXSeriesId = getAemCanId();
72 return (CAN_EID(frame) == aemXSeriesId);
73 }
74
75 return false;
76}
77
81
84
86 faultCode = static_cast<uint8_t>(wbo::Fault::CanSilent);
87 isValid = false;
88 return;
89 }
90
91 if (type == RUSEFI) {
92 // This is RE WBO
93 if (!isHeaterAllowed()) {
94 faultCode = static_cast<uint8_t>(wbo::Fault::NotAllowed);
95 isValid = false;
96 // Do not check for any errors while heater is not allowed
97 return;
98 }
99
101 if (m_faultCode != static_cast<uint8_t>(wbo::Fault::None)) {
102 // Report error code from WBO
104 isValid = false;
105 return;
106 }
107 } else if (type == AEM) {
108 // This is AEM with two flags only and no debug fields
109 heaterDuty = 0;
110 pumpDuty = 0;
111 tempC = 0;
112 nernstVoltage = 0;
113
115 if (m_isFault) {
116 faultCode = HACK_INVALID_AEM;
117 isValid = false;
118 return;
119 }
120 } else {
121 // disabled or analog
122 // clear all livedata
123 heaterDuty = 0;
124 pumpDuty = 0;
125 tempC = 0;
126 nernstVoltage = 0;
127 isValid = false;
128 return;
129 }
130
131 faultCode = static_cast<uint8_t>(wbo::Fault::None);
132}
133
134void AemXSeriesWideband::decodeFrame(const CANRxFrame& frame, efitick_t nowNt) {
135 bool accepted = false;
136 // accept frame has already guaranteed that this message belongs to us
137 // We just have to check if it's AEM or rusEFI
138 if (sensorType() == RUSEFI){
139 uint32_t id = CAN_ID(frame);
140
141 // rusEFI custom format
142 if ((id & 0x1) != 0) {
143 // low bit is set, this is the "diag" frame
144 decodeRusefiDiag(frame);
145 } else {
146 // low bit not set, this is standard frame
147 accepted = decodeRusefiStandard(frame, nowNt);
148 }
149 } else /* if (sensorType() == AEM) */ {
150 accepted = decodeAemXSeries(frame, nowNt);
151 }
152
153 if (accepted) {
154 m_lastUpdate = nowNt;
155 }
156
157 // Do refresh on each CAN packet
158 refreshState();
159}
160
161/**
162 * @return true if valid, false if invalid
163 */
164bool AemXSeriesWideband::decodeAemXSeries(const CANRxFrame& frame, efitick_t nowNt) {
165 // we don't care
166 fwUnsupported = false;
167 fwOutdated = false;
168
169 // reports in 0.0001 lambda per LSB
170 uint16_t lambdaInt = SWAP_UINT16(frame.data16[0]);
171 float lambdaFloat = 0.0001f * lambdaInt;
172
173 // bit 6 indicates sensor fault
174 m_isFault = frame.data8[7] & 0x40;
175 // bit 7 indicates valid
176 m_afrIsValid = frame.data8[6] & 0x80;
177
178 if ((m_isFault) || (!m_afrIsValid)) {
179 invalidate();
180 return false;
181 }
182
183 setValidValue(lambdaFloat, nowNt);
184 refreshSmoothedLambda(lambdaFloat);
185 return true;
186}
187
188bool AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t nowNt) {
189 auto data = reinterpret_cast<const wbo::StandardData*>(&frame.data8[0]);
190
191 if (data->Version > RUSEFI_WIDEBAND_VERSION) {
192 firmwareError(ObdCode::OBD_WB_FW_Mismatch, "Wideband controller index %d has newer protocol version (0x%02x while 0x%02x supported), please update ECU FW!",
193 m_sensorIndex, data->Version, RUSEFI_WIDEBAND_VERSION);
194 fwUnsupported = true;
195 return false;
196 }
197
198 if (data->Version < RUSEFI_WIDEBAND_VERSION_MIN) {
199 firmwareError(ObdCode::OBD_WB_FW_Mismatch, "Wideband controller index %d has outdated protocol version (0x%02x while minimum 0x%02x expected), please update WBO!",
200 m_sensorIndex, data->Version, RUSEFI_WIDEBAND_VERSION_MIN);
201 fwUnsupported = true;
202 return false;
203 }
204
205 fwUnsupported = false;
206 // compatible, but not latest
207 fwOutdated = (data->Version != RUSEFI_WIDEBAND_VERSION);
208 // TODO: request and check builddate
209
210 tempC = data->TemperatureC;
211 float lambda = 0.0001f * data->Lambda;
212 m_afrIsValid = data->Valid & 0x01;
213
214 if (!m_afrIsValid) {
215 invalidate();
216 } else {
217 setValidValue(lambda, nowNt);
218 refreshSmoothedLambda(lambda);
219 }
220
221 return true;
222}
223
240
242 if (fwUnsupported) {
243 return;
244 }
245
246 auto data = reinterpret_cast<const wbo::DiagData*>(&frame.data8[0]);
247
248 // convert to percent
249 heaterDuty = data->HeaterDuty / 2.55f;
250 pumpDuty = data->PumpDuty / 2.55f;
251
252 // convert to volts
253 nernstVoltage = data->NernstDc * 0.001f;
254
255 // no conversion, just ohms
256 esr = data->Esr;
257
258 // This state is handle in refreshState()
259 //if (!isHeaterAllowed()) {
260 // m_faultCode = HACK_CRANKING_VALUE;
261 // return;
262 //}
263
264 m_faultCode = static_cast<uint8_t>(data->Status);
265
266 if ((data->Status != wbo::Fault::None) && isHeaterAllowed()) {
268 warning(code, "Wideband #%d fault: %s", (m_sensorIndex + 1), wbo::describeFault(data->Status));
269 }
270}
271
272#endif
static constexpr uint32_t aem_base
static constexpr uint32_t rusefi_base
static constexpr efidur_t sensor_timeout
uint8_t code
Definition bluetooth.cpp:40
void decodeRusefiDiag(const CANRxFrame &frame)
bool acceptFrame(const size_t busIndex, const CANRxFrame &frame) const override final
void refreshSmoothedLambda(float lambda)
bool decodeRusefiStandard(const CANRxFrame &frame, efitick_t nowNt)
can_wbo_type_e sensorType() const
uint32_t getAemCanId() const
AemXSeriesWideband(uint8_t sensorIndex, SensorType type)
uint32_t getReCanId() const
bool decodeAemXSeries(const CANRxFrame &frame, efitick_t nowNt)
const uint8_t m_sensorIndex
void decodeFrame(const CANRxFrame &frame, efitick_t nowNt) override
EngineState engineState
Definition engine.h:344
void setSmoothingFactor(float p_smoothingFactor)
Definition exp_average.h:26
float initOrAverage(float value)
Definition exp_average.h:9
SensorType type() const
Definition sensor.h:162
void setValidValue(float value, efitick_t timestamp)
uint16_t SWAP_UINT16(uint16_t x)
Definition efilib.h:22
efitick_t getTimeNowNt()
Definition efitime.cpp:19
StoredValueSensor smoothedLambda2Sensor(SensorType::SmoothedLambda2, MS2NT(500))
ExpAverage expAverageLambda2
Definition ego.cpp:13
StoredValueSensor smoothedLambda1Sensor(SensorType::SmoothedLambda1, MS2NT(500))
ExpAverage expAverageLambda1
Definition ego.cpp:12
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
bool warning(ObdCode code, const char *fmt,...)
void firmwareError(ObdCode code, const char *fmt,...)
@ OBD_WB_FW_Mismatch
@ Wideband_2_Fault
@ Wideband_1_Fault
can_wbo_type_e
efitick_t efidur_t
size_t getWidebandBus()
SensorType
Definition sensor_type.h:18
uint8_t data8[8]
Frame data.
Definition can_mocks.h:55
uint16_t data16[4]
Frame data.
Definition can_mocks.h:56
uint8_t DLC
Data length.
Definition can_mocks.h:42
scaled_channel< uint16_t, 1000, 1 > nernstVoltage