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 stateCode = m_stateCode = static_cast<uint8_t>(wbo::Status::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
85 // Report ECU to WBO allow state
88 canSilent = true;
89 isValid = false;
90 return;
91 }
92 canSilent = false;
93
94 if (type == RUSEFI) {
95 // This is RE WBO
97 // Report state code from WBO
99 return;
100 } else if (type == AEM) {
101 // This is AEM with two flags only and no debug fields
102 heaterDuty = 0;
103 pumpDuty = 0;
104 tempC = 0;
105 nernstVoltage = 0;
106
107 if (m_isFault) {
108 stateCode = HACK_INVALID_AEM;
109 isValid = false;
110 } else {
111 // TODO: better status code?
113 static_cast<uint8_t>(wbo::Status::RunningClosedLoop) :
114 static_cast<uint8_t>(wbo::Status::Warmup);
116 }
117 return;
118 } else {
119 // disabled or analog
120 // clear all livedata
121 heaterDuty = 0;
122 pumpDuty = 0;
123 tempC = 0;
124 nernstVoltage = 0;
125 isValid = false;
126 return;
127 }
128
129 // non configured
130 stateCode = static_cast<uint8_t>(wbo::Status::CanSilent);
131}
132
133void AemXSeriesWideband::decodeFrame(const CANRxFrame& frame, efitick_t nowNt) {
134 bool accepted = false;
135 // accept frame has already guaranteed that this message belongs to us
136 // We just have to check if it's AEM or rusEFI
137 if (sensorType() == RUSEFI){
138 uint32_t id = CAN_ID(frame);
139
140 // rusEFI custom format
141 if ((id & 0x1) != 0) {
142 // low bit is set, this is the "diag" frame
143 decodeRusefiDiag(frame);
144 } else {
145 // low bit not set, this is standard frame
146 accepted = decodeRusefiStandard(frame, nowNt);
147 }
148 } else /* if (sensorType() == AEM) */ {
149 accepted = decodeAemXSeries(frame, nowNt);
150 }
151
152 if (accepted) {
153 m_lastUpdate = nowNt;
154 }
155
156 // Do refresh on each CAN packet
157 refreshState();
158}
159
160/**
161 * @return true if valid, false if invalid
162 */
163bool AemXSeriesWideband::decodeAemXSeries(const CANRxFrame& frame, efitick_t nowNt) {
164 // we don't care
165 fwUnsupported = false;
166 fwOutdated = false;
167
168 // reports in 0.0001 lambda per LSB
169 uint16_t lambdaInt = SWAP_UINT16(frame.data16[0]);
170 float lambdaFloat = 0.0001f * lambdaInt;
171
172 // bit 6 indicates sensor fault
173 m_isFault = frame.data8[7] & 0x40;
174 // bit 7 indicates valid
175 m_afrIsValid = frame.data8[6] & 0x80;
176
177 if ((m_isFault) || (!m_afrIsValid)) {
178 invalidate();
179 return false;
180 }
181
182 setValidValue(lambdaFloat, nowNt);
183 refreshSmoothedLambda(lambdaFloat);
184 return true;
185}
186
187bool AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t nowNt) {
188 auto data = reinterpret_cast<const wbo::StandardData*>(&frame.data8[0]);
189
190 if (data->Version > RUSEFI_WIDEBAND_VERSION) {
191 firmwareError(ObdCode::OBD_WB_FW_Mismatch, "Wideband controller index %d has newer protocol version (0x%02x while 0x%02x supported), please update ECU FW!",
192 m_sensorIndex, data->Version, RUSEFI_WIDEBAND_VERSION);
193 fwUnsupported = true;
194 return false;
195 }
196
197 if (data->Version < RUSEFI_WIDEBAND_VERSION_MIN) {
198 firmwareError(ObdCode::OBD_WB_FW_Mismatch, "Wideband controller index %d has outdated protocol version (0x%02x while minimum 0x%02x expected), please update WBO!",
199 m_sensorIndex, data->Version, RUSEFI_WIDEBAND_VERSION_MIN);
200 fwUnsupported = true;
201 return false;
202 }
203
204 fwUnsupported = false;
205 // compatible, but not latest
206 fwOutdated = (data->Version != RUSEFI_WIDEBAND_VERSION);
207 // TODO: request and check builddate
208
209 tempC = data->TemperatureC;
210 float lambda = 0.0001f * data->Lambda;
211 m_afrIsValid = data->Valid & 0x01;
212
213 if (!m_afrIsValid) {
214 invalidate();
215 } else {
216 setValidValue(lambda, nowNt);
217 refreshSmoothedLambda(lambda);
218 }
219
220 return true;
221}
222
239
241 if (fwUnsupported) {
242 return;
243 }
244
245 auto data = reinterpret_cast<const wbo::DiagData*>(&frame.data8[0]);
246
247 // convert to percent
248 heaterDuty = data->HeaterDuty / 2.55f;
249 pumpDuty = data->PumpDuty / 2.55f;
250
251 // convert to volts
252 nernstVoltage = data->NernstDc * 0.001f;
253
254 // no conversion, just ohms
255 esr = data->Esr;
256
257 // This state is handle in refreshState()
258 //if (!isHeaterAllowed()) {
259 // m_stateCode = HACK_CRANKING_VALUE;
260 // return;
261 //}
262
263 m_stateCode = static_cast<uint8_t>(data->status);
264
265 if ((isStatusError(static_cast<wbo::Status>(data->status))) && isHeaterAllowed()) {
267 warning(code, "Wideband #%d fault: %s", (m_sensorIndex + 1), wbo::describeStatus(data->status));
268 }
269}
270
271#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:352
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:421
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