WIP trmnl BYOS
1package handler
2
3import (
4 "fmt"
5 "image"
6 "io"
7 "strconv"
8
9 "github.com/gin-gonic/gin"
10 "tangled.org/cdbrdr.com/scrn/internal/display"
11)
12
13const (
14 width = 800
15 height = 480
16 padding = 6
17 split = width * 0.6
18)
19
20type section struct {
21 rect image.Rectangle
22}
23
24type APIHandler struct {
25 display *display.Display
26}
27
28func NewAPIHandler(display *display.Display) *APIHandler {
29 return &APIHandler{
30 display,
31 }
32}
33
34func (h *APIHandler) HandleGroup(group *gin.RouterGroup) {
35 group.GET("/setup", h.handleSetup)
36 group.GET("/display", h.handleDisplay)
37 group.GET("/image.bmp", h.handleImage)
38 group.POST("/log", h.handleLog)
39}
40
41func (h *APIHandler) handleLog(c *gin.Context) {
42 buf, err := io.ReadAll(c.Request.Body)
43 if err != nil {
44 fmt.Println(err)
45 return
46 }
47 fmt.Println(string(buf))
48}
49
50type setupResponse struct {
51 Status int `json:"status"`
52 ApiKey *string `json:"api_key"`
53 FriendlyID *string `json:"friendly_id"`
54 ImageURL *string `json:"image_url"`
55 Filename string `json:"filename,omitempty"`
56 Message string `json:"message,omitempty"`
57}
58
59// Handle /api/setup.
60// Response:
61//
62// {
63// "status": 200,
64// "api_key": "2r--SahjsAKCFksVcped2Q",
65// "friendly_id": "917F0B",
66// "image_url": "https://usetrmnl.com/images/setup/setup-logo.bmp",
67// "filename": "empty_state"
68// }
69
70// or
71//
72// {
73// "status": 404,
74// "api_key": null,
75// "friendly_id": null,
76// "image_url": null,
77// "message": "MAC Address not registered"
78// }
79func (h *APIHandler) handleSetup(c *gin.Context) {
80
81 mac := c.Request.Header.Get("ID")
82 if mac == "" {
83 c.JSON(200, &setupResponse{
84 Status: 404,
85 Message: "MAC address missing",
86 })
87 return
88 }
89
90 apiKey := "abcdf"
91 friendlyID := mac
92 c.JSON(200, &setupResponse{
93 Status: 200,
94 ApiKey: &apiKey,
95 FriendlyID: &friendlyID,
96 })
97}
98
99type displayResponse struct {
100 Status int `json:"status"`
101 ImageURL string `json:"image_url"`
102 Filename string `json:"filename"`
103 RefreshRate int `json:"refresh_rate"`
104 SpecialFunction string `json:"special_function"`
105}
106
107// Response:
108//
109// {
110// "status": 0,
111// "image_url": "https://...",
112// "filename": "mashup-2024-12-29T16-38-16Z-28d21f.bmp",
113// "refresh_rate": 907,
114// "reset_firmware": false,
115// "update_firmware": true,
116// "firmware_url": "https://trmnl.s3.us-east-2.amazonaws.com/FW1.4.5.bin",
117// "special_function": "identify"
118// }
119func (h *APIHandler) handleDisplay(c *gin.Context) {
120 fmt.Println(c.Request.Header)
121
122 c.JSON(200, &displayResponse{
123 Status: 0,
124 ImageURL: "http://192.168.0.238:8081/api/image.bmp",
125 Filename: "image.bmp",
126 RefreshRate: 60,
127 SpecialFunction: "identify",
128 })
129}
130
131func (h *APIHandler) handleImage(c *gin.Context) {
132 fmt.Println(c.Request.Header)
133
134 img, err := h.display.RenderBMP()
135 if err != nil {
136 fmt.Println(err)
137 c.AbortWithStatus(500)
138 return
139 }
140
141 c.Header("Content-Length", strconv.Itoa(len(img)))
142 c.Data(200, "image/bmp", img)
143
144 // img := image.NewPaletted(image.Rect(0, 0, 800, 480), color.Palette{color.White, color.Black})
145
146 // // ctx := draw2dimg.NewGraphicContextWithPainter(img, util.NewPalettedPainter(img))
147
148 // for _, section := range h.sections {
149 // // Create a new sub image for the section
150 // sub := (img.SubImage(section.rect)).(*image.Paletted)
151 // // Fill it with white background
152 // draw.Draw(sub, sub.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over)
153 // // Create a draw2dimg context to pass on to the module
154 // subc := draw2dimg.NewGraphicContextWithPainter(sub, util.NewPalettedPainter(sub))
155
156 // // Draw using the module
157 // if err := section.module.Draw(subc); err != nil {
158 // fmt.Println(err)
159 // continue
160 // }
161
162 // area := image.Rect(
163 // sub.Rect.Min.X+20,
164 // sub.Rect.Min.Y+30,
165 // sub.Rect.Min.X+30,
166 // sub.Rect.Min.Y+110,
167 // )
168 // draw.Draw(sub, area, util.NewGrayImage(), image.Pt(0, 0), draw.Over)
169 // }
170
171 // // Draw separator
172 // // ctx.SetStrokeColor(color.Black)
173 // // ctx.SetLineWidth(1)
174 // // ctx.SetLineDash([]float64{2, 15}, 0)
175 // // ctx.SetLineCap(draw2d.ButtCap)
176 // // ctx.MoveTo(split, 100)
177 // // ctx.LineTo(split, height-100)
178 // // ctx.Stroke()
179
180 // p := int(height * 0.2)
181
182 // for i := p; i < height-p; i += 6 {
183 // img.Set(split, i, color.Black)
184 // }
185
186 // // split := width * 0.6
187
188 // // left := img.SubImage(image.Rect(
189 // // padding,
190 // // padding,
191 // // int(split)-(padding/2),
192 // // height-padding,
193 // // ))
194 // // limg := util.NewRoundedImage(left.(*image.Paletted), 10)
195
196 // // right := img.SubImage(image.Rect(
197 // // int(split)+(padding/2),
198 // // padding,
199 // // width-padding,
200 // // height-padding,
201 // // ))
202 // // rimg := util.NewRoundedImage(right.(*image.Paletted), 10)
203
204 // // sect := (img.SubImage(image.Rect(
205 // // int(split)+(padding/2)+20,
206 // // padding+20,
207 // // int(split)+(padding/2)+30,
208 // // padding+110,
209 // // ))).(*image.Paletted)
210
211 // // draw.Draw(limg, limg.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over)
212 // // draw.Draw(rimg, rimg.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over)
213 // // draw.Draw(sect, sect.Bounds(), util.NewGrayImage(), image.Pt(0, 0), draw.Over)
214
215 // data := bytes.NewBuffer([]byte{})
216 // bmp.Encode(data, img)
217 // buf := data.Bytes()
218 // // Fix some header values so that trmnl is happy
219 // buf[46] = 2
220 // buf[57] = 0
221 // buf[61] = 0
222
223 // c.Header("Content-Length", strconv.Itoa(len(buf)))
224 // c.Data(200, "image/bmp", buf)
225}