commit
268e784cb5
@ -0,0 +1,4 @@ |
|||||||
|
/cli-mon |
||||||
|
/.idea/cli-mon.iml |
||||||
|
/.idea/modules.xml |
||||||
|
/.idea/vcs.xml |
@ -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 |
@ -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 |
||||||
|
} |
@ -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 |
||||||
|
} |
@ -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) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
} |
@ -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) |
||||||
|
} |
Loading…
Reference in new issue