199 lines
5.4 KiB
Go
199 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"path/filepath"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/dialog"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/storage"
|
|
"fyne.io/fyne/v2/widget"
|
|
"github.com/mitchellh/mapstructure"
|
|
"go.arsenm.dev/itd/internal/types"
|
|
)
|
|
|
|
func upgradeTab(parent fyne.Window) *fyne.Container {
|
|
var (
|
|
archivePath string
|
|
firmwarePath string
|
|
initPktPath string
|
|
)
|
|
|
|
var archiveBtn *widget.Button
|
|
// Create archive selection dialog
|
|
archiveDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
|
|
if e != nil || uc == nil {
|
|
return
|
|
}
|
|
uc.Close()
|
|
archivePath = uc.URI().Path()
|
|
archiveBtn.SetText(fmt.Sprintf("Select archive (.zip) [%s]", filepath.Base(archivePath)))
|
|
}, parent)
|
|
// Limit dialog to .zip files
|
|
archiveDialog.SetFilter(storage.NewExtensionFileFilter([]string{".zip"}))
|
|
// Create button to show dialog
|
|
archiveBtn = widget.NewButton("Select archive (.zip)", archiveDialog.Show)
|
|
|
|
var firmwareBtn *widget.Button
|
|
// Create firmware selection dialog
|
|
firmwareDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
|
|
if e != nil || uc == nil {
|
|
return
|
|
}
|
|
uc.Close()
|
|
firmwarePath = uc.URI().Path()
|
|
firmwareBtn.SetText(fmt.Sprintf("Select firmware (.bin) [%s]", filepath.Base(firmwarePath)))
|
|
}, parent)
|
|
// Limit dialog to .bin files
|
|
firmwareDialog.SetFilter(storage.NewExtensionFileFilter([]string{".bin"}))
|
|
// Create button to show dialog
|
|
firmwareBtn = widget.NewButton("Select firmware (.bin)", firmwareDialog.Show)
|
|
|
|
var initPktBtn *widget.Button
|
|
// Create init packet selection dialog
|
|
initPktDialog := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
|
|
if e != nil || uc == nil {
|
|
return
|
|
}
|
|
uc.Close()
|
|
initPktPath = uc.URI().Path()
|
|
initPktBtn.SetText(fmt.Sprintf("Select init packet (.dat) [%s]", filepath.Base(initPktPath)))
|
|
}, parent)
|
|
// Limit dialog to .dat files
|
|
initPktDialog.SetFilter(storage.NewExtensionFileFilter([]string{".dat"}))
|
|
// Create button to show dialog
|
|
initPktBtn = widget.NewButton("Select init packet (.dat)", initPktDialog.Show)
|
|
|
|
// Hide init packet and firmware buttons
|
|
initPktBtn.Hide()
|
|
firmwareBtn.Hide()
|
|
|
|
// Create dropdown to select upgrade type
|
|
upgradeTypeSelect := widget.NewSelect([]string{
|
|
"Archive",
|
|
"Files",
|
|
}, func(s string) {
|
|
// Hide all buttons
|
|
archiveBtn.Hide()
|
|
initPktBtn.Hide()
|
|
firmwareBtn.Hide()
|
|
// Unhide appropriate button(s)
|
|
switch s {
|
|
case "Archive":
|
|
archiveBtn.Show()
|
|
case "Files":
|
|
initPktBtn.Show()
|
|
firmwareBtn.Show()
|
|
}
|
|
})
|
|
// Select first elemetn
|
|
upgradeTypeSelect.SetSelectedIndex(0)
|
|
|
|
// Create new button to start DFU
|
|
startBtn := widget.NewButton("Start", func() {
|
|
// If archive path does not exist and both init packet and firmware paths
|
|
// also do not exist, return error
|
|
if archivePath == "" && (initPktPath == "" && firmwarePath == "") {
|
|
guiErr(nil, "Upgrade requires archive or files selected", false, parent)
|
|
return
|
|
}
|
|
|
|
// Create new label for byte progress
|
|
progressLbl := widget.NewLabelWithStyle("0 / 0 B", fyne.TextAlignCenter, fyne.TextStyle{})
|
|
// Create new progress bar
|
|
progressBar := widget.NewProgressBar()
|
|
// Create modal dialog containing label and progress bar
|
|
progressDlg := widget.NewModalPopUp(container.NewVBox(
|
|
layout.NewSpacer(),
|
|
progressLbl,
|
|
progressBar,
|
|
layout.NewSpacer(),
|
|
), parent.Canvas())
|
|
// Resize modal to 300x100
|
|
progressDlg.Resize(fyne.NewSize(300, 100))
|
|
|
|
var fwUpgType int
|
|
var files []string
|
|
// Get appropriate upgrade type and file paths
|
|
switch upgradeTypeSelect.Selected {
|
|
case "Archive":
|
|
fwUpgType = types.UpgradeTypeArchive
|
|
files = append(files, archivePath)
|
|
case "Files":
|
|
fwUpgType = types.UpgradeTypeFiles
|
|
files = append(files, initPktPath, firmwarePath)
|
|
}
|
|
|
|
// Dial itd UNIX socket
|
|
conn, err := net.Dial("unix", SockPath)
|
|
if err != nil {
|
|
guiErr(err, "Error dialing socket", false, parent)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Encode firmware upgrade request to connection
|
|
json.NewEncoder(conn).Encode(types.Request{
|
|
Type: types.ReqTypeFwUpgrade,
|
|
Data: types.ReqDataFwUpgrade{
|
|
Type: fwUpgType,
|
|
Files: files,
|
|
},
|
|
})
|
|
|
|
// Show progress dialog
|
|
progressDlg.Show()
|
|
// Hide progress dialog after completion
|
|
defer progressDlg.Hide()
|
|
|
|
scanner := bufio.NewScanner(conn)
|
|
for scanner.Scan() {
|
|
var res types.Response
|
|
// Decode scanned line into response struct
|
|
err = json.Unmarshal(scanner.Bytes(), &res)
|
|
if err != nil {
|
|
guiErr(err, "Error decoding response", false, parent)
|
|
return
|
|
}
|
|
if res.Error {
|
|
guiErr(err, "Error returned in response", false, parent)
|
|
return
|
|
}
|
|
var event types.DFUProgress
|
|
// Decode response data into progress struct
|
|
err = mapstructure.Decode(res.Value, &event)
|
|
if err != nil {
|
|
guiErr(err, "Error decoding response value", false, parent)
|
|
return
|
|
}
|
|
// Set label text to received / total B
|
|
progressLbl.SetText(fmt.Sprintf("%d / %d B", event.Received, event.Total))
|
|
// Set progress bar values
|
|
progressBar.Max = float64(event.Total)
|
|
progressBar.Value = float64(event.Received)
|
|
// Refresh progress bar
|
|
progressBar.Refresh()
|
|
// If transfer finished, break
|
|
if event.Received == event.Total {
|
|
break
|
|
}
|
|
}
|
|
})
|
|
|
|
// Return container containing all elements
|
|
return container.NewVBox(
|
|
layout.NewSpacer(),
|
|
upgradeTypeSelect,
|
|
archiveBtn,
|
|
firmwareBtn,
|
|
initPktBtn,
|
|
startBtn,
|
|
layout.NewSpacer(),
|
|
)
|
|
}
|