package main import ( "fmt" "io/ioutil" "log" "os" "path" "time" "git.wow.st/gmp/ble" "gopkg.in/yaml.v2" "gioui.org/app" "gioui.org/io/system" "gioui.org/layout" "gioui.org/unit" "gioui.org/text" "gioui.org/widget" "gioui.org/widget/material" _ "gioui.org/font/gofont" ) type conf struct { } var Config conf func main() { conffile := path.Join(confDir, "config.yml") if _, err := os.Stat(conffile); os.IsNotExist(err) { fd, err := os.Create(conffile) if err != nil { log.Fatal("Cannot create configuration file: ", err) } fd.Close() } confbytes, err := ioutil.ReadFile(conffile) if err != nil { log.Fatal("Cannot read configuration file: ", err) } if err = yaml.UnmarshalStrict(confbytes, &Config); err != nil { log.Fatal("Cannot parse configuration file: ", err) } go eventloop() app.Main() } func eventloop() { w := app.NewWindow( app.Size(unit.Dp(400), unit.Dp(400)), app.Title("HRM"), ) th := material.NewTheme() gtx := &layout.Context{Queue: w.Queue()} sysinset := &layout.Inset{} resetSysinset := func(x system.Insets) { sysinset.Top = x.Top sysinset.Bottom = x.Bottom sysinset.Left = x.Left sysinset.Right = x.Right } margin := layout.UniformInset(unit.Dp(10)) b := ble.NewBLE() b.Scan() state := "starting" var periph ble.Peripheral periphs := make([]ble.Peripheral,0) btns := make([]*widget.Button,0) var autoconnectID string var page, scanpage, connpage, hrpage func() f := &layout.Flex{Axis: layout.Vertical} scanpage = func() { c1 := f.Rigid(gtx, func() { th.Body1("Heart Rate Monitor").Layout(gtx) }) c2 := f.Rigid(gtx, func() { th.Body1(state).Layout(gtx) }) c3 := f.Rigid(gtx, func() { lst := &layout.List{Axis: layout.Vertical} lst.Layout(gtx, len(periphs), func(i int) { th.Button(periphs[i].Name).Layout(gtx, btns[i]) if btns[i].Clicked(gtx) { periph = periphs[i] b.StopScan() b.Connect(periph) page = connpage w.Invalidate() } }) }) lst := &layout.List{Axis: layout.Vertical} lst.Layout(gtx, 1, func(i int) { f.Layout(gtx, c1, c2, c3) }) } connpage = func() { c1 := f.Rigid(gtx, func() { th.Body1("Heart Rate Monitor").Layout(gtx) }) c2 := f.Rigid(gtx, func() { th.Body1("Connecting").Layout(gtx) }) c3 := f.Rigid(gtx, func() { th.Body1(periph.Name).Layout(gtx) }) f.Layout(gtx, c1, c2, c3) } hrpage = func() { c1 := f.Rigid(gtx, func() { th.Body1("Heart Rate Monitor").Layout(gtx) }) c2 := f.Rigid(gtx, func() { th.Body1(periph.Name).Layout(gtx) }) c3 := f.Rigid(gtx, func() { l := th.H1(fmt.Sprintf("%d",b.HR())) l.Alignment = text.Middle l.Layout(gtx) }) f.Layout(gtx, c1, c2, c3) } page = scanpage tick := time.NewTicker(time.Second / 30) events := b.Events() for { select { case e := <-events: switch e := e.(type) { case ble.UpdateStateEvent: state = e.State case ble.DiscoverEvent: fmt.Printf("found %s\n", e.Peripheral.Identifier()) periphs = append(periphs, e.Peripheral) //btns = append(btns, th.Button(e.Peripheral.Name)) btns = append(btns, &widget.Button{}) fmt.Printf("len(periphs) = %d\n", len(periphs)) if e.Peripheral.Identifier() == autoconnectID { b.Connect(e.Peripheral) } case ble.ConnectEvent: fmt.Printf("Connect event\n") state = "connected" ble.DiscoverServices(e.Peripheral) page = hrpage w.Invalidate() } case <- tick.C: w.Invalidate() case e := <-w.Events(): switch e := e.(type) { case system.DestroyEvent: return case system.FrameEvent: gtx.Reset(e.Config, e.Size) resetSysinset(e.Insets) sysinset.Layout(gtx, func() { margin.Layout(gtx, page) }) e.Frame(gtx.Ops) } } } }