You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
9.4 KiB
280 lines
9.4 KiB
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
|
|
}
|
|
|