rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
Public Member Functions | Data Fields | Protected Member Functions | Private Member Functions | Private Attributes
AemXSeriesWideband Class Reference

#include <AemXSeriesLambda.h>

Inheritance diagram for AemXSeriesWideband:
Inheritance graph
[legend]
Collaboration diagram for AemXSeriesWideband:
Collaboration graph
[legend]

Public Member Functions

 AemXSeriesWideband (uint8_t sensorIndex, SensorType type)
 
bool acceptFrame (const size_t busIndex, const CANRxFrame &frame) const override final
 
void refreshState (void)
 
void refreshSmoothedLambda (float lambda)
 
- Public Member Functions inherited from CanSensorBase
 CanSensorBase (uint32_t eid, SensorType type, efidur_t timeout)
 
void showInfo (const char *sensorName) const override
 
- Public Member Functions inherited from StoredValueSensor
SensorResult get () const final override
 
 StoredValueSensor (SensorType type, efidur_t timeoutNt)
 
void invalidate ()
 
void invalidate (UnexpectedCode why)
 
void setValidValue (float value, efitick_t timestamp)
 
void showInfo (const char *sensorName) const override
 
virtual void setTimeout (int timeoutMs)
 
- Public Member Functions inherited from Sensor
bool Register ()
 
const chargetSensorName () const
 
virtual bool hasSensor () const
 
virtual float getRaw () const
 
virtual bool isRedundant () const
 
void unregister ()
 
SensorType type () const
 
- Public Member Functions inherited from CanListener
 CanListener (uint32_t id)
 
CanListenerprocessFrame (const size_t busIndex, const CANRxFrame &frame, efitick_t nowNt)
 
uint32_t getId ()
 
void setNext (CanListener *next)
 
virtual CanListenerrequest ()
 
CanListenergetNext () const
 

Data Fields

bool hasSeenRx = false
 
- Data Fields inherited from wideband_state_s
uint8_t stateCode = (uint8_t)0
 
uint8_t heaterDuty = (uint8_t)0
 
uint8_t pumpDuty = (uint8_t)0
 
uint8_t alignmentFill_at_3 [1] = {}
 
bool isValid: 1 {}
 
bool canSilent: 1 {}
 
bool allowed: 1 {}
 
bool fwUnsupported: 1 {}
 
bool fwOutdated: 1 {}
 
bool unusedBit_9_5: 1 {}
 
bool unusedBit_9_6: 1 {}
 
bool unusedBit_9_7: 1 {}
 
bool unusedBit_9_8: 1 {}
 
bool unusedBit_9_9: 1 {}
 
bool unusedBit_9_10: 1 {}
 
bool unusedBit_9_11: 1 {}
 
bool unusedBit_9_12: 1 {}
 
bool unusedBit_9_13: 1 {}
 
bool unusedBit_9_14: 1 {}
 
bool unusedBit_9_15: 1 {}
 
bool unusedBit_9_16: 1 {}
 
bool unusedBit_9_17: 1 {}
 
bool unusedBit_9_18: 1 {}
 
bool unusedBit_9_19: 1 {}
 
bool unusedBit_9_20: 1 {}
 
bool unusedBit_9_21: 1 {}
 
bool unusedBit_9_22: 1 {}
 
bool unusedBit_9_23: 1 {}
 
bool unusedBit_9_24: 1 {}
 
bool unusedBit_9_25: 1 {}
 
bool unusedBit_9_26: 1 {}
 
bool unusedBit_9_27: 1 {}
 
bool unusedBit_9_28: 1 {}
 
bool unusedBit_9_29: 1 {}
 
bool unusedBit_9_30: 1 {}
 
bool unusedBit_9_31: 1 {}
 
uint16_t tempC = (uint16_t)0
 
scaled_channel< uint16_t, 1000, 1 > nernstVoltage = (uint16_t)0
 
uint16_t esr = (uint16_t)0
 
uint8_t alignmentFill_at_14 [2] = {}
 

Protected Member Functions

void decodeFrame (const CANRxFrame &frame, efitick_t nowNt) override
 
