1package onelead
2
3import (
4 "bytes"
5 "fmt"
6 "odoki/constants"
7 "odoki/ui/components"
8 "odoki/utils"
9 "strconv"
10 "time"
11
12 "fyne.io/fyne/v2"
13 "fyne.io/fyne/v2/canvas"
14 "fyne.io/fyne/v2/container"
15 "fyne.io/fyne/v2/layout"
16 "fyne.io/fyne/v2/theme"
17 "fyne.io/fyne/v2/widget"
18
19 "github.com/wcharczuk/go-chart/v2"
20 "github.com/wcharczuk/go-chart/v2/drawing"
21)
22
23var buf = new(bytes.Buffer)
24var LeadBuffer = [constants.ChannelCount][]int32{}
25var heartRateLabel *widget.Label
26
27func updateLeadChart() {
28 buf = new(bytes.Buffer)
29 fr, fg, fb, fa := theme.ForegroundColor().RGBA()
30 br, bg, bb, ba := theme.BackgroundColor().RGBA()
31
32 var xValues [constants.ChannelCount][]float64
33 var yValues [constants.ChannelCount][]float64
34 if len(LeadBuffer[0]) < 2 {
35 for i := range LeadBuffer {
36 xValues[i] = []float64{0, 1}
37 yValues[i] = []float64{0, 1}
38 }
39 }
40 for i, channel := range LeadBuffer {
41 for j, sample := range channel {
42 xValues[i] = append(xValues[i], float64(j)*float64(constants.BufferDuration)/float64(constants.BufferSize))
43 yValues[i] = append(yValues[i], float64(sample)/float64(constants.LeadMaxBValue)*float64(constants.LeadMaxVValue))
44 }
45 }
46 // Create a bar chart.
47 graph := chart.Chart{
48 //Title: "Measured Voltage (mV) vs Time (s)",
49 Background: chart.Style{
50 FillColor: drawing.Color{R: uint8(br), G: uint8(bg), B: uint8(bb), A: uint8(ba)}, // will supercede defaults
51 StrokeColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
52 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
53 },
54 Canvas: chart.Style{
55 FillColor: drawing.Color{R: uint8(br), G: uint8(bg), B: uint8(bb), A: uint8(ba)},
56 StrokeColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
57 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
58 },
59 XAxis: chart.XAxis{
60 Style: chart.Style{
61 StrokeColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
62 FillColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
63 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
64 DotColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
65 },
66 },
67 YAxis: chart.YAxis{
68 Style: chart.Style{
69 StrokeColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
70 FillColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
71 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
72 },
73 },
74 TitleStyle: chart.Style{
75 StrokeColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
76 FillColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
77 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
78 },
79 Series: []chart.Series{
80 chart.ContinuousSeries{
81 Style: chart.Style{
82 StrokeColor: constants.TraceColor, // will supercede defaults
83 FontColor: drawing.Color{R: uint8(fr), G: uint8(fg), B: uint8(fb), A: uint8(fa)}, // will supercede defaults
84 },
85 XValues: xValues[0],
86 YValues: yValues[0],
87 },
88 },
89 }
90
91 // Render the bar chart to a byte array.
92
93 err := graph.Render(chart.PNG, buf)
94 utils.Must("render bar chart", err)
95}
96
97func updateLoop(cimage *canvas.Image) {
98 k := 0
99 for {
100 time.Sleep(1 * time.Second)
101 updateLeadChart()
102 cimage.Resource = fyne.NewStaticResource("barChart", buf.Bytes())
103 cimage.Refresh()
104 fmt.Println("updateLoop")
105 k++
106 }
107}
108
109func UpdateHeartrate(heartRate uint8) {
110 heartRateLabel.Text = strconv.Itoa(int(heartRate)) + " BPM"
111 heartRateLabel.Refresh()
112}
113
114func Widget() fyne.CanvasObject {
115 updateLeadChart()
116 cimage := canvas.NewImageFromReader(buf, "barChart")
117 cimage.FillMode = canvas.ImageFillOriginal
118 go updateLoop(cimage)
119
120 heartRateLabel = widget.NewLabel("-- BPM")
121
122 return container.NewPadded(container.NewVBox(
123 components.TabTitle("1 Lead"),
124 heartRateLabel,
125 container.New(layout.NewStackLayout(), cimage),
126 ))
127}