package handler import ( "fmt" "image" "io" "strconv" "github.com/gin-gonic/gin" "tangled.org/cdbrdr.com/scrn/internal/display" ) const ( width = 800 height = 480 padding = 6 split = width * 0.6 ) type section struct { rect image.Rectangle } type APIHandler struct { display *display.Display } func NewAPIHandler(display *display.Display) *APIHandler { return &APIHandler{ display, } } func (h *APIHandler) HandleGroup(group *gin.RouterGroup) { group.GET("/setup", h.handleSetup) group.GET("/display", h.handleDisplay) group.GET("/image.bmp", h.handleImage) group.POST("/log", h.handleLog) } func (h *APIHandler) handleLog(c *gin.Context) { buf, err := io.ReadAll(c.Request.Body) if err != nil { fmt.Println(err) return } fmt.Println(string(buf)) } type setupResponse struct { Status int `json:"status"` ApiKey *string `json:"api_key"` FriendlyID *string `json:"friendly_id"` ImageURL *string `json:"image_url"` Filename string `json:"filename,omitempty"` Message string `json:"message,omitempty"` } // Handle /api/setup. // Response: // // { // "status": 200, // "api_key": "2r--SahjsAKCFksVcped2Q", // "friendly_id": "917F0B", // "image_url": "https://usetrmnl.com/images/setup/setup-logo.bmp", // "filename": "empty_state" // } // or // // { // "status": 404, // "api_key": null, // "friendly_id": null, // "image_url": null, // "message": "MAC Address not registered" // } func (h *APIHandler) handleSetup(c *gin.Context) { mac := c.Request.Header.Get("ID") if mac == "" { c.JSON(200, &setupResponse{ Status: 404, Message: "MAC address missing", }) return } apiKey := "abcdf" friendlyID := mac c.JSON(200, &setupResponse{ Status: 200, ApiKey: &apiKey, FriendlyID: &friendlyID, }) } type displayResponse struct { Status int `json:"status"` ImageURL string `json:"image_url"` Filename string `json:"filename"` RefreshRate int `json:"refresh_rate"` SpecialFunction string `json:"special_function"` } // Response: // // { // "status": 0, // "image_url": "https://...", // "filename": "mashup-2024-12-29T16-38-16Z-28d21f.bmp", // "refresh_rate": 907, // "reset_firmware": false, // "update_firmware": true, // "firmware_url": "https://trmnl.s3.us-east-2.amazonaws.com/FW1.4.5.bin", // "special_function": "identify" // } func (h *APIHandler) handleDisplay(c *gin.Context) { fmt.Println(c.Request.Header) c.JSON(200, &displayResponse{ Status: 0, ImageURL: "http://192.168.0.238:8081/api/image.bmp", Filename: "image.bmp", RefreshRate: 60, SpecialFunction: "identify", }) } func (h *APIHandler) handleImage(c *gin.Context) { fmt.Println(c.Request.Header) img, err := h.display.RenderBMP() if err != nil { fmt.Println(err) c.AbortWithStatus(500) return } c.Header("Content-Length", strconv.Itoa(len(img))) c.Data(200, "image/bmp", img) // img := image.NewPaletted(image.Rect(0, 0, 800, 480), color.Palette{color.White, color.Black}) // // ctx := draw2dimg.NewGraphicContextWithPainter(img, util.NewPalettedPainter(img)) // for _, section := range h.sections { // // Create a new sub image for the section // sub := (img.SubImage(section.rect)).(*image.Paletted) // // Fill it with white background // draw.Draw(sub, sub.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over) // // Create a draw2dimg context to pass on to the module // subc := draw2dimg.NewGraphicContextWithPainter(sub, util.NewPalettedPainter(sub)) // // Draw using the module // if err := section.module.Draw(subc); err != nil { // fmt.Println(err) // continue // } // area := image.Rect( // sub.Rect.Min.X+20, // sub.Rect.Min.Y+30, // sub.Rect.Min.X+30, // sub.Rect.Min.Y+110, // ) // draw.Draw(sub, area, util.NewGrayImage(), image.Pt(0, 0), draw.Over) // } // // Draw separator // // ctx.SetStrokeColor(color.Black) // // ctx.SetLineWidth(1) // // ctx.SetLineDash([]float64{2, 15}, 0) // // ctx.SetLineCap(draw2d.ButtCap) // // ctx.MoveTo(split, 100) // // ctx.LineTo(split, height-100) // // ctx.Stroke() // p := int(height * 0.2) // for i := p; i < height-p; i += 6 { // img.Set(split, i, color.Black) // } // // split := width * 0.6 // // left := img.SubImage(image.Rect( // // padding, // // padding, // // int(split)-(padding/2), // // height-padding, // // )) // // limg := util.NewRoundedImage(left.(*image.Paletted), 10) // // right := img.SubImage(image.Rect( // // int(split)+(padding/2), // // padding, // // width-padding, // // height-padding, // // )) // // rimg := util.NewRoundedImage(right.(*image.Paletted), 10) // // sect := (img.SubImage(image.Rect( // // int(split)+(padding/2)+20, // // padding+20, // // int(split)+(padding/2)+30, // // padding+110, // // ))).(*image.Paletted) // // draw.Draw(limg, limg.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over) // // draw.Draw(rimg, rimg.Bounds(), image.NewUniform(color.White), image.Pt(0, 0), draw.Over) // // draw.Draw(sect, sect.Bounds(), util.NewGrayImage(), image.Pt(0, 0), draw.Over) // data := bytes.NewBuffer([]byte{}) // bmp.Encode(data, img) // buf := data.Bytes() // // Fix some header values so that trmnl is happy // buf[46] = 2 // buf[57] = 0 // buf[61] = 0 // c.Header("Content-Length", strconv.Itoa(len(buf))) // c.Data(200, "image/bmp", buf) }