bool decodeAemXSeries (const CANRxFrame &frame, efitick_t nowNt)
 
bool decodeRusefiStandard (const CANRxFrame &frame, efitick_t nowNt)
 
void decodeRusefiDiag (const CANRxFrame &frame)
 
- Protected Member Functions inherited from Sensor
 Sensor (SensorType type)
 

Private Member Functions

can_wbo_type_e sensorType () const
 
uint32_t getReCanId () const
 
uint32_t getAemCanId () const
 
bool isHeaterAllowed ()
 

Private Attributes

const uint8_t m_sensorIndex
 
uint8_t m_stateCode
 
bool m_afrIsValid
 
bool m_isFault
 
efitick_t m_lastUpdate = 0
 

Additional Inherited Members

- Static Public Member Functions inherited from Sensor
static void showAllSensorInfo ()
 
static void showInfo (SensorType type)
 
static void resetRegistry ()
 
static const SensorgetSensorOfType (SensorType type)
 
static SensorResult get (SensorType type)
 
static float getOrZero (SensorType type)
 
static float getRaw (SensorType type)
 
static bool isRedundant (SensorType type)
 
static bool hasSensor (SensorType type)
 
static void setMockValue (SensorType type, float value, bool mockRedundant=false)
 
static void setInvalidMockValue (SensorType type)
 
static void resetMockValue (SensorType type)
 
static void resetAllMocks ()
 
static void inhibitTimeouts (bool inhibit)
 
static const chargetSensorName (SensorType type)
 
- Static Protected Attributes inherited from Sensor
static bool s_inhibitSensorTimeouts = false
 

Detailed Description

Definition at line 16 of file AemXSeriesLambda.h.

Constructor & Destructor Documentation

◆ AemXSeriesWideband()

AemXSeriesWideband::AemXSeriesWideband ( uint8_t  sensorIndex,
SensorType  type 
)

Definition at line 14 of file AemXSeriesLambda.cpp.

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}
static constexpr efidur_t sensor_timeout
const uint8_t m_sensorIndex
SensorType type() const
Definition sensor.h:166

Member Function Documentation

◆ acceptFrame()

bool AemXSeriesWideband::acceptFrame ( const size_t  busIndex,
const CANRxFrame frame 
) const
finaloverridevirtual

Reimplemented from CanListener.

Definition at line 44 of file AemXSeriesLambda.cpp.

44 {
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}
can_wbo_type_e sensorType() const
uint32_t getAemCanId() const
uint32_t getReCanId() const
can_wbo_type_e
size_t getWidebandBus()
uint8_t DLC
Data length.
Definition can_mocks.h:42
Here is the call graph for this function:

◆ decodeAemXSeries()

bool AemXSeriesWideband::decodeAemXSeries ( const CANRxFrame frame,
efitick_t  nowNt 
)
protected
Returns
true if valid, false if invalid

Definition at line 164 of file AemXSeriesLambda.cpp.

164 {
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}
void refreshSmoothedLambda(float lambda)
void setValidValue(float value, efitick_t timestamp)
uint16_t SWAP_UINT16(uint16_t x)
Definition efilib.h:22
uint8_t data8[8]
Frame data.
Definition can_mocks.h:55
uint16_t data16[4]
Frame data.
Definition can_mocks.h:56

Referenced by decodeFrame().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decodeFrame()

void AemXSeriesWideband::decodeFrame ( const CANRxFrame frame,
efitick_t  nowNt 
)
overrideprotectedvirtual

Implements CanListener.

Definition at line 133 of file AemXSeriesLambda.cpp.

133 {
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}
void decodeRusefiDiag(const CANRxFrame &frame)
bool decodeRusefiStandard(const CANRxFrame &frame, efitick_t nowNt)
bool decodeAemXSeries(const CANRxFrame &frame, efitick_t nowNt)
Here is the call graph for this function:

◆ decodeRusefiDiag()

void AemXSeriesWideband::decodeRusefiDiag ( const CANRxFrame frame)
protected

Definition at line 241 of file AemXSeriesLambda.cpp.

