diff --git a/api/info.go b/api/info.go index a422df7..98670a2 100644 --- a/api/info.go +++ b/api/info.go @@ -48,7 +48,7 @@ func (c *Client) BatteryLevel() (uint8, error) { func (c *Client) WatchBatteryLevel() (<-chan uint8, func(), error) { c.battLevelCh = make(chan types.Response, 2) err := c.requestNoRes(types.Request{ - Type: types.ReqTypeBattLevel, + Type: types.ReqTypeWatchBattLevel, }) if err != nil { return nil, nil, err diff --git a/cmd/itgui/info.go b/cmd/itgui/info.go index cb082aa..b5b6fa7 100644 --- a/cmd/itgui/info.go +++ b/cmd/itgui/info.go @@ -1,11 +1,9 @@ package main import ( - "bufio" "errors" "fmt" "image/color" - "net" "encoding/json" @@ -13,10 +11,11 @@ import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/theme" + "go.arsenm.dev/itd/api" "go.arsenm.dev/itd/internal/types" ) -func infoTab(parent fyne.Window) *fyne.Container { +func infoTab(parent fyne.Window, client *api.Client) *fyne.Container { infoLayout := container.NewVBox( // Add rectangle for a bit of padding canvas.NewRectangle(color.Transparent), @@ -32,13 +31,18 @@ func infoTab(parent fyne.Window) *fyne.Container { ) infoLayout.Add(heartRate) - // Watch for heart rate updates - go watch(types.ReqTypeWatchHeartRate, func(data interface{}) { - // Change text of heart rate label - heartRateLbl.Text = fmt.Sprintf("%d BPM", int(data.(float64))) - // Refresh label - heartRateLbl.Refresh() - }, parent) + fmt.Println(3) + heartRateCh, cancel, err := client.WatchHeartRate() + onClose = append(onClose, cancel) + go func() { + for heartRate := range heartRateCh { + // Change text of heart rate label + heartRateLbl.Text = fmt.Sprintf("%d BPM", heartRate) + // Refresh label + heartRateLbl.Refresh() + } + }() + fmt.Println(4) // Create label for battery level battLevelLbl := newText("0%", 24) @@ -50,32 +54,43 @@ func infoTab(parent fyne.Window) *fyne.Container { ) infoLayout.Add(battLevel) - // Watch for changes in battery level - go watch(types.ReqTypeWatchBattLevel, func(data interface{}) { - battLevelLbl.Text = fmt.Sprintf("%d%%", int(data.(float64))) - battLevelLbl.Refresh() - }, parent) + fmt.Println(5) + battLevelCh, cancel, err := client.WatchBatteryLevel() + onClose = append(onClose, cancel) + go func() { + for battLevel := range battLevelCh { + // Change text of battery level label + battLevelLbl.Text = fmt.Sprintf("%d%%", battLevel) + // Refresh label + battLevelLbl.Refresh() + } + }() + fmt.Println(6) - fwVerString, err := get(types.ReqTypeFwVersion) + fmt.Println(7) + fwVerString, err := client.Version() if err != nil { guiErr(err, "Error getting firmware string", true, parent) } + fmt.Println(8) fwVer := container.NewVBox( newText("Firmware Version", 12), - newText(fwVerString.(string), 24), + newText(fwVerString, 24), canvas.NewLine(theme.ShadowColor()), ) infoLayout.Add(fwVer) - btAddrString, err := get(types.ReqTypeBtAddress) + fmt.Println(9) + btAddrString, err := client.Address() if err != nil { panic(err) } + fmt.Println(10) btAddr := container.NewVBox( newText("Bluetooth Address", 12), - newText(btAddrString.(string), 24), + newText(btAddrString, 24), canvas.NewLine(theme.ShadowColor()), ) infoLayout.Add(btAddr) @@ -83,53 +98,6 @@ func infoTab(parent fyne.Window) *fyne.Container { return infoLayout } -func watch(req int, onRecv func(data interface{}), parent fyne.Window) error { - conn, err := net.Dial("unix", SockPath) - if err != nil { - return err - } - defer conn.Close() - err = json.NewEncoder(conn).Encode(types.Request{ - Type: req, - }) - if err != nil { - return err - } - scanner := bufio.NewScanner(conn) - for scanner.Scan() { - res, err := getResp(scanner.Bytes()) - if err != nil { - guiErr(err, "Error getting response from connection", false, parent) - continue - } - onRecv(res.Value) - } - return nil -} - -func get(req int) (interface{}, error) { - conn, err := net.Dial("unix", SockPath) - if err != nil { - return nil, err - } - defer conn.Close() - err = json.NewEncoder(conn).Encode(types.Request{ - Type: req, - }) - if err != nil { - return nil, err - } - line, _, err := bufio.NewReader(conn).ReadLine() - if err != nil { - return nil, err - } - res, err := getResp(line) - if err != nil { - return nil, err - } - return res.Value, nil -} - func getResp(line []byte) (*types.Response, error) { var res types.Response err := json.Unmarshal(line, &res) diff --git a/cmd/itgui/main.go b/cmd/itgui/main.go index 0bdf961..b5cfd29 100644 --- a/cmd/itgui/main.go +++ b/cmd/itgui/main.go @@ -1,31 +1,42 @@ package main import ( - "net" + "fmt" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/container" + "go.arsenm.dev/itd/api" ) -var SockPath = "/tmp/itd/socket" +var onClose []func() func main() { // Create new app a := app.New() // Create new window with title "itgui" window := a.NewWindow("itgui") + window.SetOnClosed(func() { + for _, closeFn := range onClose { + closeFn() + } + }) - _, err := net.Dial("unix", SockPath) + fmt.Println(1) + client, err := api.New(api.DefaultAddr) if err != nil { - guiErr(err, "Error dialing itd socket", true, window) + guiErr(err, "Error connecting to itd", true, window) } + onClose = append(onClose, func() { + client.Close() + }) + fmt.Println(2) // Create new app tabs container tabs := container.NewAppTabs( - container.NewTabItem("Info", infoTab(window)), - container.NewTabItem("Notify", notifyTab(window)), - container.NewTabItem("Set Time", timeTab(window)), - container.NewTabItem("Upgrade", upgradeTab(window)), + container.NewTabItem("Info", infoTab(window, client)), + container.NewTabItem("Notify", notifyTab(window, client)), + container.NewTabItem("Set Time", timeTab(window, client)), + container.NewTabItem("Upgrade", upgradeTab(window, client)), ) // Set tabs as window content diff --git a/cmd/itgui/notify.go b/cmd/itgui/notify.go index 51f63d6..054a386 100644 --- a/cmd/itgui/notify.go +++ b/cmd/itgui/notify.go @@ -1,17 +1,14 @@ package main import ( - "encoding/json" - "net" - "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" - "go.arsenm.dev/itd/internal/types" + "go.arsenm.dev/itd/api" ) -func notifyTab(parent fyne.Window) *fyne.Container { +func notifyTab(parent fyne.Window, client *api.Client) *fyne.Container { // Create new entry for notification title titleEntry := widget.NewEntry() titleEntry.SetPlaceHolder("Title") @@ -22,20 +19,11 @@ func notifyTab(parent fyne.Window) *fyne.Container { // Create new button to send notification sendBtn := widget.NewButton("Send", func() { - // Dial itd UNIX socket - conn, err := net.Dial("unix", SockPath) + err := client.Notify(titleEntry.Text, bodyEntry.Text) if err != nil { - guiErr(err, "Error dialing socket", false, parent) + guiErr(err, "Error sending notification", false, parent) return } - // Encode notify request on connection - json.NewEncoder(conn).Encode(types.Request{ - Type: types.ReqTypeNotify, - Data: types.ReqDataNotify{ - Title: titleEntry.Text, - Body: bodyEntry.Text, - }, - }) }) // Return new container containing all elements diff --git a/cmd/itgui/time.go b/cmd/itgui/time.go index 0fe3ac7..b093a3b 100644 --- a/cmd/itgui/time.go +++ b/cmd/itgui/time.go @@ -1,18 +1,16 @@ package main import ( - "encoding/json" - "net" "time" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" - "go.arsenm.dev/itd/internal/types" + "go.arsenm.dev/itd/api" ) -func timeTab(parent fyne.Window) *fyne.Container { +func timeTab(parent fyne.Window, client *api.Client) *fyne.Container { // Create new entry for time string timeEntry := widget.NewEntry() // Set text to current time formatter properly @@ -21,7 +19,7 @@ func timeTab(parent fyne.Window) *fyne.Container { // Create button to set current time currentBtn := widget.NewButton("Set Current", func() { timeEntry.SetText(time.Now().Format(time.RFC1123)) - setTime(true) + setTime(client, true) }) // Create button to set time inside entry @@ -33,7 +31,7 @@ func timeTab(parent fyne.Window) *fyne.Container { return } // Set time to parsed time - setTime(false, parsedTime) + setTime(client, false, parsedTime) }) // Return new container with all elements centered @@ -48,30 +46,13 @@ func timeTab(parent fyne.Window) *fyne.Container { // setTime sets the first element in the variadic parameter // if current is false, otherwise, it sets the current time. -func setTime(current bool, t ...time.Time) error { - // Dial UNIX socket - conn, err := net.Dial("unix", SockPath) - if err != nil { - return err - } - defer conn.Close() - var data string - // If current is true, use the string "now" - // otherwise, use the formatted time from the - // first element in the variadic parameter. - // "now" is more accurate than formatting - // current time as only seconds are preserved - // in that case. +func setTime(client *api.Client, current bool, t ...time.Time) error { + var err error if current { - data = "now" + err = client.SetTimeNow() } else { - data = t[0].Format(time.RFC3339) + err = client.SetTime(t[0]) } - // Encode SetTime request with above data - err = json.NewEncoder(conn).Encode(types.Request{ - Type: types.ReqTypeSetTime, - Data: data, - }) if err != nil { return err } diff --git a/cmd/itgui/upgrade.go b/cmd/itgui/upgrade.go index f2e2eb9..30a89c1 100644 --- a/cmd/itgui/upgrade.go +++ b/cmd/itgui/upgrade.go @@ -1,10 +1,7 @@ package main import ( - "bufio" - "encoding/json" "fmt" - "net" "path/filepath" "fyne.io/fyne/v2" @@ -13,11 +10,11 @@ import ( "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" - "github.com/mitchellh/mapstructure" + "go.arsenm.dev/itd/api" "go.arsenm.dev/itd/internal/types" ) -func upgradeTab(parent fyne.Window) *fyne.Container { +func upgradeTab(parent fyne.Window, client *api.Client) *fyne.Container { var ( archivePath string firmwarePath string @@ -117,7 +114,7 @@ func upgradeTab(parent fyne.Window) *fyne.Container { // Resize modal to 300x100 progressDlg.Resize(fyne.NewSize(300, 100)) - var fwUpgType int + var fwUpgType api.UpgradeType var files []string // Get appropriate upgrade type and file paths switch upgradeTypeSelect.Selected { @@ -129,48 +126,18 @@ func upgradeTab(parent fyne.Window) *fyne.Container { files = append(files, initPktPath, firmwarePath) } - // Dial itd UNIX socket - conn, err := net.Dial("unix", SockPath) + progress, err := client.FirmwareUpgrade(fwUpgType, files...) if err != nil { - guiErr(err, "Error dialing socket", false, parent) + guiErr(err, "Error initiating DFU", 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 - } + for event := range progress { // Set label text to received / total B progressLbl.SetText(fmt.Sprintf("%d / %d B", event.Received, event.Total)) // Set progress bar values @@ -179,7 +146,7 @@ func upgradeTab(parent fyne.Window) *fyne.Container { // Refresh progress bar progressBar.Refresh() // If transfer finished, break - if event.Received == event.Total { + if event.Sent == event.Total { break } }