package yabl import ( can "cli-mon/can" "encoding/binary" "os" 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 { tag string 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(isOffline bool) ([]*Event, bool) } func NewProtocolConverter(tag string) Converter { if len(tag) == 0 { tag = os.Getenv("HOSTNAME") if len(tag) == 0 { tag, _ = os.Hostname() } } c := &converter{tag: tag} 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{ Tag: &c.tag, Field: &f.name, ActionName: ¶m.name, Object: ¶m.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(isOffline bool) ([]*Event, bool) { var multipler uint = 2 var events []*Event for k, param := range c.protocolMap { var now time.Time if isOffline { now = getMaxTime(&c.protocolMap) } else { 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{ Tag: &c.tag, Field: &fld.name, ActionName: ¶m.name, Object: ¶m.object, unit: unit(k.unitId), Updated: &deadline, 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 } func getMaxTime(protocolMap *map[key]*action) time.Time { now := time.Unix(0, 0) for _, param := range *protocolMap { for _, fld := range param.fields { if fld.last != nil && fld.last.After(now) { now = *fld.last } } } return now }