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 hasSeenRx = true;
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_stateCode = HACK_CRANKING_VALUE;
261 // return;
262 //}
263
264 m_stateCode = static_cast<uint8_t>(data->status);
265
266 if ((isStatusError(static_cast<wbo::Status>(data->status))) && isHeaterAllowed()) {
268 warning(code, "Wideband #%d fault: %s", (m_sensorIndex + 1), wbo::describeStatus(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: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:166
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:415
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