mirror of
https://github.com/wisplite/parchment.git
synced 2026-06-27 13:47:08 -05:00
upload page added + parchment properly waits for ack command
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ type Device struct {
|
|||||||
Connected bool
|
Connected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commandAck = []byte{0xAA, 0x06, 0x00, 0x00, 0x00}
|
||||||
|
|
||||||
// NewDevice creates a new Device instance.
|
// NewDevice creates a new Device instance.
|
||||||
func NewDevice() *Device {
|
func NewDevice() *Device {
|
||||||
return &Device{}
|
return &Device{}
|
||||||
@@ -51,18 +54,16 @@ func (d *Device) Connect() error {
|
|||||||
|
|
||||||
d.Port = port
|
d.Port = port
|
||||||
d.Connected = true
|
d.Connected = true
|
||||||
|
_ = d.Port.SetReadTimeout(100 * time.Millisecond)
|
||||||
|
|
||||||
// Send dev mode request
|
// Send dev mode request
|
||||||
// 0xAA 0x04 0x00 0x00 0x00 is the command sequence for dev mode
|
// 0xAA 0x04 0x00 0x00 0x00 is the command sequence for dev mode
|
||||||
_, err = d.Port.Write([]byte{0xAA, 0x04, 0x00, 0x00, 0x00})
|
err = d.sendCommand([]byte{0xAA, 0x04, 0x00, 0x00, 0x00})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.Close()
|
d.Close()
|
||||||
return fmt.Errorf("failed to send dev mode request: %w", err)
|
return fmt.Errorf("failed to enter dev mode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow some time for the device to respond or settle if needed
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,14 +74,10 @@ func (d *Device) ExitDevMode() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// disable dev mode
|
// disable dev mode
|
||||||
_, err := d.Port.Write([]byte{0xAA, 0x05, 0x00, 0x00, 0x00})
|
if err := d.sendCommand([]byte{0xAA, 0x05, 0x00, 0x00, 0x00}); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("failed to exit dev mode: %w", err)
|
||||||
return fmt.Errorf("failed to send exit dev mode command: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow some time for the device to respond or settle if needed
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,3 +105,57 @@ func (d *Device) Write(data []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
return d.Port.Write(data)
|
return d.Port.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Device) sendCommand(cmd []byte) error {
|
||||||
|
if d.Port == nil {
|
||||||
|
return fmt.Errorf("port not open")
|
||||||
|
}
|
||||||
|
if _, err := d.Port.Write(cmd); err != nil {
|
||||||
|
return fmt.Errorf("failed to send command: %w", err)
|
||||||
|
}
|
||||||
|
if err := d.waitForResponse(commandAck, 2*time.Second); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) waitForResponse(expected []byte, timeout time.Duration) error {
|
||||||
|
if d.Port == nil {
|
||||||
|
return fmt.Errorf("port not open")
|
||||||
|
}
|
||||||
|
if len(expected) == 0 {
|
||||||
|
return fmt.Errorf("expected response is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
deadline := time.NewTimer(timeout)
|
||||||
|
defer deadline.Stop()
|
||||||
|
|
||||||
|
readBuf := make([]byte, 64)
|
||||||
|
window := make([]byte, 0, len(expected)*4)
|
||||||
|
maxWindow := len(expected) * 4
|
||||||
|
if maxWindow < 64 {
|
||||||
|
maxWindow = 64
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-deadline.C:
|
||||||
|
return fmt.Errorf("timeout waiting for response %x", expected)
|
||||||
|
default:
|
||||||
|
n, err := d.Port.Read(readBuf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed while waiting for response: %w", err)
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
window = append(window, readBuf[:n]...)
|
||||||
|
if len(window) > maxWindow {
|
||||||
|
window = window[len(window)-maxWindow:]
|
||||||
|
}
|
||||||
|
if bytes.Contains(window, expected) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ func MonitorDevice(ctx context.Context, app *tview.Application, frame **tview.Fr
|
|||||||
err = device.Connect()
|
err = device.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
UpdateDeviceStatus(app, *frame, state, "Error connecting to cardputer: "+err.Error(), tcell.ColorRed)
|
UpdateDeviceStatus(app, *frame, state, "Error connecting to cardputer: "+err.Error(), tcell.ColorRed)
|
||||||
|
SetError(state, err.Error())
|
||||||
} else {
|
} else {
|
||||||
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
UpdateDeviceStatus(app, *frame, state, "Connected to cardputer: "+port, tcell.ColorGreen)
|
||||||
if state.Error == "Cardputer disconnected" {
|
if state.Error == "Cardputer disconnected" {
|
||||||
@@ -69,7 +70,7 @@ func main() {
|
|||||||
Page: "home",
|
Page: "home",
|
||||||
Error: "",
|
Error: "",
|
||||||
}
|
}
|
||||||
frame := AppUI(app, ¤tFrame, state)
|
frame := AppUI(app, ¤tFrame, state, device)
|
||||||
currentFrame = frame
|
currentFrame = frame
|
||||||
app.SetRoot(frame, true)
|
app.SetRoot(frame, true)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/navidys/tvxwidgets"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,15 +14,26 @@ type UIState struct {
|
|||||||
Success string
|
Success string
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
func AppUI(app *tview.Application, currentFrame **tview.Frame, state *UIState, device *Device) *tview.Frame {
|
||||||
list := tview.NewList()
|
list := tview.NewList()
|
||||||
list.AddItem("CPkg Tools", "Create and unpack cpkg files for distribution", 'c', func() {
|
list.AddItem("CPkg Tools", "Create and unpack cpkg files for distribution", 'c', func() {
|
||||||
newFrame := PackageUI(app, currentFrame, state)
|
newFrame := PackageUI(app, currentFrame, state, device)
|
||||||
*currentFrame = newFrame
|
*currentFrame = newFrame
|
||||||
state.Page = "package"
|
state.Page = "package"
|
||||||
app.SetRoot(newFrame, true)
|
app.SetRoot(newFrame, true)
|
||||||
})
|
})
|
||||||
list.AddItem("Upload to Cardputer", "Creates a package and uploads it to the connected Cardputer", 'u', nil)
|
list.AddItem("Upload to Cardputer", "Creates a package and uploads it to the connected Cardputer", 'u', func() {
|
||||||
|
if !device.Connected {
|
||||||
|
SetError(state, "No cardputer connected")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
SetSuccess(state, "Upload started")
|
||||||
|
}
|
||||||
|
newFrame := UploadUI(app, currentFrame, state, device)
|
||||||
|
*currentFrame = newFrame
|
||||||
|
state.Page = "upload"
|
||||||
|
app.SetRoot(newFrame, true)
|
||||||
|
})
|
||||||
list.AddItem("Live Refresh", "Monitors for changes and automatically uploads to the Cardputer (WIP)", 'l', nil)
|
list.AddItem("Live Refresh", "Monitors for changes and automatically uploads to the Cardputer (WIP)", 'l', nil)
|
||||||
frame := tview.NewFrame(list)
|
frame := tview.NewFrame(list)
|
||||||
frame.SetBorders(0, 0, 0, 0, 0, 0)
|
frame.SetBorders(0, 0, 0, 0, 0, 0)
|
||||||
@@ -41,7 +53,19 @@ func SetSuccess(state *UIState, text string) {
|
|||||||
state.Success = text
|
state.Success = text
|
||||||
}
|
}
|
||||||
|
|
||||||
func PackageUI(app *tview.Application, currentFrame **tview.Frame, state *UIState) *tview.Frame {
|
func UploadUI(app *tview.Application, currentFrame **tview.Frame, state *UIState, device *Device) *tview.Frame {
|
||||||
|
list := tview.NewFlex()
|
||||||
|
list.SetDirection(tview.FlexRow)
|
||||||
|
progress := tvxwidgets.NewPercentageModeGauge()
|
||||||
|
progress.SetValue(0)
|
||||||
|
progress.SetMaxValue(100)
|
||||||
|
progress.SetBorder(true)
|
||||||
|
progress.SetTitle("Upload Progress")
|
||||||
|
list.AddItem(progress, 0, 1, false)
|
||||||
|
return tview.NewFrame(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PackageUI(app *tview.Application, currentFrame **tview.Frame, state *UIState, device *Device) *tview.Frame {
|
||||||
list := tview.NewList()
|
list := tview.NewList()
|
||||||
list.AddItem("Create Package", "Creates a .cpkg file in the running directory", 'c', func() {
|
list.AddItem("Create Package", "Creates a .cpkg file in the running directory", 'c', func() {
|
||||||
fsys := os.DirFS(".")
|
fsys := os.DirFS(".")
|
||||||
@@ -63,7 +87,7 @@ func PackageUI(app *tview.Application, currentFrame **tview.Frame, state *UIStat
|
|||||||
})
|
})
|
||||||
list.AddItem("Unpack Package", "Unpacks a chosen .cpkg file into a subdirectory", 'u', nil)
|
list.AddItem("Unpack Package", "Unpacks a chosen .cpkg file into a subdirectory", 'u', nil)
|
||||||
list.AddItem("Back", "Go back to the home page", 'b', func() {
|
list.AddItem("Back", "Go back to the home page", 'b', func() {
|
||||||
newFrame := AppUI(app, currentFrame, state)
|
newFrame := AppUI(app, currentFrame, state, device)
|
||||||
*currentFrame = newFrame
|
*currentFrame = newFrame
|
||||||
state.Page = "home"
|
state.Page = "home"
|
||||||
app.SetRoot(newFrame, true)
|
app.SetRoot(newFrame, true)
|
||||||
@@ -83,6 +107,8 @@ func UpdateDeviceStatus(app *tview.Application, frame *tview.Frame, state *UISta
|
|||||||
frame.AddText("Parchment - v0.0.1", true, tview.AlignLeft, tcell.ColorWhite)
|
frame.AddText("Parchment - v0.0.1", true, tview.AlignLeft, tcell.ColorWhite)
|
||||||
case "package":
|
case "package":
|
||||||
frame.AddText("Package Tools", true, tview.AlignLeft, tcell.ColorWhite)
|
frame.AddText("Package Tools", true, tview.AlignLeft, tcell.ColorWhite)
|
||||||
|
case "upload":
|
||||||
|
frame.AddText("Uploading to Cardputer - Do not disconnect the cardputer until the upload is complete", true, tview.AlignLeft, tcell.ColorWhite)
|
||||||
}
|
}
|
||||||
if state.Error != "" {
|
if state.Error != "" {
|
||||||
frame.AddText(state.Error, false, tview.AlignRight, tcell.ColorRed)
|
frame.AddText(state.Error, false, tview.AlignRight, tcell.ColorRed)
|
||||||
|
|||||||
Reference in New Issue
Block a user