Initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
/cli-mon
|
||||||
|
/.idea/cli-mon.iml
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/vcs.xml
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
package can
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const CAN_ID_071 = 0x071
|
||||||
|
const CAN_ID_073 = 0x073
|
||||||
|
const CAN_ID_021 = 0x021
|
||||||
|
const CAN_ID_022 = 0x022
|
||||||
|
|
||||||
|
type CanFrame struct {
|
||||||
|
CanId uint32
|
||||||
|
Payload []uint8
|
||||||
|
Date string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCan New returns a new CAN bus socket.
|
||||||
|
func NewCan() (*Socket, error) {
|
||||||
|
fd, err := unix.Socket(unix.AF_CAN, unix.SOCK_RAW, unix.CAN_RAW)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Socket{dev: device{fd}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socket is a high-level representation of a CANBus socket.
|
||||||
|
type Socket struct {
|
||||||
|
iface *net.Interface
|
||||||
|
addr *unix.SockaddrCAN
|
||||||
|
dev device
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the CAN bus socket.
|
||||||
|
func (sck *Socket) Close() error {
|
||||||
|
return unix.Close(sck.dev.fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sck *Socket) Bind(addr string, filter []unix.CanFilter) error {
|
||||||
|
iface, err := net.InterfaceByName(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sck.iface = iface
|
||||||
|
sck.addr = &unix.SockaddrCAN{Ifindex: sck.iface.Index}
|
||||||
|
|
||||||
|
//add filter
|
||||||
|
if filter != nil {
|
||||||
|
unix.SetsockoptCanRawFilter(sck.dev.fd, unix.SOL_CAN_RAW, unix.CAN_RAW_FILTER, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return unix.Bind(sck.dev.fd, sck.addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recv receives data from the CAN socket.
|
||||||
|
// id is the CAN_frame id the data was originated from.
|
||||||
|
func (sck *Socket) Recv() (id uint32, data []byte, err error) {
|
||||||
|
var buf [frameSize]byte
|
||||||
|
n, err := io.ReadFull(sck.dev, buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return id, data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != len(buf) {
|
||||||
|
return id, data, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
id = binary.LittleEndian.Uint32(buf[:4])
|
||||||
|
//TODO make correct switch betwin EFF and SFF
|
||||||
|
id &= unix.CAN_EFF_MASK
|
||||||
|
data = make([]byte, buf[4])
|
||||||
|
copy(data, buf[8:])
|
||||||
|
return id, data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type device struct {
|
||||||
|
fd int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d device) Read(data []byte) (int, error) {
|
||||||
|
return unix.Read(d.fd, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d device) Write(data []byte) (int, error) {
|
||||||
|
return unix.Write(d.fd, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const frameSize = unsafe.Sizeof(canframe{})
|
||||||
|
|
||||||
|
// frame is a can_frame.
|
||||||
|
type canframe struct {
|
||||||
|
ID uint32
|
||||||
|
Len byte
|
||||||
|
_ [3]byte
|
||||||
|
Data [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartCan(canbus string) (<-chan *CanFrame, error) {
|
||||||
|
|
||||||
|
var filter []unix.CanFilter = []unix.CanFilter{
|
||||||
|
{Id: CAN_ID_071, Mask: 0xFFF},
|
||||||
|
{Id: CAN_ID_073, Mask: 0xFFF},
|
||||||
|
{Id: CAN_ID_021, Mask: 0xFFF},
|
||||||
|
{Id: CAN_ID_022, Mask: 0xFFF},
|
||||||
|
}
|
||||||
|
|
||||||
|
if socket, err := NewCan(); err == nil {
|
||||||
|
|
||||||
|
if cerr := socket.Bind(canbus, filter); cerr == nil {
|
||||||
|
|
||||||
|
canevents := make(chan *CanFrame)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(canevents)
|
||||||
|
defer socket.Close()
|
||||||
|
|
||||||
|
for { //TODO implement stop
|
||||||
|
if id, data, serr := socket.Recv(); serr == nil {
|
||||||
|
canevents <- &CanFrame{
|
||||||
|
Date: time.Now().String(),
|
||||||
|
CanId: id,
|
||||||
|
Payload: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return canevents, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("can't bind can socket")
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package can
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// (2022-07-08 16:54:15.587099) can0 100 [8] 00 00 00 00 00 00 64 00
|
||||||
|
// (1670578900.771868) can0 00004021#00000000FCFFFFFF
|
||||||
|
const EXPR_HR = "\\((.*)\\)\\s+can\\d+\\s+(\\S+)\\s+\\[\\d\\]\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)"
|
||||||
|
const EXPR_M = "\\((.*)\\)\\s+can\\d+\\s+(\\S+)#([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})"
|
||||||
|
const length = 11
|
||||||
|
|
||||||
|
var patternHr = regexp.MustCompile(EXPR_HR)
|
||||||
|
var patternM = regexp.MustCompile(EXPR_M)
|
||||||
|
|
||||||
|
func Readfile(filename *string) <-chan *CanFrame {
|
||||||
|
c := make(chan *CanFrame)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(c)
|
||||||
|
|
||||||
|
file, err := os.Open(*filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
process(scanner, c)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func process(scanner *bufio.Scanner, ch chan<- *CanFrame) {
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Text()
|
||||||
|
if frame := fromString(&text); frame != nil {
|
||||||
|
ch <- frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadStdin() <-chan *CanFrame {
|
||||||
|
c := make(chan *CanFrame)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
process(scanner, c)
|
||||||
|
}()
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromString(text *string) *CanFrame {
|
||||||
|
var submatch []string
|
||||||
|
if submatch = patternHr.FindStringSubmatch(*text); submatch == nil {
|
||||||
|
if submatch = patternM.FindStringSubmatch(*text); submatch == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(submatch) == length {
|
||||||
|
canid, err := strconv.ParseUint(submatch[2], 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := make([]uint8, 8)
|
||||||
|
for idx, octet := range submatch[3:] {
|
||||||
|
val, err := strconv.ParseUint(octet, 16, 0)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
payload[idx] = uint8(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CanFrame{
|
||||||
|
Date: submatch[1],
|
||||||
|
CanId: uint32(canid),
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cli-mon/can"
|
||||||
|
"cli-mon/ui"
|
||||||
|
"cli-mon/yabl"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
filename := flag.String("f", "", "Candump filename")
|
||||||
|
canbus := flag.String("i", "", "CAN bus interface")
|
||||||
|
stdin := flag.Bool("s", false, "Read from stdin")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var frames <-chan *can.CanFrame
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case *stdin:
|
||||||
|
frames = can.ReadStdin()
|
||||||
|
case len(*filename) > 0:
|
||||||
|
frames = can.Readfile(filename)
|
||||||
|
case len(*canbus) > 0:
|
||||||
|
var err error
|
||||||
|
frames, err = can.StartCan(*canbus)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
flag.Usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
if frames == nil {
|
||||||
|
fmt.Println("Get no data")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages = yabl.StartProtocolParsing(frames)
|
||||||
|
|
||||||
|
ui.InitCliApp(messages)
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
module cli-mon
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gizak/termui/v3 v3.1.0
|
||||||
|
golang.org/x/sys v0.3.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-runewidth v0.0.2 // indirect
|
||||||
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
|
||||||
|
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||||
|
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||||
|
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import "cli-mon/yabl"
|
||||||
|
|
||||||
|
var fNewCIS = func(packet *yabl.ContactorInternalState) *contactorType {
|
||||||
|
return &contactorType{state: packet}
|
||||||
|
}
|
||||||
|
var fGetCIS = func(c *contactorType) *yabl.ContactorInternalState {
|
||||||
|
return c.state
|
||||||
|
}
|
||||||
|
var fSetCIS = func(c *contactorType, packet *yabl.ContactorInternalState) {
|
||||||
|
c.state = packet
|
||||||
|
}
|
||||||
|
|
||||||
|
var fNewCES = func(packet *yabl.ContactorInternalErrors) *contactorType {
|
||||||
|
return &contactorType{errors: packet}
|
||||||
|
}
|
||||||
|
var fGetCES = func(c *contactorType) *yabl.ContactorInternalErrors {
|
||||||
|
return c.errors
|
||||||
|
}
|
||||||
|
var fSetCES = func(c *contactorType, packet *yabl.ContactorInternalErrors) {
|
||||||
|
c.errors = packet
|
||||||
|
}
|
||||||
|
|
||||||
|
var fNewPPE = func(packet *yabl.PuPresentEnergy) *connectorType {
|
||||||
|
return &connectorType{energy: packet}
|
||||||
|
}
|
||||||
|
var fGetPPE = func(c *connectorType) *yabl.PuPresentEnergy {
|
||||||
|
return c.energy
|
||||||
|
}
|
||||||
|
var fSetPPE = func(c *connectorType, packet *yabl.PuPresentEnergy) {
|
||||||
|
c.energy = packet
|
||||||
|
}
|
||||||
|
|
||||||
|
var fNewPP = func(packet *yabl.PuPeriphery) *connectorType {
|
||||||
|
return &connectorType{state: packet}
|
||||||
|
}
|
||||||
|
var fGetPP = func(c *connectorType) *yabl.PuPeriphery {
|
||||||
|
return c.state
|
||||||
|
}
|
||||||
|
var fSetPP = func(c *connectorType, packet *yabl.PuPeriphery) {
|
||||||
|
c.state = packet
|
||||||
|
}
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cli-mon/yabl"
|
||||||
|
"github.com/gizak/termui/v3/widgets"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type connectorType struct {
|
||||||
|
energy *yabl.PuPresentEnergy
|
||||||
|
state *yabl.PuPeriphery
|
||||||
|
}
|
||||||
|
|
||||||
|
type contactorType struct {
|
||||||
|
state *yabl.ContactorInternalState
|
||||||
|
errors *yabl.ContactorInternalErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
type modelTypes interface {
|
||||||
|
*connectorType | *contactorType
|
||||||
|
}
|
||||||
|
|
||||||
|
type dataTypes interface {
|
||||||
|
*yabl.PuPresentEnergy | *yabl.PuPeriphery | *yabl.ContactorInternalState | *yabl.ContactorInternalErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
type fNewType[T modelTypes, V dataTypes] func(e V) T
|
||||||
|
type fGetType[T modelTypes, V dataTypes] func(m T) V
|
||||||
|
type fSetType[T modelTypes, V dataTypes] func(m T, e V)
|
||||||
|
|
||||||
|
var connectors = make([]*connectorType, connectorsCount+1)
|
||||||
|
var contactors = make([]*contactorType, contactorsCount+1)
|
||||||
|
|
||||||
|
var connUI [connectorsCount + 1]*widgets.Paragraph
|
||||||
|
var contUI [contactorsCount + 1]*widgets.Paragraph
|
||||||
|
var contactorsErr *widgets.Paragraph
|
||||||
|
|
||||||
|
func process(message yabl.Packet) {
|
||||||
|
if message == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unitId := message.GetUnitId()
|
||||||
|
|
||||||
|
switch msg := message.(type) {
|
||||||
|
case *yabl.ContactorInternalState:
|
||||||
|
if updateOrNew(contactors, unitId, msg, fNewCIS, fGetCIS, fSetCIS) {
|
||||||
|
updateContactorsView(unitId)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *yabl.ContactorInternalErrors:
|
||||||
|
if updateOrNew(contactors, unitId, msg, fNewCES, fGetCES, fSetCES) {
|
||||||
|
updateContactorsStateView()
|
||||||
|
}
|
||||||
|
|
||||||
|
case *yabl.PuPeriphery:
|
||||||
|
if updateOrNew(connectors, unitId, msg, fNewPP, fGetPP, fSetPP) {
|
||||||
|
updateConnectorsView(unitId)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *yabl.PuPresentEnergy:
|
||||||
|
if updateOrNew(connectors, unitId, msg, fNewPPE, fGetPPE, fSetPPE) {
|
||||||
|
updateConnectorsView(unitId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateOrNew[T modelTypes, V dataTypes](array []T, id uint, msg V, fNew fNewType[T, V], fGet fGetType[T, V], fSet fSetType[T, V]) bool {
|
||||||
|
if model := array[id]; model != nil {
|
||||||
|
if element := fGet(model); !reflect.DeepEqual(element, msg) {
|
||||||
|
fSet(model, msg)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
model = fNew(msg)
|
||||||
|
array[id] = model
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cli-mon/yabl"
|
||||||
|
ui "github.com/gizak/termui/v3"
|
||||||
|
"github.com/gizak/termui/v3/widgets"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const headerHeight int = 4
|
||||||
|
const contactorsCount = 18
|
||||||
|
const connectorsCount = 6
|
||||||
|
|
||||||
|
func InitCliApp(events <-chan yabl.Packet) {
|
||||||
|
if err := ui.Init(); err != nil {
|
||||||
|
log.Fatalf("failed to initialize termui: %v", err)
|
||||||
|
}
|
||||||
|
defer ui.Close()
|
||||||
|
|
||||||
|
var connectorsTab *ui.Grid
|
||||||
|
//var contactorsErr *widgets.Paragraph
|
||||||
|
var contactorsStateTab *ui.Grid
|
||||||
|
var header *widgets.Paragraph
|
||||||
|
|
||||||
|
tabpane := widgets.NewTabPane("Connectors", "Contactors States", "Contactors Errors")
|
||||||
|
tabpane.SetRect(0, 1, 150, 4)
|
||||||
|
tabpane.Border = true
|
||||||
|
|
||||||
|
header = newHeader()
|
||||||
|
connectorsTab = newConnectorsView()
|
||||||
|
contactorsStateTab = newContactorsView()
|
||||||
|
contactorsErr = newContactorsErrView()
|
||||||
|
|
||||||
|
renderTab := func() {
|
||||||
|
switch tabpane.ActiveTabIndex {
|
||||||
|
case 0:
|
||||||
|
termWidth, termHeight := ui.TerminalDimensions()
|
||||||
|
connectorsTab.SetRect(0, headerHeight, termWidth, termHeight)
|
||||||
|
ui.Render(connectorsTab)
|
||||||
|
case 1:
|
||||||
|
termWidth, termHeight := ui.TerminalDimensions()
|
||||||
|
contactorsStateTab.SetRect(0, headerHeight, termWidth, termHeight)
|
||||||
|
ui.Render(contactorsStateTab)
|
||||||
|
case 2:
|
||||||
|
ui.Render(contactorsErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Render(header, tabpane, connectorsTab)
|
||||||
|
|
||||||
|
uiEvents := ui.PollEvents()
|
||||||
|
ticker := time.NewTicker(2 * time.Second).C
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-uiEvents:
|
||||||
|
switch e.ID { // event string/identifier
|
||||||
|
case "q", "<C-c>": // press 'q' or 'C-c' to quit
|
||||||
|
return
|
||||||
|
case "<MouseLeft>":
|
||||||
|
//payload := e.Payload.(ui.Mouse)
|
||||||
|
//x, y := payload.X, payload.Y
|
||||||
|
//p.Text = fmt.Sprintf("X = %d, Y = %d", x, y)
|
||||||
|
case "<Left>":
|
||||||
|
tabpane.FocusLeft()
|
||||||
|
ui.Clear()
|
||||||
|
ui.Render(header, tabpane)
|
||||||
|
renderTab()
|
||||||
|
case "<Right>":
|
||||||
|
tabpane.FocusRight()
|
||||||
|
ui.Clear()
|
||||||
|
ui.Render(header, tabpane)
|
||||||
|
renderTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Type {
|
||||||
|
case ui.KeyboardEvent: // handle all key presses
|
||||||
|
//eventID := e.ID // keypress string
|
||||||
|
//p.Text = eventID
|
||||||
|
}
|
||||||
|
// use Go's built-in tickers for updating and drawing data
|
||||||
|
case <-ticker:
|
||||||
|
renderTab()
|
||||||
|
case message := <-events:
|
||||||
|
process(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+224
@@ -0,0 +1,224 @@
|
|||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cli-mon/yabl"
|
||||||
|
"fmt"
|
||||||
|
ui "github.com/gizak/termui/v3"
|
||||||
|
"github.com/gizak/termui/v3/widgets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newHeader() *widgets.Paragraph {
|
||||||
|
widget := widgets.NewParagraph()
|
||||||
|
widget.Text = "Press q to quit, Press <Left> or <Right> to switch tabs"
|
||||||
|
widget.SetRect(0, 0, 50, 1)
|
||||||
|
widget.Border = false
|
||||||
|
widget.TextStyle.Bg = ui.ColorBlue
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnectorsView() *ui.Grid {
|
||||||
|
grid := ui.NewGrid()
|
||||||
|
|
||||||
|
termWidth, termHeight := ui.TerminalDimensions()
|
||||||
|
grid.SetRect(0, headerHeight, termWidth, termHeight)
|
||||||
|
|
||||||
|
var conn [connectorsCount + 1]*widgets.Paragraph //ui.GridItem
|
||||||
|
|
||||||
|
for i := 0; i <= connectorsCount; i++ {
|
||||||
|
p := widgets.NewParagraph()
|
||||||
|
p.Text = fmt.Sprintf("No data: #%2.d", i)
|
||||||
|
p.Title = fmt.Sprintf("Connector: #%2.d", i)
|
||||||
|
//p.SetRect(0, 0, 50, 30)
|
||||||
|
p.TextStyle.Bg = ui.ColorBlue
|
||||||
|
p.TextStyle.Fg = ui.ColorWhite
|
||||||
|
p.BorderStyle.Fg = ui.ColorYellow
|
||||||
|
p.Border = true
|
||||||
|
|
||||||
|
connUI[i] = p
|
||||||
|
conn[i] = p //ui.NewCol(1.0/6, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.Set(
|
||||||
|
ui.NewRow(
|
||||||
|
1.0/2,
|
||||||
|
ui.NewCol(1.0/4, conn[1]),
|
||||||
|
ui.NewCol(1.0/4, conn[2]),
|
||||||
|
ui.NewCol(1.0/4, conn[3]),
|
||||||
|
ui.NewCol(1.0/4, conn[4]),
|
||||||
|
),
|
||||||
|
ui.NewRow(
|
||||||
|
1.0/2,
|
||||||
|
ui.NewCol(1.0/4, conn[5]),
|
||||||
|
ui.NewCol(1.0/4, conn[6]),
|
||||||
|
ui.NewCol(1.0/4, conn[0]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
|
func newContactorsView() *ui.Grid {
|
||||||
|
grid := ui.NewGrid()
|
||||||
|
|
||||||
|
termWidth, termHeight := ui.TerminalDimensions()
|
||||||
|
grid.SetRect(0, headerHeight, termWidth, termHeight)
|
||||||
|
|
||||||
|
var cont [contactorsCount + 1]ui.GridItem
|
||||||
|
|
||||||
|
//var contactors = make([]ui.GridItem, contactorsCount)
|
||||||
|
for i := 1; i <= contactorsCount; i++ {
|
||||||
|
p := widgets.NewParagraph()
|
||||||
|
p.Text = fmt.Sprintf("No data: #%2.d", i)
|
||||||
|
p.Title = fmt.Sprintf("Contactor: #%2.d", i)
|
||||||
|
p.Border = false
|
||||||
|
p.TextStyle.Bg = ui.ColorBlue
|
||||||
|
p.TextStyle.Fg = ui.ColorWhite
|
||||||
|
p.BorderStyle.Fg = ui.ColorYellow
|
||||||
|
p.Border = true
|
||||||
|
|
||||||
|
contUI[i] = p
|
||||||
|
cont[i] = ui.NewCol(1.0/6, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.Set(
|
||||||
|
ui.NewRow(
|
||||||
|
1.0/3,
|
||||||
|
cont[1],
|
||||||
|
cont[2],
|
||||||
|
cont[3],
|
||||||
|
cont[4],
|
||||||
|
cont[5],
|
||||||
|
cont[6],
|
||||||
|
),
|
||||||
|
ui.NewRow(
|
||||||
|
1.0/3,
|
||||||
|
cont[7],
|
||||||
|
cont[8],
|
||||||
|
cont[9],
|
||||||
|
cont[10],
|
||||||
|
cont[11],
|
||||||
|
cont[12],
|
||||||
|
),
|
||||||
|
ui.NewRow(
|
||||||
|
1.0/3,
|
||||||
|
cont[13],
|
||||||
|
cont[14],
|
||||||
|
cont[15],
|
||||||
|
cont[16],
|
||||||
|
cont[17],
|
||||||
|
cont[18],
|
||||||
|
))
|
||||||
|
|
||||||
|
//ui.NewRow(1, ui.InterfaceSlice(contactors)...)
|
||||||
|
grid.Set()
|
||||||
|
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
|
func newContactorsErrView() *widgets.Paragraph {
|
||||||
|
p := widgets.NewParagraph()
|
||||||
|
p.Text = "No data\n"
|
||||||
|
p.Title = "Contactors Errors"
|
||||||
|
p.SetRect(5, 5, 55, 15)
|
||||||
|
p.BorderStyle.Fg = ui.ColorYellow
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContactorsView(unitId uint) {
|
||||||
|
p := contUI[unitId]
|
||||||
|
s := contactors[unitId].state
|
||||||
|
|
||||||
|
if s == nil || p == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Text = fmt.Sprintf(
|
||||||
|
"BoardReady: %s\nContactorOn: %s\nUnexpectedState: %s\nIsolated: %s\nDebug: %s",
|
||||||
|
s.ContactorReady,
|
||||||
|
s.ContactorOn,
|
||||||
|
s.UnexpectedState,
|
||||||
|
s.Isolated,
|
||||||
|
s.DebugEnabled)
|
||||||
|
|
||||||
|
if s.ContactorReady == yabl.BOARD_READY_OK {
|
||||||
|
p.TextStyle.Bg = ui.ColorClear
|
||||||
|
} else {
|
||||||
|
p.TextStyle.Bg = ui.ColorRed
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ContactorOn == yabl.ON {
|
||||||
|
p.TitleStyle.Bg = ui.ColorBlue
|
||||||
|
} else {
|
||||||
|
p.TitleStyle.Bg = ui.ColorClear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateConnectorsView(unitId uint) {
|
||||||
|
p := connUI[unitId]
|
||||||
|
s := connectors[unitId].state
|
||||||
|
e := connectors[unitId].energy
|
||||||
|
|
||||||
|
if s == nil || e == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fstring := "ConnectorInsert %s\n" +
|
||||||
|
"ContactorOn %s\n" +
|
||||||
|
"ConnectorLocked %s\n" +
|
||||||
|
"LineLevel %s\n" +
|
||||||
|
"IsolationState %s\n" +
|
||||||
|
"ChargingAllowed %s\n" +
|
||||||
|
"PwmEnabled %s\n" +
|
||||||
|
"CpLineVoltage %s\n" +
|
||||||
|
"V2GMode %s\n" +
|
||||||
|
"VoltageBefore %s\n" +
|
||||||
|
"VoltageAfter %s\n" +
|
||||||
|
"PresentCurrent %s"
|
||||||
|
|
||||||
|
p.Text = fmt.Sprintf(
|
||||||
|
fstring,
|
||||||
|
s.ConnectorInsert,
|
||||||
|
s.ContactorOn,
|
||||||
|
s.ConnectorLocked,
|
||||||
|
s.CpLineLevel,
|
||||||
|
s.IsolationState,
|
||||||
|
s.ChargingAllowed,
|
||||||
|
s.PwmEnabled,
|
||||||
|
s.CpLineVoltage,
|
||||||
|
e.V2GMode,
|
||||||
|
e.VoltageBefore,
|
||||||
|
e.VoltageAfter,
|
||||||
|
e.PresentCurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContactorsStateView() {
|
||||||
|
p := contactorsErr
|
||||||
|
|
||||||
|
if contactors[1] == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e := contactors[1].errors
|
||||||
|
|
||||||
|
if e == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Text = fmt.Sprintf(
|
||||||
|
"BoardReady: %s\nOtherError: %s\nGroupChanged: %s\nUnexpectedFormation: %s\nCpuNotReady: %s\nPuNotReady: %s\nDebug: %s",
|
||||||
|
e.BoardReady,
|
||||||
|
e.OtherError,
|
||||||
|
e.ContactorGroupChanged,
|
||||||
|
e.UnexpectedFormation,
|
||||||
|
e.CpuNotReady,
|
||||||
|
e.PuNotReady,
|
||||||
|
e.Debug,
|
||||||
|
)
|
||||||
|
|
||||||
|
if e.BoardReady == yabl.BOARD_READY_OK {
|
||||||
|
p.TextStyle.Bg = ui.ColorClear
|
||||||
|
} else {
|
||||||
|
p.TextStyle.Bg = ui.ColorRed
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
package yabl
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func (t BooleanType) String() string {
|
||||||
|
switch t {
|
||||||
|
case ON:
|
||||||
|
return "ON"
|
||||||
|
case OFF:
|
||||||
|
return "OFF"
|
||||||
|
default:
|
||||||
|
panic("BooleanType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t ErrorType) String() string {
|
||||||
|
switch t {
|
||||||
|
case NO_ERROR:
|
||||||
|
return "OK"
|
||||||
|
case ERROR:
|
||||||
|
return "ERROR"
|
||||||
|
default:
|
||||||
|
panic("ErrorType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t BoardReadyType) String() string {
|
||||||
|
switch t {
|
||||||
|
case BOARD_READY_OK:
|
||||||
|
return "OK"
|
||||||
|
case BOARD_READY_INFO:
|
||||||
|
return "INFO"
|
||||||
|
case BOARD_READY_WARNING:
|
||||||
|
return "WARNING"
|
||||||
|
case BOARD_READY_DEBUG:
|
||||||
|
return "DEBUG"
|
||||||
|
case BOARD_READY_DEP_ERROR:
|
||||||
|
return "DEP_ERROR"
|
||||||
|
case BOARD_READY_ERROR:
|
||||||
|
return "ERROR"
|
||||||
|
case BOARD_READY_CRITICAL:
|
||||||
|
return "CRITICAL"
|
||||||
|
default:
|
||||||
|
panic("BoardReadyType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t ContactorInternalOtherErrorType) String() string {
|
||||||
|
switch t {
|
||||||
|
case OTHER_NO_ERROR:
|
||||||
|
return "OK"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("ERROR_CODE_%d", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t ContactorGroupChangedType) String() string {
|
||||||
|
switch t {
|
||||||
|
case NO_PENDING_CHANGES:
|
||||||
|
return "NO_PENDING"
|
||||||
|
case INITIALIZED_CHANGE:
|
||||||
|
return "INITIALIZED"
|
||||||
|
case CHANGE_IN_PROGRESS:
|
||||||
|
return "IN_PROGRESS"
|
||||||
|
default:
|
||||||
|
panic("ContactorGroupChangedType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t V2GModeType) String() string {
|
||||||
|
switch t {
|
||||||
|
case V2G_MODE_G2V:
|
||||||
|
return "G2V"
|
||||||
|
case V2G_MODE_V2G:
|
||||||
|
return "V2G"
|
||||||
|
case V2G_MODE_INV:
|
||||||
|
return "INV"
|
||||||
|
default:
|
||||||
|
panic("V2GModeType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Voltage11BitType) String() string {
|
||||||
|
return fmt.Sprintf("%dV", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Current10BitType) String() string {
|
||||||
|
return fmt.Sprintf("%dA", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t CpLineLevelType) String() string {
|
||||||
|
switch t {
|
||||||
|
case NOT_ENABLE:
|
||||||
|
return "NOT_ENABLE"
|
||||||
|
case TWELVE:
|
||||||
|
return "12V_NOT_CONNECTED"
|
||||||
|
case NINE:
|
||||||
|
return "9V_CONNECTED"
|
||||||
|
case SIX:
|
||||||
|
return "6V_CHARGING"
|
||||||
|
case THREE:
|
||||||
|
return "3V"
|
||||||
|
case MINUS_TWELVE:
|
||||||
|
return "-12V"
|
||||||
|
default:
|
||||||
|
panic("CpLineLevelType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t IsolationStateType) String() string {
|
||||||
|
switch t {
|
||||||
|
case UNKNOWN:
|
||||||
|
return "UNKNOWN"
|
||||||
|
case ONGOING:
|
||||||
|
return "ONGOING"
|
||||||
|
case PASSED:
|
||||||
|
return "PASSED"
|
||||||
|
case WARNING:
|
||||||
|
return "WARNING"
|
||||||
|
case FAILED:
|
||||||
|
return "FAILED"
|
||||||
|
default:
|
||||||
|
panic("IsolationStateType not defended")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Voltage9BitType) String() string {
|
||||||
|
return fmt.Sprintf("%.1fV", t)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user