241 {
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}
uint8_t code
Definition bluetooth.cpp:40
bool warning(ObdCode code, const char *fmt,...)
@ Wideband_2_Fault
@ Wideband_1_Fault
scaled_channel< uint16_t, 1000, 1 > nernstVoltage

Referenced by decodeFrame().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ decodeRusefiStandard()

bool AemXSeriesWideband::decodeRusefiStandard ( const CANRxFrame frame,
efitick_t  nowNt 
)
protected

Definition at line 188 of file AemXSeriesLambda.cpp.

188 {
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}
void firmwareError(ObdCode code, const char *fmt,...)
@ OBD_WB_FW_Mismatch

Referenced by decodeFrame().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getAemCanId()

uint32_t AemXSeriesWideband::getAemCanId ( ) const
private

Definition at line 39 of file AemXSeriesLambda.cpp.

39 {
40 // 0th sensor is 0x00000180, 1st sensor is 0x00000181, etc
42}
static constexpr uint32_t aem_base
static constexpr engine_configuration_s * engineConfiguration

Referenced by acceptFrame().

Here is the caller graph for this function:

◆ getReCanId()

uint32_t AemXSeriesWideband::getReCanId ( ) const
private

Definition at line 34 of file AemXSeriesLambda.cpp.

34 {
35 // 0th sensor is 0x190 and 0x191, 1st sensor is 0x192 and 0x193
37}
static constexpr uint32_t rusefi_base

Referenced by acceptFrame().

Here is the caller graph for this function:

◆ isHeaterAllowed()

bool AemXSeriesWideband::isHeaterAllowed ( )
private

Definition at line 78 of file AemXSeriesLambda.cpp.

78 {
79 return ((sensorType() == AEM) || (engine->engineState.heaterControlEnabled));
80}
EngineState engineState
Definition engine.h:352
static EngineAccessor engine
Definition engine.h:415

Referenced by decodeRusefiDiag(), and refreshState().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ refreshSmoothedLambda()

void AemXSeriesWideband::refreshSmoothedLambda ( float  lambda)

Definition at line 224 of file AemXSeriesLambda.cpp.

224 {
225 switch (type()) {
226 case SensorType::Lambda1: {
229 break;
230 }
231 case SensorType::Lambda2: {
234 break;
235 }
236 default:
237 break;
238 }
239}
void setSmoothingFactor(float p_smoothingFactor)
Definition exp_average.h:26
float initOrAverage(float value)
Definition exp_average.h:9
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

Referenced by decodeAemXSeries(), and decodeRusefiStandard().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ refreshState()

void AemXSeriesWideband::refreshState ( void  )

Definition at line 82 of file AemXSeriesLambda.cpp.

82 {
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}

Referenced by decodeFrame(), and getLiveData().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sensorType()

can_wbo_type_e AemXSeriesWideband::sensorType ( ) const
private

Definition at line 30 of file AemXSeriesLambda.cpp.

Referenced by acceptFrame(), decodeFrame(), isHeaterAllowed(), and refreshState().

Here is the caller graph for this function:

Field Documentation

◆ hasSeenRx

bool AemXSeriesWideband::hasSeenRx = false

Definition at line 26 of file AemXSeriesLambda.h.

Referenced by decodeFrame(), and uaefi_slowCallback().

◆ m_afrIsValid

bool AemXSeriesWideband::m_afrIsValid
private

◆ m_isFault

bool AemXSeriesWideband::m_isFault
private

Definition at line 51 of file AemXSeriesLambda.h.

Referenced by AemXSeriesWideband(), decodeAemXSeries(), and refreshState().

◆ m_lastUpdate

efitick_t AemXSeriesWideband::m_lastUpdate = 0
private

Definition at line 53 of file AemXSeriesLambda.h.

Referenced by decodeFrame(), and refreshState().

◆ m_sensorIndex

const uint8_t AemXSeriesWideband::m_sensorIndex
private

◆ m_stateCode

uint8_t AemXSeriesWideband::m_stateCode
private

Definition at line 47 of file AemXSeriesLambda.h.

Referenced by AemXSeriesWideband(), decodeRusefiDiag(), and refreshState().


The documentation for this class was generated from the following files: