package yabl import ( "cli-mon/can" "encoding/binary" ) const ( CONTACTOR_MAX = 18 + 1 CONNECTOR_MAX = 6 + 1 ALL_BITS = 0xFFFFFFFFFFFFFFFF UNIT_ID_OFFSET = 12 UNIT_ID_MASK = 0b111111111111 << UNIT_ID_OFFSET ACTION_ID_MASK = 0b111111111111 BOARD_READY_OK BoardReadyType = 0 BOARD_READY_INFO BoardReadyType = 1 BOARD_READY_WARNING BoardReadyType = 2 BOARD_READY_DEBUG BoardReadyType = 3 BOARD_READY_DEP_ERROR BoardReadyType = 4 BOARD_READY_ERROR BoardReadyType = 5 BOARD_READY_CRITICAL BoardReadyType = 6 OFF BooleanType = 0 ON BooleanType = 1 NO_ERROR ErrorType = 0 ERROR ErrorType = 1 OTHER_NO_ERROR ContactorInternalOtherErrorType = 0 NO_PENDING_CHANGES ContactorGroupChangedType = 0 INITIALIZED_CHANGE ContactorGroupChangedType = 1 CHANGE_IN_PROGRESS ContactorGroupChangedType = 2 V2G_MODE_G2V V2GModeType = 0 V2G_MODE_V2G V2GModeType = 1 V2G_MODE_INV V2GModeType = 2 NOT_ENABLE CpLineLevelType = 0 TWELVE CpLineLevelType = 1 NINE CpLineLevelType = 2 SIX CpLineLevelType = 3 THREE CpLineLevelType = 4 MINUS_TWELVE CpLineLevelType = 5 ISOLATION_STATE_UNKNOWN IsolationStateType = 0 ONGOING IsolationStateType = 1 PASSED IsolationStateType = 2 WARNING IsolationStateType = 3 FAILED IsolationStateType = 4 AUTH AuthModeType = 0 PNC AuthModeType = 1 AUTH_STATE_UNKNOWN AuthStateType = 0 AUTH_STATE_ALLOW AuthStateType = 1 AUTH_STATE_DENY AuthStateType = 2 CONTACTOR_NO_MODE ContactorModeType = 0 CONTACTOR_TRANSACTION_PROCESS ContactorModeType = 1 CONTACTOR_CUSTOM_MODE ContactorModeType = 2 CONTACTOR_ONLY_ONE_OUT_MODE ContactorModeType = 3 CONTACTOR_ONE_TO_ONE_OUT_MODE ContactorModeType = 4 CONTACTOR_SIMPLE_DYNAMIC_MODE ContactorModeType = 5 DEBUG_SWITCH_MODE_AUTO DebugSwitchModeType = 0 DEBUG_SWITCH_MODE_OFF DebugSwitchModeType = 1 DEBUG_SWITCH_MODE_ON DebugSwitchModeType = 2 DEBUG_SWITCH_MODE_PERMANENT_OFF DebugSwitchModeType = 4 DEBUG_SWITCH_MODE_PERMANENT_ON DebugSwitchModeType = 5 ) type Packet interface { GetUnitId() uint } type ContactorInternalState struct { UnitId uint ContactorReady BoardReadyType ContactorOn BooleanType UnexpectedState ErrorType Isolated ErrorType DebugEnabled BooleanType } type ContactorInternalErrors struct { UnitId uint BoardReady BoardReadyType OtherError ContactorInternalOtherErrorType ContactorGroupChanged ContactorGroupChangedType UnexpectedFormation ContactorInternalOtherErrorType CpuNotReady ErrorType PuNotReady ErrorType Debug BooleanType } type PuPresentEnergy struct { UnitId uint V2GMode V2GModeType VoltageBefore Voltage11BitType VoltageAfter Voltage11BitType PresentCurrent Current10BitType } type PuPeriphery struct { UnitId uint ConnectorInsert BooleanType ContactorOn BooleanType ConnectorLocked BooleanType CpLineLevel CpLineLevelType IsolationState IsolationStateType ChargingAllowed BooleanType PwmEnabled BooleanType CpLineVoltage Voltage9BitType } type LogicAuth struct { UnitId uint AuthMode AuthModeType AuthState AuthStateType } type LogicEnergyMode struct { UnitId uint V2gMode V2GModeType CurrentMax Current10BitType VoltageMax Voltage11BitType PowerMax Power14BitType } type LogicWorkingMode struct { UnitId uint TargetContactorMode ContactorModeType Availability BooleanType } type CpuPresentEnergy struct { UnitId uint PowerDirectionMode V2GModeType PresentCurrent Current10BitType PresentVoltage Voltage11BitType } type CpuPeriphery struct { UnitId uint ContactorInput BooleanType CircuitBreakerInput BooleanType CircuitBreakerPowerCBInput BooleanType } type CpuEnergySettings struct { UnitId uint CurrentMax Current10BitType VoltageMax Voltage11BitType PowerMax Power14BitType TargetBatteryVoltage Voltage11BitType TargetGoalVoltage Voltage11BitType } type CpuErrors struct { UnitId uint BoardReady BoardReadyType OtherError OtherError4BitType RedButtonHard ErrorType RedButtonSoft ErrorType ModulesGone ErrorType GridVoltageHighErr ErrorType GridVoltageHighWarn ErrorType GridVoltageLowWarn ErrorType GridVoltageLowErr ErrorType GridVoltageLow Voltage11BitType GridVoltageHigh Voltage11BitType GridVoltageEmpty ErrorType NotReadySecc ErrorType NotReadyPu ErrorType NotReadyContactors ErrorType DebugConvertersEnabled ErrorType ContactorInputError ErrorType NotReadyPeriphery ErrorType } type CpuDebug struct { UnitId uint DebugModeOn BooleanType DebugContactorInputOn DebugSwitchModeType DebugCircuitBreakerOn DebugSwitchModeType DebugRedButtonSoftware DebugSwitchModeType } type PuErrors struct { UnitId uint BoardReady BoardReadyType OtherError OtherError4BitType IncorrectVoltage ErrorType IncorrectVoltageValue Voltage11BitType IncorrectCurrent ErrorType IncorrectCurrentValue Current10BitType IsolationBroken ErrorType CpLineBroken ErrorType CpLineGap69 ErrorType CableReady BoardReadyType NotReadyCpu ErrorType NotReadySecc ErrorType ContactorOutputError ErrorType DebugContactorOutputEnabled BooleanType OutputCircuitBreakerEnabled ErrorType OutputCircuitBreakerEnabledValue SignedVoltage12bitType } type PuDebug struct { UnitId uint DebugModeOn BooleanType DebugContactorOutputOn DebugSwitchModeType } type SeccTargetEnergy struct { UnitId uint TargetChargingAllow BooleanType TargetBatteryVoltage Voltage11BitType TargetGoalVoltage Voltage11BitType TargetCurrent Current10BitType } type SeccErrors struct { UnitId uint BoardReady BoardReadyType NotReadyLogic ErrorType } type SignedVoltage12bitType int type DebugSwitchModeType uint type OtherError4BitType uint type ContactorModeType uint type Power14BitType uint type AuthStateType uint type AuthModeType uint type BoardReadyType uint type BooleanType uint type ErrorType uint type ContactorInternalOtherErrorType uint type ContactorGroupChangedType uint type V2GModeType uint type Voltage11BitType uint type Current10BitType uint type CpLineLevelType uint type IsolationStateType uint type Voltage9BitType float32 func StartProtocolParsing(frames <-chan *can.CanFrame) <-chan Packet { result := make(chan Packet) go func() { defer close(result) var contactorsFirstState [CONTACTOR_MAX]bool var contactorsFirstErr [CONTACTOR_MAX]bool var puFirst [CONNECTOR_MAX]bool var puPeripheryFirst [CONNECTOR_MAX]bool for frame := range frames { if frames == nil { continue } var unitId = uint((frame.CanId & UNIT_ID_MASK) >> UNIT_ID_OFFSET) switch { case frame.CanId&ACTION_ID_MASK == can.CAN_ID_071: changed := false var model = ContactorInternalState{UnitId: unitId} if val, ok := get(0, 3, frame.Payload); ok && model.ContactorReady != BoardReadyType(val) { model.ContactorReady = BoardReadyType(val) changed = true } if val, ok := get(3, 2, frame.Payload); ok && model.ContactorOn != BooleanType(val) { model.ContactorOn = BooleanType(val) changed = true } if val, ok := get(5, 2, frame.Payload); ok && model.UnexpectedState != ErrorType(val) { model.UnexpectedState = ErrorType(val) changed = true } if val, ok := get(7, 2, frame.Payload); ok && model.Isolated != ErrorType(val) { model.Isolated = ErrorType(val) changed = true } if val, ok := get(9, 2, frame.Payload); ok && model.DebugEnabled != BooleanType(val) { model.DebugEnabled = BooleanType(val) changed = true } if changed || !contactorsFirstState[unitId] { contactorsFirstState[unitId] = true result <- &model } case frame.CanId&ACTION_ID_MASK == can.CAN_ID_073: changed := false model := ContactorInternalErrors{UnitId: unitId} if val, ok := get(0, 3, frame.Payload); ok && model.BoardReady != BoardReadyType(val) { model.BoardReady = BoardReadyType(val) changed = true } if val, ok := get(3, 4, frame.Payload); ok && model.OtherError != ContactorInternalOtherErrorType(val) { model.OtherError = ContactorInternalOtherErrorType(val) changed = true } if val, ok := get(7, 3, frame.Payload); ok && model.ContactorGroupChanged != ContactorGroupChangedType(val) { model.ContactorGroupChanged = ContactorGroupChangedType(val) changed = true } if val, ok := get(10, 4, frame.Payload); ok && model.UnexpectedFormation != ContactorInternalOtherErrorType(val) { model.UnexpectedFormation = ContactorInternalOtherErrorType(val) changed = true } if val, ok := get(14, 2, frame.Payload); ok && model.CpuNotReady != ErrorType(val) { model.CpuNotReady = ErrorType(val) changed = true } if val, ok := get(16, 2, frame.Payload); ok && model.PuNotReady != ErrorType(val) { model.PuNotReady = ErrorType(val) changed = true } if val, ok := get(18, 2, frame.Payload); ok && model.Debug != BooleanType(val) { model.Debug = BooleanType(val) changed = true } if changed || !contactorsFirstErr[unitId] { contactorsFirstErr[unitId] = true result <- &model } case frame.CanId&ACTION_ID_MASK == can.CAN_ID_021: changed := false model := PuPresentEnergy{UnitId: unitId} if val, ok := get(0, 2, frame.Payload); ok && model.V2GMode != V2GModeType(val) { model.V2GMode = V2GModeType(val) changed = true } if val, ok := get(2, 11, frame.Payload); ok && model.VoltageBefore != Voltage11BitType(val) { model.VoltageBefore = Voltage11BitType(val) changed = true } if val, ok := get(13, 11, frame.Payload); ok && model.VoltageAfter != Voltage11BitType(val) { model.VoltageAfter = Voltage11BitType(val) changed = true } if val, ok := get(24, 10, frame.Payload); ok && model.PresentCurrent != Current10BitType(val) { model.PresentCurrent = Current10BitType(val) changed = true } if changed || !puFirst[unitId] { puFirst[unitId] = true result <- &model } case frame.CanId&ACTION_ID_MASK == can.CAN_ID_022: changed := false model := PuPeriphery{UnitId: unitId} if val, ok := get(0, 2, frame.Payload); ok && model.ConnectorInsert != BooleanType(val) { model.ConnectorInsert = BooleanType(val) changed = true } if val, ok := get(2, 2, frame.Payload); ok && model.ContactorOn != BooleanType(val) { model.ContactorOn = BooleanType(val) changed = true } if val, ok := get(4, 2, frame.Payload); ok && model.ConnectorLocked != BooleanType(val) { model.ConnectorLocked = BooleanType(val) changed = true } if val, ok := get(6, 3, frame.Payload); ok && model.CpLineLevel != CpLineLevelType(val) { model.CpLineLevel = CpLineLevelType(val) changed = true } if val, ok := get(9, 3, frame.Payload); ok && model.IsolationState != IsolationStateType(val) { model.IsolationState = IsolationStateType(val) changed = true } if val, ok := get(12, 2, frame.Payload); ok && model.ChargingAllowed != BooleanType(val) { model.ChargingAllowed = BooleanType(val) changed = true } if val, ok := get(14, 2, frame.Payload); ok && model.PwmEnabled != BooleanType(val) { model.PwmEnabled = BooleanType(val) changed = true } if val, ok := get(16, 9, frame.Payload); ok && model.CpLineVoltage != (Voltage9BitType(val)*0.1-15) { model.CpLineVoltage = Voltage9BitType(val)*0.1 - 15 changed = true } if changed || !puPeripheryFirst[unitId] { puPeripheryFirst[unitId] = true result <- &model } } } }() return result } func get(from uint, size uint, buffer []byte) (uint64, bool) { value := binary.LittleEndian.Uint64(buffer) var mask uint64 = ^(ALL_BITS << size) mask = mask << from selected := mask & value if selected == mask { return 0, false } else { return selected >> from, true } } func (t *ContactorInternalState) GetUnitId() uint { return t.UnitId } func (t *ContactorInternalErrors) GetUnitId() uint { return t.UnitId } func (t *PuPresentEnergy) GetUnitId() uint { return t.UnitId } func (t *PuPeriphery) GetUnitId() uint { return t.UnitId } func (a *LogicAuth) GetUnitId() uint { return a.UnitId } func (l *LogicEnergyMode) GetUnitId() uint { return l.UnitId } func (l *LogicWorkingMode) GetUnitId() uint { return l.UnitId } func (c *CpuPresentEnergy) GetUnitId() uint { return c.UnitId } func (c *CpuPeriphery) GetUnitId() uint { return c.UnitId } func (c *CpuEnergySettings) GetUnitId() uint { return c.UnitId } func (c *CpuErrors) GetUnitId() uint { return c.UnitId } func (d *CpuDebug) GetUnitId() uint { return d.UnitId } func (p *PuErrors) GetUnitId() uint { return p.UnitId } func (d *PuDebug) GetUnitId() uint { return d.UnitId } func (s *SeccTargetEnergy) GetUnitId() uint { return s.UnitId } func (e *SeccErrors) GetUnitId() uint { return e.UnitId }