Initial commit

This commit is contained in:
2022-12-12 12:57:02 +03:00
commit 268e784cb5
13 changed files with 1162 additions and 0 deletions
+43
View File
@@ -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
View File
@@ -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
}
+88
View File
@@ -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
View File
@@ -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
}
}