package yabl import ( can "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 UNKNOWN IsolationStateType = 0 ONGOING IsolationStateType = 1 PASSED IsolationStateType = 2 WARNING IsolationStateType = 3 FAILED IsolationStateType = 4 ) 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 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 = 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 }