1313#include " heater_control.h"
1414#include " lambda_conversion.h"
1515#include " max3185x.h"
16- #include " ../for_rusefi/wideband_can .h"
16+ #include " pwmout .h"
1717
1818// EcuMaster protocol
1919// CAN 1Mbps, big-endian
@@ -154,3 +154,125 @@ constexpr ProtocolHandler ecuMasterClassicEgtTxHandler = MakeProtocolHandler<&Se
154154constexpr ProtocolHandler ecuMasterBlackEgtTxHandler = MakeProtocolHandler<&SendEcuMasterEgtFormat>(ECU_MASTER_EGT_TX_PERIOD_MS );
155155
156156#endif
157+
158+
159+ #if (IO_EXPANDER_ENABLED > 0)
160+
161+ #define ECUMASTER_SWITCHBOARD_TX_PERIOD_MS 100
162+ #define ECUMASTER_SWITCHBOARD_BASE_ID 0x640
163+ #define ECUMASTER_SWITCHBOARD_DEVICE_ID (n ) (ECUMASTER_SWITCHBOARD_BASE_ID + (n) * 4 )
164+ #define ECUMASTER_SWITCHBOARD_RX_OFFSET 3
165+
166+ namespace ecumaster
167+ {
168+ // BASE: AV1-AV4, 0.001 V
169+ // BASE + 1: AV5-AV8, 0.001 V
170+ struct AVData
171+ {
172+ uint16_t Value[4 ];
173+ } __attribute__((packed));
174+
175+ static_assert (sizeof (AVData) == 8 );
176+
177+ // BASE + 2
178+ struct OtherData
179+ {
180+ uint8_t Rotary1 : 4 ; // 0-15
181+ uint8_t Rotary2 : 4 ; // 0-15
182+ uint8_t Rotary3 : 4 ; // 0-15
183+ uint8_t Rotary4 : 4 ; // 0-15
184+ uint8_t Rotary5 : 4 ; // 0-15
185+ uint8_t Rotary6 : 4 ; // 0-15
186+ uint8_t Rotary7 : 4 ; // 0-15
187+ uint8_t Rotary8 : 4 ; // 0-15
188+ uint8_t Switch; // bit 0-7 represent switch 1-8 (0=open, 1=closed)
189+ uint8_t AnalogState; // bitmask of which analog inputs are above threshold (1) or below threshold (0)
190+ uint8_t LowSideState; // bitmask of which low-side outputs are active (1) or inactive (0)
191+ uint8_t Heartbeat; // Incremented on each message
192+ } __attribute__((packed));
193+
194+ static_assert (sizeof (OtherData) == 8 );
195+
196+ // BASE + 3: Low-side output control messages from ECU to switchboard
197+ struct LowSideRxData
198+ {
199+ uint8_t State[4 ];
200+ uint8_t Reserved[4 ];
201+ } __attribute__((packed));
202+
203+ static_assert (sizeof (LowSideRxData) == 8 );
204+ }
205+
206+ static uint8_t hearbeat = 0 ;
207+ static uint8_t analogStatus = 0 ;
208+ static uint8_t lowSideStatus = 0 ;
209+
210+ void SendEcuMasterSwitchBoardFormat (Configuration* configuration)
211+ {
212+
213+ auto id = ECUMASTER_SWITCHBOARD_BASE_ID + configuration->afr [0 ].ExtraCanIdOffset ;
214+
215+ // Handle first 4 channels for now
216+ constexpr uint8_t channels = AUX_INPUT_CHANNELS > 4 ? 4 : AUX_INPUT_CHANNELS ;
217+
218+ CanTxTyped<ecumaster::AVData> frame (id, true );
219+ for (uint8_t i = 0 ; i < channels; i++)
220+ {
221+ if (configuration->ioExpanderConfig .IOInputsEnabled & (1 << i))
222+ {
223+ float voltage = GetAuxInputVoltage (i);
224+
225+ // Some hysteresis
226+ if (voltage > 3 .0f ) analogStatus |= (1 << i);
227+ if (voltage < 2 .0f ) analogStatus &= ~(1 << i);
228+
229+ uint16_t raw = (uint16_t )(voltage * 1000 );
230+ frame->Value [i] = raw;
231+ }
232+ else
233+ {
234+ frame->Value [i] = 0 ; // Input disabled, report as 0V
235+ }
236+ }
237+
238+ CanTxTyped<ecumaster::OtherData> otherFrame (id + 2 , true );
239+
240+ otherFrame->AnalogState = analogStatus;
241+ otherFrame->LowSideState = lowSideStatus;
242+ otherFrame->Heartbeat = hearbeat++;
243+ }
244+
245+ void HandleEcuMasterCanMessage (const CANRxFrame* msg, Configuration* configuration)
246+ {
247+ auto msg_id = CAN_ID (*msg);
248+
249+ auto device_id = ECUMASTER_SWITCHBOARD_DEVICE_ID (configuration->ioExpanderConfig .Offset );
250+
251+ if (msg_id != device_id + ECUMASTER_SWITCHBOARD_RX_OFFSET ) {
252+ return ; // Not a low-side control message
253+ }
254+
255+ auto lowSideData = reinterpret_cast <const ecumaster::LowSideRxData*>(msg->data8 );
256+ for (uint8_t i = 0 ; i < 4 ; i++)
257+ {
258+ if (configuration->ioExpanderConfig .IOOutputsEnabled & (1 << i))
259+ {
260+ if (lowSideData->State [i])
261+ {
262+ lowSideStatus |= (1 << i);
263+ SetAuxPwmDuty (i, 1.0 ); // Set PWM duty to 100% for active low-side output
264+ }
265+ else
266+ {
267+ lowSideStatus &= ~(1 << i);
268+ SetAuxPwmDuty (i, 0.0 ); // Set PWM duty to 0% for inactive low-side output
269+ }
270+
271+
272+ }
273+ }
274+ }
275+
276+ constexpr ProtocolHandler ecuMasterSwitchBoardTxHandler = MakeProtocolHandler<&SendEcuMasterSwitchBoardFormat>(ECUMASTER_SWITCHBOARD_TX_PERIOD_MS );
277+
278+ #endif
0 commit comments