package main import ( _ "embed" "image/color" "strconv" "time" "unsafe" "tinygo.org/x/tinydraw" "tinygo.org/x/tinyfont" "tinygo.org/x/tinyfont/freesans" "tinygo.org/x/tinyfont/gophers" qrcode "github.com/skip2/go-qrcode" ) const ( logoDisplayTime = 10 * time.Second ) var rainbow []color.RGBA var quit bool var selectedScreen uint8 //go:embed logo.bin var badgeLogo string func Badge() { quit = false selectedScreen = 0 display.FillScreen(colorBlack) rainbow = make([]color.RGBA, 256) for i := 0; i < 256; i++ { rainbow[i] = getRainbowRGB(uint8(i)) } for { switch selectedScreen { case 7: // last +1 selectedScreen = 0 fallthrough case 0: showLogoBin() if quit { break } case 1: if hardwareName == "GOPHERBADGE" { logopurpleHardware() } else { selectedScreen++ } if quit { break } case 2: myNameIsRainbow(YourName) if quit { break } case 3: blinkyRainbow(YourTitleA1, YourTitleA2) if quit { break } case 4: scroll(YourMarqueeTop, YourMarqueeMiddle, YourMarqueeBottom) if quit { break } case 5: QR(YourQRText) if quit { break } case 255: // max selectedScreen = 6 // last one fallthrough case 6: blinkyRainbow(YourTitleB1, YourTitleB2) if quit { break } default: selectedScreen = 0 } if quit { break } } } func myNameIs(name string) { display.FillScreen(colorWhite) // black corners detail display.FillRectangle(0, 0, cornerRadius, cornerRadius, colorBlack) display.FillRectangle(0, displayHeight-cornerRadius, cornerRadius, cornerRadius, colorBlack) display.FillRectangle(displayWidth-cornerRadius, 0, cornerRadius, cornerRadius, colorBlack) display.FillRectangle(displayWidth-cornerRadius, displayHeight-cornerRadius, cornerRadius, cornerRadius, colorBlack) // round corners tinydraw.FilledCircle(&display, cornerRadius, cornerRadius, cornerRadius, colorRed) tinydraw.FilledCircle(&display, displayWidth-cornerRadius-1, cornerRadius, cornerRadius, colorRed) tinydraw.FilledCircle(&display, cornerRadius, displayHeight-cornerRadius-1, cornerRadius, colorRed) tinydraw.FilledCircle(&display, displayWidth-cornerRadius-1, displayHeight-cornerRadius-1, cornerRadius, colorRed) // top band display.FillRectangle(cornerRadius, 0, displayWidth-2*cornerRadius-1, cornerRadius, colorRed) display.FillRectangle(0, cornerRadius, displayWidth, int16(topBandHeight), colorRed) // bottom band display.FillRectangle(cornerRadius, displayHeight-cornerRadius-1, displayWidth-2*cornerRadius-1, cornerRadius+1, colorRed) display.FillRectangle(0, displayHeight-int16(bottomBandHeight)-cornerRadius-1, displayWidth, int16(bottomBandHeight), colorRed) // top text if displayWidth >= 320 { // gopherbadge: HELLO + my name is w32, _ := tinyfont.LineWidth(&freesans.Bold18pt7b, "HELLO") tinyfont.WriteLine(&display, &freesans.Bold18pt7b, (displayWidth-int16(w32))/2, int16(helloY), "HELLO", colorWhite) w32, _ = tinyfont.LineWidth(&freesans.Oblique9pt7b, "my name is") tinyfont.WriteLine(&display, &freesans.Oblique9pt7b, (displayWidth-int16(w32))/2, int16(myNameIsY), "my name is", colorWhite) } else { // pybadge: my NAME is w32, _ := tinyfont.LineWidth(&freesans.Regular12pt7b, "my NAME is") tinyfont.WriteLine(&display, &freesans.Regular12pt7b, (displayWidth-int16(w32))/2, int16(myNameIsY), "my NAME is", colorWhite) } writeLine(name, colorBlack, displayWidth/2, 6*displayHeight/10, displayWidth, true) // gophers if displayWidth >= 320 { tinyfont.WriteLineColors(&display, &gophers.Regular58pt, displayWidth-int16(gophersX), int16(gophersY), "BE", []color.RGBA{getRainbowRGB(100), getRainbowRGB(200)}) } else { tinyfont.WriteLineColors(&display, &gophers.Regular32pt, displayWidth-int16(gophersX), int16(gophersY), "BE", []color.RGBA{getRainbowRGB(100), getRainbowRGB(200)}) } } func myNameIsRainbow(name string) { myNameIs(name) for i := 0; i < 230; i++ { writeLine(name, rainbow[i], displayWidth/2, 6*displayHeight/10, displayWidth, true) i += 2 getInput() if goBack() { quit = true return } } selectedScreen++ } func blinkyRainbow(topline, bottomline string) { display.FillScreen(colorWhite) // calculate the width of the text so we could center them later for i := int16(0); i < 20; i++ { writeLine(topline, getRainbowRGB(uint8(i*12)), displayWidth/2, 4*displayHeight/10, displayWidth, true) writeLine(bottomline, getRainbowRGB(uint8(i*12)), displayWidth/2, 8*displayHeight/10, displayWidth, true) getInput() if goBack() { quit = true return } } selectedScreen++ } func scroll(topline, middleline, bottomline string) { display.FillScreen(colorWhite) writeLine(topline, getRainbowRGB(200), displayWidth/2, 3*displayHeight/10, displayWidth, true) writeLine(middleline, getRainbowRGB(80), displayWidth/2, 6*displayHeight/10, displayWidth, true) writeLine(bottomline, getRainbowRGB(120), displayWidth/2, 9*displayHeight/10, displayWidth, true) display.SetScrollArea(0, 0) defer func() { display.SetScroll(0) display.StopScroll() }() for k := 0; k < 4; k++ { for i := int16(displayWidth - 1); i >= 0; i-- { getInput() if goBack() { quit = true return } display.SetScroll(i) time.Sleep(10 * time.Millisecond) } } selectedScreen++ } func logopurpleHardware() { bgColor := color.RGBA{109, 0, 140, 255} white := color.RGBA{255, 255, 255, 255} display.FillScreen(bgColor) if displayWidth >= 320 { // Full logo for gopherbadge display.FillRectangle(6, 166, 308, 21, white) tinydraw.FilledCircle(&display, 282, 130, 9, white) tinydraw.Line(&display, 259, 110, 298, 149, bgColor) tinydraw.Line(&display, 260, 110, 299, 149, bgColor) tinydraw.Line(&display, 261, 110, 300, 149, bgColor) tinydraw.Line(&display, 262, 110, 301, 149, bgColor) tinydraw.Line(&display, 263, 110, 302, 149, bgColor) tinydraw.Line(&display, 264, 110, 303, 149, bgColor) tinydraw.Line(&display, 265, 110, 304, 149, bgColor) display.FillRectangle(250, 98, 11, 63, white) display.FillRectangle(250, 98, 44, 11, white) display.FillRectangle(270, 150, 44, 11, white) display.FillRectangle(303, 98, 11, 63, white) tinyfont.WriteLine(&display, &freesans.Regular18pt7b, 6, 109, "purple", white) tinyfont.WriteLine(&display, &freesans.Regular18pt7b, 6, 153, "Hardware by", white) } else { // Simplified logo for pybadge tinyfont.WriteLine(&display, &freesans.Bold9pt7b, 10, 60, "purple", white) tinyfont.WriteLine(&display, &freesans.Bold9pt7b, 10, 80, "Hardware", white) } refreshIntervals := uint8(7) displayTime := logoDisplayTime / 3 for i := uint8(0); i < refreshIntervals; i++ { time.Sleep(displayTime / time.Duration(refreshIntervals)) getInput() if goBack() { quit = true return } } selectedScreen++ } func getRainbowRGB(i uint8) color.RGBA { if i < 85 { return color.RGBA{i * 3, 255 - i*3, 0, 255} } else if i < 170 { i -= 85 return color.RGBA{255 - i*3, 0, i * 3, 255} } i -= 170 return color.RGBA{0, i * 3, 255 - i*3, 255} } func showLogoBin() { selectedScreen++ row := make([]color.RGBA, displayWidth) unsafeBadgeLogo := unsafe.Slice(unsafe.StringData(badgeLogo), len(badgeLogo)) if len(badgeLogo) < displayHeight*displayWidth { return } for i := 0; i < displayHeight; i++ { for j := 0; j < displayWidth; j++ { values, err := strconv.ParseUint(string(unsafeBadgeLogo[6*(displayWidth*i+j):6*(displayWidth*i+j+1)]), 16, 32) if err != nil { println(err) } row[j] = color.RGBA{ R: uint8(values >> 16), G: uint8((values >> 8) & 0xFF), B: uint8(values & 0xFF), A: 255, } } display.FillRectangleWithBuffer(0, int16(i), displayWidth, 1, row) } refreshIntervals := uint8(20) for i := uint8(0); i < refreshIntervals; i++ { time.Sleep(logoDisplayTime / time.Duration(refreshIntervals)) getInput() if goBack() { quit = true return } } } func QR(msg string) { qr, err := qrcode.New(msg, qrcode.Medium) if err != nil { println(err, 123) } qrbytes := qr.Bitmap() size := int16(len(qrbytes)) factor := int16(displayHeight / len(qrbytes)) bx := (displayWidth - size*factor) / 2 by := (displayHeight - size*factor) / 2 display.FillScreen(color.RGBA{109, 0, 140, 255}) for y := int16(0); y < size; y++ { for x := int16(0); x < size; x++ { if qrbytes[y][x] { display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colorBlack) } else { display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colorWhite) } } } refreshIntervals := uint8(20) for i := uint8(0); i < refreshIntervals; i++ { time.Sleep(logoDisplayTime / time.Duration(refreshIntervals)) getInput() if goBack() { quit = true return } } selectedScreen++ } func getFontWidthSize(text string) (w32 uint32, size byte) { w32, _ = tinyfont.LineWidth(&freesans.Bold24pt7b, text) size = 24 if w32 < uint32(FontWidthThreshold) { size = 24 } else { w32, _ = tinyfont.LineWidth(&freesans.Bold18pt7b, text) if w32 < uint32(FontWidthThreshold) { size = 18 } else { w32, _ = tinyfont.LineWidth(&freesans.Bold12pt7b, text) if w32 < uint32(FontWidthThreshold) { size = 12 } else { w32, _ = tinyfont.LineWidth(&freesans.Bold9pt7b, text) size = 9 } } } return }