Small CLI monitoring tool to decode proprietary [...] protocol and display info in human readable representation
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.
ycli-mon/yabl/protocol.go

163 lines
4.2 KiB

package yabl
import (
can "cli-mon/can"
"encoding/binary"
time "time"
)
type action struct {
object Action
fields []*field
interval uint
name AName
}
type field struct {
length uint8
setter func(uint64 uint64) any
value uint64
last *time.Time
name FName
}
type key struct {
canId uint32
unitId uint
}
type converter struct {
protocolMap map[key]action
cpuPresentEnergyArray [CONNECTOR_MAX]*CpuPresentEnergy
cpuPeripheryInstance *CpuPeriphery
cpuEnergySettingsArray [CONNECTOR_MAX]*CpuEnergySettings
cpuErrorsInstance *CpuErrors
cpuDebugInstance *CpuDebug
puPresentEnergyArray [CONNECTOR_MAX]*PuPresentEnergy
puPeripheryArray [CONNECTOR_MAX]*PuPeriphery
puErrorsArray [CONNECTOR_MAX]*PuErrors
puDebugArray [CONNECTOR_MAX]*PuDebug
seccTargetEnergyArray [CONNECTOR_MAX]*SeccTargetEnergy
seccErrorsArray [CONNECTOR_MAX]*SeccErrors
logicAuthArray [CONNECTOR_MAX]*LogicAuth
logicEnergyMode [CONNECTOR_MAX]*LogicEnergyMode
logicErrorsInstance *LogicErrors
logicWorkingMode [CONNECTOR_MAX]*LogicWorkingMode
contactorInternalStateArray [CONTACTOR_MAX]*ContactorInternalState
contactorInternalErrorsInstance *ContactorInternalErrors
contactorsInternalForce *ContactorsInternalForce
contactorInternalDebugArray [CONTACTOR_MAX]*ContactorInternalDebug
peripheryStateArray [CONNECTOR_MAX]*PeripheryState
peripheryInfoArray [CONNECTOR_MAX]*PeripheryInfo
peripheryDebugArray [CONNECTOR_MAX]*PeripheryDebug
converterPresentEnergyArray [CONVERTERS_MAX]*ConverterPresentEnergy
converterErrorsArray [CONVERTERS_MAX]*ConverterErrors
converterDebugArray [CONVERTERS_MAX]*ConverterDebug
}
type Converter interface {
EventsFromFrame(*can.CanFrame) ([]*Event, bool)
CheckTimeouts() ([]*Event, bool)
}
func NewProtocolConverter() Converter {
c := &converter{}
c.initialize()
return c
}
func (c *converter) EventsFromFrame(frame *can.CanFrame) ([]*Event, bool) {
if frame == nil {
return nil, false
}
var unitId = uint((frame.CanId & UNIT_ID_MASK) >> UNIT_ID_OFFSET)
var canId = frame.CanId & ACTION_ID_MASK
var k = key{canId: canId, unitId: unitId}
if param, ok := c.protocolMap[k]; ok {
result := make([]*Event, 0, len(param.fields))
var start uint8 = 0
for _, f := range param.fields {
if val, found := get(start, f.length, frame.Payload); found {
f.last = frame.Date
if f.value != val { // value changed
f.value = val
obj := f.setter(val)
event := &Event{
Field: f.name,
ActionName: param.name,
Object: param.object,
unit: unit(unitId),
Updated: frame.Date,
Value: obj,
}
result = append(result, event)
}
}
start += f.length // next field
}
return result, len(result) > 0
}
return nil, false
}
func get(from uint8, size uint8, 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 (u unit) GetUnitId() uint {
return uint(u)
}
func (c *converter) CheckTimeouts() ([]*Event, bool) {
var multipler uint = 2
var events []*Event
for k, param := range c.protocolMap {
now := time.Now()
deadline := now.Add(-time.Duration(param.interval*multipler) * time.Millisecond)
var from uint8 = 0
for _, fld := range param.fields {
if fld.last == nil {
continue
} else if deadline.After(*fld.last) {
if events == nil {
events = make([]*Event, 0, len(param.fields))
}
event := &Event{
Field: fld.name,
ActionName: param.name,
Object: param.object,
unit: unit(k.unitId),
Updated: &now,
Value: nil,
}
var mask uint64 = ^(ALL_BITS << fld.length)
mask = mask << from
fld.value = mask
events = append(events, event)
fld.last = nil
}
from += fld.length
}
}
return events, events != nil
}