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}