13 #include <rusefi/endian.h>
25 #define DRIVER_NAME "IOBox"
33 #define MSIOBOX_OUTPUTS 8
37 #define MSIOBOX_INPUTS 8
39 #define MSIOBOX_SIGNALS (MSIOBOX_OUTPUTS + MSIOBOX_INPUTS)
43 #define MSIOBOX_OUT_COUNT 7
45 #define MSIOBOX_ADC_IN_COUNT 7
47 #define MSIOBOX_TACH_IN_COUNT 4
50 #define MSIOBOX_PING_TIMEOUT 100
51 #define MSIOBOX_RESTART_TIMEOUT 1000
60 #define CAN_IOBOX_BASE1 0x200
61 #define CAN_IOBOX_BASE2 0x220
62 #define CAN_IOBOX_BASE3 0x240
65 #define CAN_IOBOX_PING 0x00
66 #define CAN_IOBOX_CONFIG 0x01
67 #define CAN_IOBOX_SET_PWM(n) (0x02 + ((n) & 0x03))
68 #define CAN_IOBOX_LAST_IN 0x05
71 #define CAN_IOBOX_WHOAMI 0x08
72 #define CAN_IOBOX_ADC14 0x09
73 #define CAN_IOBOX_ADC57 0x0A
74 #define CAN_IOBOX_TACH1 0x0B
76 #define CAN_IOBOX_TACH4 0x0E
105 static_assert(
sizeof(iobox_pwm) == 8);
108 struct iobox_pwm_last {
113 static_assert(
sizeof(iobox_pwm_last) == 5);
116 struct iobox_whoami {
123 static_assert(
sizeof(iobox_whoami) == 8);
130 static_assert(
sizeof(iobox_adc14) == 8);
139 static_assert(
sizeof(iobox_adc57) == 8);
148 static_assert(
sizeof(iobox_tach) == 8);
171 MsIoBox(uint32_t bus, uint32_t base, uint16_t
period);
177 int config(uint32_t bus, uint32_t base, uint16_t
period);
197 void CalcOnOffPeriod(
int ch, pwm_settings &pwm);
205 } OutPwm[MSIOBOX_OUT_COUNT];
207 uint16_t AdcValue[MSIOBOX_ADC_IN_COUNT];
217 } Tach[MSIOBOX_TACH_IN_COUNT];
224 uint32_t pwmBaseFreq = 1000 * 1000 * 100 / 5000;
226 uint32_t tachinBaseFreq = 1000 * 1000 * 100 / 66;
231 bool needUpdateConfig;
242 MsIoBox::MsIoBox(uint32_t bus, uint32_t base, uint16_t
period)
272 bool MsIoBox::acceptFrame(
const CANRxFrame& frame)
const {
274 if (CAN_ISX(frame)) {
278 uint32_t
id = CAN_ID(frame);
282 if ((
id >= base + 8) && (
id <= base + 14)) {
290 int MsIoBox::ping() {
297 int MsIoBox::setup() {
300 cfg->pwm_mask = OutMode;
301 cfg->tachin_mask = InMode;
302 cfg->adc_broadcast_interval =
period;
303 cfg->tach_broadcast_interval =
period;
308 void MsIoBox::CalcOnOffPeriod(
int ch, pwm_settings &pwm)
310 if ((OutMode & BIT(
ch)) == 0) {
311 pwm.on = pwm.off = 0;
315 int period = (pwmBaseFreq + (OutPwm[
ch].frequency / 2)) / OutPwm[
ch].frequency;
318 pwm.off =
period - pwm.on;
322 int MsIoBox::update() {
326 for (
size_t i = 0; i < 3; i++) {
328 if ((OutMode & (BIT(i) | BIT(i + 1))) == 0)
332 for (
size_t j = 0; j < 2; j++) {
333 CalcOnOffPeriod(i + j, pwm->ch[j]);
341 CalcOnOffPeriod(MSIOBOX_OUT_COUNT - 1, pwm->ch[0]);
343 pwm->out_state = OutVal;
349 void MsIoBox::decodeFrame(
const CANRxFrame& frame, efitick_t) {
350 uint32_t
id = CAN_ID(frame);
351 uint32_t offset =
id - base;
355 if (offset == CAN_IOBOX_ADC14) {
356 auto data =
reinterpret_cast<const iobox_adc14*
>(&frame.
data8[0]);
358 for (
size_t i = 0; i < 4; i++) {
359 AdcValue[i] = data->adc[i];
361 }
else if (offset == CAN_IOBOX_ADC57) {
362 auto data =
reinterpret_cast<const iobox_adc57*
>(&frame.
data8[0]);
364 InVal = data->inputs;
365 for (
size_t i = 0; i < 3; i++) {
366 AdcValue[i + 4] = data->adc[i];
368 }
else if ((offset >= CAN_IOBOX_TACH1) && (offset <= CAN_IOBOX_TACH4)) {
369 size_t i = offset - CAN_IOBOX_TACH1;
370 auto data =
reinterpret_cast<const iobox_tach*
>(&frame.
data8[0]);
374 Tach[i].period = data->period;
375 Tach[i].teeths = data->n_teeth;
376 Tach[i].totalTooth = data->total_tooth;
381 if (offset == CAN_IOBOX_WHOAMI) {
382 auto data =
reinterpret_cast<const iobox_whoami*
>(&frame.
data8[0]);
386 pwmBaseFreq = 1000 * 1000 * 100 / data->pwm_period;
387 tachinBaseFreq = 1000 * 1000 * 100 / data->tachin_period;
412 if (
pin >= MSIOBOX_OUTPUTS)
415 uint8_t OutModeNew = OutMode & (~BIT(
pin));
416 uint8_t OutValNew = OutVal;
418 OutValNew |= BIT(
pin);
420 OutValNew &= ~BIT(
pin);
423 if (OutValNew != OutVal) {
427 if (OutModeNew != OutMode) {
428 OutMode = OutModeNew;
429 needUpdateConfig =
true;
435 int MsIoBox::readPad(
size_t pin) {
436 if ((
pin < MSIOBOX_OUTPUTS) || (
pin >= MSIOBOX_SIGNALS))
439 pin -= MSIOBOX_OUTPUTS;
441 if (InMode & BIT(
pin)) {
446 return !!(InVal & BIT(
pin));
451 if (
pin >= MSIOBOX_OUT_COUNT)
462 if ((OutMode & BIT(
pin)) == 0) {
464 needUpdateConfig =
true;
475 if (
pin >= MSIOBOX_SIGNALS)
482 return PIN_DRIVER_OFF;
485 void MsIoBox::checkState(
void)
499 if (stateTimer.hasElapsedMs(MSIOBOX_PING_TIMEOUT)) {
505 if (stateTimer.hasElapsedMs(
period * 3)) {
509 if (needUpdateConfig) {
511 needUpdateConfig =
false;
521 if (stateTimer.hasElapsedMs(MSIOBOX_RESTART_TIMEOUT)) {
544 for (
size_t i = 0; i < BOARD_CAN_GPIO_COUNT; i++) {
void registerCanListener(CanListener &listener)
uint8_t tach_broadcast_interval
typedef __attribute__
Ignition Mode.
uint8_t adc_broadcast_interval
static MsIoBox instance[BOARD_CAN_GPIO_COUNT]
virtual bool acceptFrame(const CANRxFrame &frame) const
virtual CanListener * request()
virtual void decodeFrame(const CANRxFrame &frame, efitick_t nowNt)=0
int gpiochip_register(brain_pin_e base, const char *name, GpioChip &gpioChip, size_t size)
Register gpiochip.
void writePad(const char *msg, brain_pin_e pin, int bit)
persistent_config_s * config
engine_configuration_s * engineConfiguration
uint8_t data8[8]
Frame data.
virtual int setPadPWM(size_t, float, float)
virtual brain_pin_diag_e getDiag(size_t)
virtual int readPad(size_t)
MsIoBox_config_s msIoBox0