├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── accel3d.go ├── assets ├── getting_flashed.jpg ├── on_off.jpg └── welcome.jpg ├── badge.go ├── cmd ├── assets │ ├── fosdem-2023.jpg │ ├── fosdem.jpg │ ├── fosdemgo.jpg │ ├── golab.jpg │ ├── gopherconeu-2022.jpg │ ├── gopherconuk-2022.jpg │ ├── gopherconus-2022.jpg │ ├── gopherconus-2023.jpg │ ├── kubecon-eu-2023.jpg │ └── tinygo.jpg ├── logos │ ├── generate_logo_rgba.go │ └── logo-template.txt └── main.go ├── co2_monitor.go ├── data.go ├── gameoflife.go ├── go.mod ├── go.sum ├── leds.go ├── main.go ├── menu.go ├── music.go ├── snake.go └── tutorial ├── badgelife ├── display.go └── main.go ├── basics ├── README.md ├── assets │ ├── step0.jpg │ ├── step1.jpg │ ├── step2.gif │ ├── step2.jpg │ ├── step3b.gif │ ├── step5.jpg │ ├── step6.jpg │ └── step7.jpg ├── step0 │ └── main.go ├── step1 │ └── main.go ├── step2 │ └── main.go ├── step3 │ └── main.go ├── step3b │ └── main.go ├── step4 │ └── main.go ├── step5 │ └── main.go ├── step6 │ └── main.go ├── step7 │ └── main.go └── step8 │ └── main.go ├── flightbadge └── main.go ├── mynameis └── main.go ├── snake ├── README.md ├── assets │ ├── step0.jpg │ ├── step1.jpg │ ├── step2.gif │ ├── step3.gif │ ├── step4.gif │ ├── step5.jpg │ ├── step6.jpg │ ├── step7_01.gif │ └── step7_02.jpg ├── step0 │ └── main.go ├── step1 │ └── main.go ├── step2 │ └── main.go ├── step3 │ └── main.go ├── step4 │ └── main.go ├── step5 │ └── main.go ├── step6 │ └── main.go └── step7 │ └── main.go └── terminal └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | logo.go 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tinygo/tinygo-dev:latest 2 | 3 | WORKDIR /usr/src/app 4 | 5 | # pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change 6 | COPY go.mod go.sum ./ 7 | RUN go mod download && go mod verify 8 | 9 | COPY . . 10 | RUN go build -v -o /usr/local/bin/app cmd/main.go 11 | 12 | CMD ["app"] -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | flash: flash-tinygo 2 | 3 | prepare-gceu: 4 | go run cmd/main.go -conf=gceu22 5 | 6 | flash-gceu: prepare-gceu perform-flash 7 | 8 | prepare-gcuk: 9 | go run cmd/main.go -conf=gcuk22 10 | 11 | flash-gcuk: prepare-gcuk perform-flash 12 | 13 | prepare-gcus22: 14 | go run cmd/main.go -conf=gcus22 15 | 16 | flash-gcus22: prepare-gcus22 perform-flash 17 | 18 | prepare-gcus: 19 | go run cmd/main.go -conf=gcus23 20 | 21 | flash-gcus: prepare-gcus perform-flash 22 | 23 | prepare-tinygo: 24 | go run cmd/main.go -conf=tinygo 25 | 26 | flash-tinygo: prepare-tinygo perform-flash 27 | 28 | prepare-fosdem: 29 | go run cmd/main.go -conf=fosdem23 30 | 31 | flash-fosdem: prepare-fosdem perform-flash 32 | 33 | prepare-golab: 34 | go run cmd/main.go -conf=golab 35 | 36 | flash-golab: prepare-golab perform-flash 37 | 38 | perform-flash: 39 | tinygo flash -size short -target gobadge -ldflags="-X main.YourName='$(NAME)' -X main.YourTitleA1='$(TITLE1)' -X main.YourTitleA2='$(TITLE2)'" . 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoBadge 2 | 3 | TinyGo powered badge using the Adafruit Pybadge hardware aka "GoBadge". 4 | 5 | https://www.adafruit.com/product/4200 6 | 7 | # How to install 8 | 9 | - Install TinyGo using the instructions from https://tinygo.org 10 | 11 | - Clone this repo 12 | 13 | - Change directories into the directory with the repo 14 | 15 | - Connect your Gobadge to your computer using a USB cable 16 | 17 | - Make sure to turn on the badge, flip the switch at the top of the board next to `select` to the `on` position. The screen should light up and might be showing a sine wave display (if it was not already flashed to something else). 18 | ![location of on off switch](assets/on_off.jpg "on off switch location") 19 | 20 | ***Important Note*** 21 | 22 | The first time you flash your new GoBadge, you will probably need to double-click the "Reset" button located on the back of the badge in order to put the badge into bootloader mode. This will only need to be done once on brand new badges, after that you can flash it normally. 23 | 24 | - Run this command to compile and flash the code to your Gobadge: 25 | 26 | If you are running Mac or Linux, or have make installed you can run the following: 27 | 28 | ``` 29 | make flash 30 | ``` 31 | 32 | otherwise run tinygo directly 33 | 34 | ``` 35 | tinygo flash -target gobadge . 36 | ``` 37 | 38 | Note: if you get a `permision denied` error; please, consult this [page](https://tinygo.org/docs/guides/tinygo-flash-errors/) for possible solution. You many need to restart the computer; afterward to get the group to stick. 39 | 40 | - To display a conference logo on your badge, use one of the following targets (depending on GC for Europe, UK, or US): 41 | ``` 42 | make flash-gceu 43 | make flash-gcuk 44 | make flash-gcus 45 | ``` 46 | 47 | - To customize the Gobadge with your own name and information, use the `NAME`, `TITLE1`, and `TITLE2` variables like this: 48 | 49 | ``` 50 | make flash-gcus NAME="@TinyGolang" TITLE1="Go compiler" TITLE2="small places" 51 | ``` 52 | 53 | # Add a new logo 54 | 55 | - Create an image with a 160x128 pixels size, copy it into `cmd/assets` folder. 56 | For the moment only jpeg images are supported. 57 | - In `cmd/main.go` add the path to your file here 58 | 59 | ```go 60 | const ( 61 | gopherconEU22Logo = "./cmd/assets/gopherconeu-2022.jpg" 62 | gopherconUK22Logo = "./cmd/assets/gopherconuk-2022.jpg" 63 | gopherconUS22Logo = "./cmd/assets/gopherconus-2022.jpg" 64 | yourPathLogoHere = "./your/path/to/the/logo" 65 | ) 66 | ``` 67 | 68 | - Add the corresponding flag to the conf map: 69 | 70 | ```go 71 | func confs() map[string]string { 72 | return map[string]string{ 73 | "gceu22" : gopherconEU22Logo, 74 | "gcuk22" : gopherconUK22Logo, 75 | "gcus22" : gopherconUS22Logo, 76 | "flagLogo" : yourPathLogoHere, 77 | } 78 | } 79 | ``` 80 | 81 | Add a new target to the Makefile: 82 | 83 | ```bash 84 | flash-yourconf: 85 | go run cmd/main.go -conf=flagLogo 86 | tinygo flash -target gobadge . 87 | ``` 88 | 89 | You can run: 90 | 91 | ```bash 92 | make flash-yourconf 93 | ``` 94 | 95 | It will use `cmd/logos/logo-template.txt` to generate the image into a `[]color.RGBA`. 96 | Then it is stored in variable in `logo.go` file. 97 | 98 | ```go 99 | package main 100 | 101 | import "image/color" 102 | 103 | var logoRGBA = []color.RGBA{ {255, 255, 255} } 104 | ``` 105 | 106 | After the image has been generated, the make command will flash it to the board. 107 | 108 | 109 | 👏 Congratulations! It is now a GoBadge. 110 | -------------------------------------------------------------------------------- /accel3d.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/tinydraw" 9 | "tinygo.org/x/tinyfont" 10 | "tinygo.org/x/tinyfont/proggy" 11 | ) 12 | 13 | func Accel3D() { 14 | white := color.RGBA{255, 255, 255, 255} 15 | red := color.RGBA{255, 0, 0, 255} 16 | green := color.RGBA{0, 255, 0, 255} 17 | blue := color.RGBA{0, 0, 255, 255} 18 | black := color.RGBA{0, 0, 0, 255} 19 | 20 | display.FillScreen(white) 21 | tinydraw.Rectangle(&display, 26, 30, 132, 7, black) 22 | tinydraw.Rectangle(&display, 26, 40, 132, 7, black) 23 | tinydraw.Rectangle(&display, 26, 50, 132, 7, black) 24 | 25 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 10, 80, "Move the PyBadge to see", black) 26 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 14, 90, "the accelerometer in", black) 27 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 60, 100, "action.", black) 28 | 29 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 36, "X:", black) 30 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 46, "Y:", black) 31 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 56, "Z:", black) 32 | 33 | x, y, z := accel.ReadRawAcceleration() 34 | for { 35 | pressed, _ := buttons.Read8Input() 36 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 37 | break 38 | } 39 | 40 | x, y, z = accel.ReadRawAcceleration() 41 | x = x / 500 42 | y = y / 500 43 | z = z / 500 44 | if x > 64 { 45 | x = 64 46 | } 47 | if y > 64 { 48 | y = 64 49 | } 50 | if z > 64 { 51 | z = 64 52 | } 53 | if x < -64 { 54 | x = -64 55 | } 56 | if y < -64 { 57 | y = -64 58 | } 59 | if z < -64 { 60 | z = -64 61 | } 62 | display.FillRectangle(28, 32, 128, 2, white) 63 | display.FillRectangle(28, 42, 128, 2, white) 64 | display.FillRectangle(28, 52, 128, 2, white) 65 | if x < 0 { 66 | display.FillRectangle(92+x, 32, -x, 2, red) 67 | } else { 68 | display.FillRectangle(92, 32, x, 2, red) 69 | } 70 | if y < 0 { 71 | display.FillRectangle(92+y, 42, -y, 2, green) 72 | } else { 73 | display.FillRectangle(92, 42, y, 2, green) 74 | } 75 | if z < 0 { 76 | display.FillRectangle(92+z, 52, -z, 2, blue) 77 | } else { 78 | display.FillRectangle(92, 52, z, 2, blue) 79 | } 80 | 81 | println("X:", x, "Y:", y, "Z:", z) 82 | time.Sleep(time.Millisecond * 100) 83 | time.Sleep(50 * time.Millisecond) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /assets/getting_flashed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/assets/getting_flashed.jpg -------------------------------------------------------------------------------- /assets/on_off.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/assets/on_off.jpg -------------------------------------------------------------------------------- /assets/welcome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/assets/welcome.jpg -------------------------------------------------------------------------------- /badge.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/tinydraw" 9 | "tinygo.org/x/tinyfont" 10 | "tinygo.org/x/tinyfont/freesans" 11 | "tinygo.org/x/tinyfont/gophers" 12 | 13 | qrcode "github.com/skip2/go-qrcode" 14 | ) 15 | 16 | const ( 17 | WIDTH = 160 18 | HEIGHT = 128 19 | ) 20 | 21 | const ( 22 | logoDisplayTime = 10 * time.Second 23 | ) 24 | 25 | var rainbow []color.RGBA 26 | var pressed uint8 27 | var quit bool 28 | 29 | func Badge() { 30 | setCustomData() 31 | quit = false 32 | display.FillScreen(colors[BLACK]) 33 | 34 | rainbow = make([]color.RGBA, 256) 35 | for i := 0; i < 256; i++ { 36 | rainbow[i] = getRainbowRGB(uint8(i)) 37 | } 38 | 39 | for { 40 | logo() 41 | if quit { 42 | break 43 | } 44 | myNameIsRainbow(YourName) 45 | if quit { 46 | break 47 | } 48 | blinkyRainbow(YourTitleA1, YourTitleA2) 49 | if quit { 50 | break 51 | } 52 | scroll(YourMarqueeTop, YourMarqueeMiddle, YourMarqueeBottom) 53 | if quit { 54 | break 55 | } 56 | QR(YourQRText) 57 | if quit { 58 | break 59 | } 60 | blinkyRainbow(YourTitleB1, YourTitleB2) 61 | if quit { 62 | break 63 | } 64 | } 65 | } 66 | 67 | func myNameIs(name string) { 68 | display.FillScreen(colors[WHITE]) 69 | 70 | var r int16 = 8 71 | 72 | // black corners detail 73 | display.FillRectangle(0, 0, r, r, colors[BLACK]) 74 | display.FillRectangle(0, HEIGHT-r, r, r, colors[BLACK]) 75 | display.FillRectangle(WIDTH-r, 0, r, r, colors[BLACK]) 76 | display.FillRectangle(WIDTH-r, HEIGHT-r, r, r, colors[BLACK]) 77 | 78 | // round corners 79 | tinydraw.FilledCircle(&display, r, r, r, colors[RED]) 80 | tinydraw.FilledCircle(&display, WIDTH-r-1, r, r, colors[RED]) 81 | tinydraw.FilledCircle(&display, r, HEIGHT-r-1, r, colors[RED]) 82 | tinydraw.FilledCircle(&display, WIDTH-r-1, HEIGHT-r-1, r, colors[RED]) 83 | 84 | // top band 85 | display.FillRectangle(r, 0, WIDTH-2*r-1, r, colors[RED]) 86 | display.FillRectangle(0, r, WIDTH, 26, colors[RED]) 87 | 88 | // bottom band 89 | display.FillRectangle(r, HEIGHT-r-1, WIDTH-2*r-1, r+1, colors[RED]) 90 | display.FillRectangle(0, HEIGHT-2*r-1, WIDTH, r, colors[RED]) 91 | 92 | // top text : my NAME is 93 | w32, _ := tinyfont.LineWidth(&freesans.Regular12pt7b, "my NAME is") 94 | tinyfont.WriteLine(&display, &freesans.Regular12pt7b, (WIDTH-int16(w32))/2, 24, "my NAME is", colors[WHITE]) 95 | 96 | // middle text 97 | w32, _ = tinyfont.LineWidth(&freesans.Bold9pt7b, name) 98 | tinyfont.WriteLine(&display, &freesans.Bold9pt7b, (WIDTH-int16(w32))/2, 72, name, colors[BLACK]) 99 | 100 | // gophers 101 | tinyfont.WriteLineColors(&display, &gophers.Regular32pt, WIDTH-48, 110, "BE", []color.RGBA{getRainbowRGB(100), getRainbowRGB(200)}) 102 | } 103 | 104 | func myNameIsRainbow(name string) { 105 | myNameIs(name) 106 | 107 | w32, _ := tinyfont.LineWidth(&freesans.Bold9pt7b, name) 108 | for i := 0; i < 230; i++ { 109 | tinyfont.WriteLineColors(&display, &freesans.Bold9pt7b, (WIDTH-int16(w32))/2, 72, name, rainbow[i:]) 110 | pressed, _ = buttons.Read8Input() 111 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 112 | quit = true 113 | break 114 | } 115 | } 116 | } 117 | 118 | func blinky(topline, bottomline string) { 119 | display.FillScreen(colors[WHITE]) 120 | 121 | // calculate the width of the text so we could center them later 122 | w32top, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, topline) 123 | w32bottom, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, bottomline) 124 | for i := int16(0); i < 10; i++ { 125 | // show black text 126 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32top))/2, 50, topline, colors[BLACK]) 127 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32bottom))/2, 100, bottomline, colors[BLACK]) 128 | 129 | // repeat the other way around 130 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32top))/2, 50, topline, colors[WHITE]) 131 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32bottom))/2, 100, bottomline, colors[WHITE]) 132 | 133 | pressed, _ = buttons.Read8Input() 134 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 135 | quit = true 136 | break 137 | } 138 | } 139 | } 140 | 141 | func blinkyRainbow(topline, bottomline string) { 142 | display.FillScreen(colors[WHITE]) 143 | 144 | // calculate the width of the text so we could center them later 145 | w32top, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, topline) 146 | w32bottom, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, bottomline) 147 | for i := int16(0); i < 20; i++ { 148 | // show black text 149 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32top))/2, 50, topline, getRainbowRGB(uint8(i*12))) 150 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32bottom))/2, 100, bottomline, getRainbowRGB(uint8(i*12))) 151 | 152 | pressed, _ = buttons.Read8Input() 153 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 154 | quit = true 155 | break 156 | } 157 | } 158 | } 159 | 160 | func scroll(topline, middleline, bottomline string) { 161 | display.FillScreen(colors[WHITE]) 162 | 163 | // calculate the width of the text, so we could center them later 164 | w32top, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, topline) 165 | w32middle, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, middleline) 166 | w32bottom, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, bottomline) 167 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32top))/2, 34, topline, getRainbowRGB(200)) 168 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32middle))/2, 60, middleline, getRainbowRGB(80)) 169 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, (WIDTH-int16(w32bottom))/2, 100, bottomline, getRainbowRGB(120)) 170 | 171 | display.SetScrollArea(0, 0) 172 | for k := 0; k < 4; k++ { 173 | for i := int16(159); i >= 0; i-- { 174 | 175 | pressed, _ = buttons.Read8Input() 176 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 177 | quit = true 178 | break 179 | } 180 | display.SetScroll(i) 181 | time.Sleep(10 * time.Millisecond) 182 | } 183 | } 184 | display.SetScroll(0) 185 | display.StopScroll() 186 | } 187 | 188 | func logo() { 189 | display.FillRectangleWithBuffer(0, 0, WIDTH, HEIGHT, logoRGBA) 190 | time.Sleep(logoDisplayTime) 191 | } 192 | 193 | func QR(msg string) { 194 | qr, err := qrcode.New(msg, qrcode.Medium) 195 | if err != nil { 196 | println(err, 123) 197 | } 198 | 199 | qrbytes := qr.Bitmap() 200 | size := int16(len(qrbytes)) 201 | 202 | factor := int16(HEIGHT / len(qrbytes)) 203 | 204 | bx := (WIDTH - size*factor) / 2 205 | by := (HEIGHT - size*factor) / 2 206 | display.FillScreen(color.RGBA{109, 0, 140, 255}) 207 | for y := int16(0); y < size; y++ { 208 | for x := int16(0); x < size; x++ { 209 | if qrbytes[y][x] { 210 | display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colors[0]) 211 | } else { 212 | display.FillRectangle(bx+x*factor, by+y*factor, factor, factor, colors[1]) 213 | } 214 | } 215 | } 216 | 217 | time.Sleep(logoDisplayTime) 218 | pressed, _ = buttons.Read8Input() 219 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 220 | quit = true 221 | } 222 | } 223 | 224 | func setCustomData() { 225 | if YourName == "" { 226 | YourName = DefaultName 227 | } 228 | 229 | if YourTitleA1 == "" { 230 | YourTitleA1 = DefaultTitleA1 231 | } 232 | 233 | if YourTitleA2 == "" { 234 | YourTitleA2 = DefaultTitleA2 235 | } 236 | 237 | if YourTitleB1 == "" { 238 | YourTitleB1 = DefaultTitleB1 239 | } 240 | 241 | if YourTitleB2 == "" { 242 | YourTitleB2 = DefaultTitleB2 243 | } 244 | 245 | if YourMarqueeTop == "" { 246 | YourMarqueeTop = DefaultMarqueeTop 247 | } 248 | 249 | if YourMarqueeMiddle == "" { 250 | YourMarqueeMiddle = DefaultMarqueeMiddle 251 | } 252 | 253 | if YourMarqueeBottom == "" { 254 | YourMarqueeBottom = DefaultMarqueeBottom 255 | } 256 | 257 | if YourQRText == "" { 258 | YourQRText = DefaultQRText 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /cmd/assets/fosdem-2023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/fosdem-2023.jpg -------------------------------------------------------------------------------- /cmd/assets/fosdem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/fosdem.jpg -------------------------------------------------------------------------------- /cmd/assets/fosdemgo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/fosdemgo.jpg -------------------------------------------------------------------------------- /cmd/assets/golab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/golab.jpg -------------------------------------------------------------------------------- /cmd/assets/gopherconeu-2022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/gopherconeu-2022.jpg -------------------------------------------------------------------------------- /cmd/assets/gopherconuk-2022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/gopherconuk-2022.jpg -------------------------------------------------------------------------------- /cmd/assets/gopherconus-2022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/gopherconus-2022.jpg -------------------------------------------------------------------------------- /cmd/assets/gopherconus-2023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/gopherconus-2023.jpg -------------------------------------------------------------------------------- /cmd/assets/kubecon-eu-2023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/kubecon-eu-2023.jpg -------------------------------------------------------------------------------- /cmd/assets/tinygo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/cmd/assets/tinygo.jpg -------------------------------------------------------------------------------- /cmd/logos/generate_logo_rgba.go: -------------------------------------------------------------------------------- 1 | package logos 2 | 3 | import ( 4 | "fmt" 5 | "image/color" 6 | "image/jpeg" 7 | "log" 8 | "os" 9 | "strings" 10 | "text/template" 11 | ) 12 | 13 | func GenerateLogoRGBAFile(filepath string) { 14 | colors := generateLogoRGBA(filepath) 15 | colorsStr := convertToString(colors) 16 | generateFile(colorsStr) 17 | } 18 | 19 | func generateLogoRGBA(filepath string) []color.RGBA { 20 | file, _ := os.Open(filepath) 21 | img, err := jpeg.Decode(file) 22 | if err != nil { 23 | log.Fatal("failed to decode image file", err) 24 | } 25 | 26 | colors := make([]color.RGBA, 0) 27 | 28 | for y := 0; y < img.Bounds().Max.Y; y++ { 29 | for x := 0; x < img.Bounds().Max.X; x++ { 30 | r, g, b, _ := img.At(x, y).RGBA() 31 | colors = append(colors, color.RGBA{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: uint8(255)}) 32 | } 33 | } 34 | 35 | return colors 36 | } 37 | 38 | func convertToString(colors []color.RGBA) string { 39 | var content strings.Builder 40 | var err error 41 | 42 | for i, c := range colors { 43 | str := fmt.Sprintf("{%d, %d, %d, %d}", c.R, c.G, c.B, c.A) 44 | _, err = content.WriteString(str) 45 | if err != nil { 46 | log.Fatal("failed to write string") 47 | } 48 | 49 | if i < len(colors)-1 { 50 | _, err = content.WriteString(", ") 51 | if err != nil { 52 | log.Fatal("failed to write string") 53 | } 54 | } 55 | } 56 | 57 | return content.String() 58 | } 59 | 60 | func generateFile(colorsStr string) { 61 | tmp, err := template.ParseFiles("./cmd/logos/logo-template.txt") 62 | if err != nil { 63 | log.Fatal("failed to parse template", err) 64 | } 65 | 66 | f, err := os.Create("logo.go") 67 | if err != nil { 68 | log.Fatal("failed to create output file", err) 69 | } 70 | 71 | type Colors struct { 72 | LogoRGBA string 73 | } 74 | 75 | err = tmp.Execute(f, Colors{LogoRGBA: colorsStr}) 76 | if err != nil { 77 | log.Fatal("failed to execute template", err) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cmd/logos/logo-template.txt: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "image/color" 4 | 5 | var logoRGBA = []color.RGBA{ {{.LogoRGBA}} } 6 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | 7 | "github.com/tinygo-org/gobadge/cmd/logos" 8 | ) 9 | 10 | const ( 11 | gopherconEU22Logo = "./cmd/assets/gopherconeu-2022.jpg" 12 | gopherconUK22Logo = "./cmd/assets/gopherconuk-2022.jpg" 13 | gopherconUS22Logo = "./cmd/assets/gopherconus-2022.jpg" 14 | gopherconUS23Logo = "./cmd/assets/gopherconus-2023.jpg" 15 | fosdem23Logo = "./cmd/assets/fosdem-2023.jpg" 16 | kubeconEU23 = "./cmd/assets/kubecon-eu-2023.jpg" 17 | tinygoLogo = "./cmd/assets/tinygo.jpg" 18 | golab = "./cmd/assets/golab.jpg" 19 | fosdem = "./cmd/assets/fosdem.jpg" 20 | fosdemgo = "./cmd/assets/fosdemgo.jpg" 21 | ) 22 | 23 | func main() { 24 | conf := flag.String("conf", tinygoLogo, "Choose the conference logo you want to (e.g.: tinygo, gceu22, gcuk22, gcus22, golab)") 25 | flag.Parse() 26 | 27 | c := confs() 28 | logo, ok := c[*conf] 29 | if !ok { 30 | fmt.Println("I do not have yet this conf in my catalog.") 31 | return 32 | } 33 | 34 | logos.GenerateLogoRGBAFile(logo) 35 | } 36 | 37 | func confs() map[string]string { 38 | return map[string]string{ 39 | "gceu22": gopherconEU22Logo, 40 | "gcuk22": gopherconUK22Logo, 41 | "gcus22": gopherconUS22Logo, 42 | "gcus23": gopherconUS23Logo, 43 | "fosdem23": fosdem23Logo, 44 | "tinygo": tinygoLogo, 45 | "kubeconeu23": kubeconEU23, 46 | "golab": golab, 47 | "fosdem": fosdem, 48 | "fosdemgo": fosdemgo, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /co2_monitor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "strconv" 7 | "time" 8 | 9 | "tinygo.org/x/tinyfont" 10 | "tinygo.org/x/tinyfont/freesans" 11 | "tinygo.org/x/tinyfont/proggy" 12 | 13 | "tinygo.org/x/drivers/scd4x" 14 | ) 15 | 16 | var ledColors = make([]color.RGBA, 5) 17 | 18 | func CO2Monitor() { 19 | display.EnableBacklight(true) 20 | display.FillScreen(colors[WHITE]) 21 | 22 | sensor := scd4x.New(machine.I2C0) 23 | sensor.Configure() 24 | 25 | if err := sensor.StartPeriodicMeasurement(); err != nil { 26 | println(err) 27 | } 28 | 29 | w32, _ := tinyfont.LineWidth(&freesans.Bold12pt7b, "TinyGo CO") 30 | xPPM := ((WIDTH - int16(w32)) / 2) - 3 31 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, xPPM, 30, "TinyGo CO", colors[BLACK]) 32 | //w32, _ = tinyfont.LineWidth(&freesans.Bold12pt7b, "TinyGo CO") 33 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, xPPM+int16(w32)+1, 33, "2", colors[RED]) 34 | // move it one pixel to make it looks like BOLD font 35 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, xPPM+int16(w32)+2, 33, "2", colors[RED]) 36 | 37 | w32, _ = tinyfont.LineWidth(&proggy.TinySZ8pt7b, "PPM") 38 | xPPM = WIDTH - int16(w32) - 4 39 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, xPPM, 64, "PPM", colors[BLACK]) 40 | 41 | w32, _ = tinyfont.LineWidth(&proggy.TinySZ8pt7b, "TEMP.") 42 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, ((WIDTH/2)-int16(w32))/2, 94, "TEMP", colors[BLACK]) 43 | 44 | w32, _ = tinyfont.LineWidth(&proggy.TinySZ8pt7b, "RH") 45 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, (WIDTH/2)+((WIDTH/2)-int16(w32))/2, 94, "RH", colors[BLACK]) 46 | 47 | w32, _ = tinyfont.LineWidth(&proggy.TinySZ8pt7b, "ºC") 48 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, (WIDTH/2)-int16(w32)-4, 112, "ºC", colors[BLACK]) 49 | 50 | w32, _ = tinyfont.LineWidth(&proggy.TinySZ8pt7b, "%") 51 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, WIDTH-int16(w32)-4, 110, "%", colors[BLACK]) 52 | 53 | oldCO2 := "" 54 | oldTemp := "" 55 | oldHumidity := "" 56 | var xCO2 int16 57 | var xTemp int16 58 | var xHumidity int16 59 | 60 | for { 61 | co2, err := sensor.ReadCO2() 62 | if err != nil { 63 | println(err) 64 | } 65 | 66 | ShowCO2Level(co2) 67 | 68 | // Clear old readings 69 | tinyfont.WriteLine(&display, &freesans.Bold24pt7b, xCO2, 77, oldCO2, colors[WHITE]) 70 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, xTemp, 120, oldTemp, colors[WHITE]) 71 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, xHumidity, 120, oldHumidity, colors[WHITE]) 72 | 73 | // Display new readings 74 | oldCO2 = strconv.Itoa(int(co2)) 75 | w32, _ = tinyfont.LineWidth(&freesans.Bold24pt7b, oldCO2) 76 | xCO2 = xPPM - int16(w32) - 10 77 | tinyfont.WriteLine(&display, &freesans.Bold24pt7b, xCO2, 77, oldCO2, colors[BLACK]) 78 | 79 | value, _ := sensor.ReadTemperature() 80 | println("TEMP", value) 81 | oldTemp = strconv.FormatFloat(float64(value)/1000, 'f', 1, 64) 82 | w32, _ = tinyfont.LineWidth(&freesans.Bold12pt7b, oldTemp) 83 | xTemp = ((WIDTH/2)-int16(w32))/2 - 6 84 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, xTemp, 120, oldTemp, colors[BLACK]) 85 | 86 | value, _ = sensor.ReadHumidity() 87 | println("HUMD", value) 88 | oldHumidity = strconv.FormatFloat(float64(value), 'f', 1, 64) 89 | w32, _ = tinyfont.LineWidth(&freesans.Bold12pt7b, oldHumidity) 90 | xHumidity = (WIDTH / 2) + ((WIDTH/2)-int16(w32))/2 - 6 91 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, xHumidity, 120, oldHumidity, colors[BLACK]) 92 | 93 | pressed, _ := buttons.Read8Input() 94 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 95 | break 96 | } 97 | 98 | time.Sleep(time.Second) 99 | } 100 | 101 | Clear() 102 | Clear() 103 | 104 | time.Sleep(50 * time.Millisecond) 105 | 106 | display.EnableBacklight(true) 107 | } 108 | 109 | // ShowCO2Level shows the current CO2 level on the LEDs. 110 | func ShowCO2Level(co2 int32) { 111 | if co2 < 0 { 112 | co2 = 0 113 | } 114 | if co2 > 2000 { 115 | co2 = 2000 116 | } 117 | // color 118 | var c color.RGBA 119 | switch { 120 | case co2 < 800: 121 | c = color.RGBA{R: 0x00, G: 0xff, B: 0x00} 122 | case co2 < 1500: 123 | c = color.RGBA{R: 0xff, G: 0xff, B: 0x00} 124 | default: 125 | c = color.RGBA{R: 0xff, G: 0x00, B: 0x00} 126 | } 127 | 128 | // how many to light up 129 | howmany := int(co2/400) + 1 130 | 131 | // clear old colors 132 | for i := 0; i < len(ledColors); i++ { 133 | if i < howmany { 134 | ledColors[i] = c 135 | } else { 136 | ledColors[i] = color.RGBA{0, 0, 0, 0} 137 | } 138 | } 139 | 140 | leds.WriteColors(ledColors) 141 | } 142 | 143 | func Clear() { 144 | for i := 0; i < len(ledColors); i++ { 145 | ledColors[i] = color.RGBA{0, 0, 0, 0} 146 | } 147 | leds.WriteColors(ledColors) 148 | 149 | time.Sleep(50 * time.Millisecond) 150 | } 151 | -------------------------------------------------------------------------------- /data.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Replace with your data by using -ldflags like this: 4 | // 5 | // tinygo flash -target gobadge -ldflags="-X main.YourName=@myontwitter -X main.YourTitle1='Amazing human' -X main.YourTitle2='also kind'" 6 | // 7 | // See Makefile for more info. 8 | var ( 9 | YourName, YourTitleA1, YourTitleA2, YourTitleB1, YourTitleB2 string 10 | YourMarqueeTop, YourMarqueeMiddle, YourMarqueeBottom, YourQRText string 11 | ) 12 | 13 | const ( 14 | DefaultName = "@TinyGolang" 15 | DefaultTitleA1 = "Go Compiler" 16 | DefaultTitleA2 = "Small Places" 17 | DefaultMarqueeTop = "This badge" 18 | DefaultMarqueeMiddle = "runs" 19 | DefaultMarqueeBottom = "TINYGO" 20 | DefaultQRText = "https://tinygo.org" 21 | DefaultTitleB1 = "I like" 22 | DefaultTitleB2 = "TINYGO" 23 | ) 24 | -------------------------------------------------------------------------------- /gameoflife.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/acifani/vita/lib/game" 5 | "image/color" 6 | "time" 7 | "tinygo.org/x/drivers/shifter" 8 | ) 9 | 10 | var ( 11 | gamebuffer []byte 12 | 13 | universe *game.Universe 14 | 15 | width uint32 = 26 16 | height uint32 = 21 17 | population = 20 18 | cellSize int16 = 6 19 | 20 | wh = colors[WHITE] 21 | 22 | cellBuf = []color.RGBA{ 23 | wh, wh, wh, wh, wh, wh, 24 | wh, wh, bk, bk, wh, wh, 25 | wh, bk, bk, bk, bk, wh, 26 | wh, bk, bk, bk, bk, wh, 27 | wh, wh, bk, bk, wh, wh, 28 | wh, wh, wh, wh, wh, wh, 29 | } 30 | ) 31 | 32 | func GameOfLife() { 33 | white := color.RGBA{255, 255, 255, 255} 34 | display.FillScreen(white) 35 | 36 | gamebuffer = make([]byte, height*width) 37 | universe = game.NewUniverse(height, width) 38 | universe.Randomize(population) 39 | universe.Read(gamebuffer) 40 | 41 | for { 42 | drawGrid() 43 | display.Display() 44 | universe.Read(gamebuffer) 45 | 46 | universe.Tick() 47 | 48 | buttons.ReadInput() 49 | println("LOOP") 50 | if buttons.Pins[shifter.BUTTON_B].Get() { 51 | println("RESET") 52 | universe.Reset() 53 | universe.Randomize(population) 54 | } 55 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 56 | break 57 | } 58 | 59 | time.Sleep(50 * time.Millisecond) 60 | } 61 | } 62 | 63 | func drawGrid() { 64 | var rows, cols uint32 65 | 66 | for rows = 0; rows < height; rows++ { 67 | for cols = 0; cols < width; cols++ { 68 | idx := universe.GetIndex(rows, cols) 69 | 70 | switch { 71 | case universe.Cell(idx) == gamebuffer[idx]: 72 | // no change, so skip 73 | continue 74 | case universe.Cell(idx) == game.Alive: 75 | display.FillRectangleWithBuffer(2+cellSize*int16(cols), 1+cellSize*int16(rows), cellSize, cellSize, cellBuf) 76 | default: // game.Dead 77 | display.FillRectangle(2+cellSize*int16(cols), 1+cellSize*int16(rows), cellSize, cellSize, colors[WHITE]) 78 | } 79 | 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tinygo-org/gobadge 2 | 3 | go 1.21 4 | 5 | toolchain go1.21.1 6 | 7 | require ( 8 | github.com/acifani/vita v1.2.0 9 | github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e 10 | tinygo.org/x/drivers v0.23.0 11 | tinygo.org/x/tinydraw v0.3.0 12 | tinygo.org/x/tinyfont v0.3.0 13 | tinygo.org/x/tinyterm v0.2.1-0.20221003142551-ae75982d313f 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/acifani/vita v1.2.0 h1:9pS0W9FbGxfvmNiitFHYuDm1kBxuOSQozBKZFqXsmxQ= 2 | github.com/acifani/vita v1.2.0/go.mod h1:r5ldyqj9b7t2/sDrUcLOQbQ9g/I28JQ7nSUjvRtruyw= 3 | github.com/bgould/http v0.0.0-20190627042742-d268792bdee7/go.mod h1:BTqvVegvwifopl4KTEDth6Zezs9eR+lCWhvGKvkxJHE= 4 | github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= 5 | github.com/frankban/quicktest v1.10.2 h1:19ARM85nVi4xH7xPXuc5eM/udya5ieh7b/Sv+d844Tk= 6 | github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s= 7 | github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= 8 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 9 | github.com/hajimehoshi/go-jisx0208 v1.0.0/go.mod h1:yYxEStHL7lt9uL+AbdWgW9gBumwieDoZCiB1f/0X0as= 10 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 11 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 12 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 13 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 14 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 15 | github.com/sago35/go-bdf v0.0.0-20200313142241-6c17821c91c4/go.mod h1:rOebXGuMLsXhZAC6mF/TjxONsm45498ZyzVhel++6KM= 16 | github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= 17 | github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= 18 | github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= 19 | golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 20 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 21 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 22 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 23 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 24 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 25 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 26 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 27 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 28 | tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= 29 | tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= 30 | tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI= 31 | tinygo.org/x/drivers v0.19.0/go.mod h1:uJD/l1qWzxzLx+vcxaW0eY464N5RAgFi1zTVzASFdqI= 32 | tinygo.org/x/drivers v0.23.0 h1:fUy4OmLOWWYCOzDp/83Qewej1Q+YgUpwkm11e7gxUc0= 33 | tinygo.org/x/drivers v0.23.0/go.mod h1:J4+51Li1kcfL5F93kmnDWEEzQF3bLGz0Am3Q7E2a8/E= 34 | tinygo.org/x/tinydraw v0.3.0 h1:OjsdMcES5+7IIs/4diFpq/pWFsa0VKtbi1mURuj2q64= 35 | tinygo.org/x/tinydraw v0.3.0/go.mod h1:Yz0vLSP2rHsIKpLYkEmLnE+2zyhhITu2LxiVtLRiW6I= 36 | tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM= 37 | tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM= 38 | tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk= 39 | tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20= 40 | tinygo.org/x/tinyfs v0.2.0/go.mod h1:6ZHYdvB3sFYeMB3ypmXZCNEnFwceKc61ADYTYHpep1E= 41 | tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4= 42 | tinygo.org/x/tinyterm v0.2.1-0.20221003142551-ae75982d313f h1:QZKIR/NSAWOwR3Uv5hYzwgtSsReOWZNCqK2NlmPylgA= 43 | tinygo.org/x/tinyterm v0.2.1-0.20221003142551-ae75982d313f/go.mod h1:ii6r/nCtNVRQgac21uQj9tlY3PnJuUAcZWMLgdVwMFo= 44 | -------------------------------------------------------------------------------- /leds.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | ) 8 | 9 | func Leds() { 10 | display.EnableBacklight(false) 11 | display.FillScreen(color.RGBA{0,0,0,255}) 12 | ledColors := make([]color.RGBA, 5) 13 | var i uint8 14 | for { 15 | ledColors[0] = getRainbowRGB(i) 16 | ledColors[1] = getRainbowRGB(i+10) 17 | ledColors[2] = getRainbowRGB(i+20) 18 | ledColors[3] = getRainbowRGB(i+30) 19 | ledColors[4] = getRainbowRGB(i+40) 20 | leds.WriteColors(ledColors) 21 | 22 | pressed, _ := buttons.Read8Input() 23 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 24 | break 25 | } 26 | i+=2 27 | 28 | time.Sleep(50*time.Millisecond) 29 | } 30 | 31 | ledColors[0] = color.RGBA{0,0,0,255} 32 | ledColors[1] = color.RGBA{0,0,0,255} 33 | ledColors[2] = color.RGBA{0,0,0,255} 34 | ledColors[3] = color.RGBA{0,0,0,255} 35 | ledColors[4] = color.RGBA{0,0,0,255} 36 | leds.WriteColors(ledColors) 37 | time.Sleep(50*time.Millisecond) 38 | ledColors[0] = color.RGBA{0,0,0,255} 39 | ledColors[1] = color.RGBA{0,0,0,255} 40 | ledColors[2] = color.RGBA{0,0,0,255} 41 | ledColors[3] = color.RGBA{0,0,0,255} 42 | ledColors[4] = color.RGBA{0,0,0,255} 43 | leds.WriteColors(ledColors) 44 | time.Sleep(50*time.Millisecond) 45 | 46 | display.EnableBacklight(true) 47 | } 48 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/lis3dh" 9 | 10 | "tinygo.org/x/drivers/ws2812" 11 | 12 | "tinygo.org/x/drivers/shifter" 13 | "tinygo.org/x/drivers/st7735" 14 | ) 15 | 16 | var display st7735.Device 17 | var buttons shifter.Device 18 | var leds ws2812.Device 19 | var bzrPin machine.Pin 20 | var accel lis3dh.Device 21 | 22 | const ( 23 | BLACK = iota 24 | WHITE 25 | RED 26 | SNAKE 27 | TEXT 28 | ) 29 | 30 | var colors = []color.RGBA{ 31 | color.RGBA{0, 0, 0, 255}, 32 | color.RGBA{255, 255, 255, 255}, 33 | color.RGBA{250, 0, 0, 255}, 34 | color.RGBA{0, 200, 0, 255}, 35 | color.RGBA{160, 160, 160, 255}, 36 | } 37 | 38 | var snakeGame = NewSnakeGame() 39 | 40 | func main() { 41 | machine.SPI1.Configure(machine.SPIConfig{ 42 | SCK: machine.SPI1_SCK_PIN, 43 | SDO: machine.SPI1_SDO_PIN, 44 | SDI: machine.SPI1_SDI_PIN, 45 | Frequency: 8000000, 46 | }) 47 | machine.I2C0.Configure(machine.I2CConfig{SCL: machine.SCL_PIN, SDA: machine.SDA_PIN}) 48 | 49 | accel = lis3dh.New(machine.I2C0) 50 | accel.Address = lis3dh.Address0 51 | accel.Configure() 52 | 53 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 54 | display.Configure(st7735.Config{ 55 | Rotation: st7735.ROTATION_90, 56 | }) 57 | 58 | buttons = shifter.NewButtons() 59 | buttons.Configure() 60 | 61 | neo := machine.NEOPIXELS 62 | neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) 63 | leds = ws2812.New(neo) 64 | 65 | bzrPin = machine.A0 66 | bzrPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) 67 | 68 | speaker := machine.SPEAKER_ENABLE 69 | speaker.Configure(machine.PinConfig{Mode: machine.PinOutput}) 70 | speaker.High() 71 | 72 | for { 73 | switch menu() { 74 | case 0: 75 | Badge() 76 | break 77 | case 1: 78 | snakeGame.Loop() 79 | break 80 | case 2: 81 | Leds() 82 | break 83 | case 3: 84 | Accel3D() 85 | break 86 | case 4: 87 | GameOfLife() 88 | break 89 | case 5: 90 | Music() 91 | break 92 | default: 93 | break 94 | } 95 | println("LOOP") 96 | time.Sleep(1 * time.Second) 97 | } 98 | } 99 | 100 | func getRainbowRGB(i uint8) color.RGBA { 101 | if i < 85 { 102 | return color.RGBA{i * 3, 255 - i*3, 0, 255} 103 | } else if i < 170 { 104 | i -= 85 105 | return color.RGBA{255 - i*3, 0, i * 3, 255} 106 | } 107 | i -= 170 108 | return color.RGBA{0, i * 3, 255 - i*3, 255} 109 | } 110 | -------------------------------------------------------------------------------- /menu.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "time" 6 | 7 | "tinygo.org/x/drivers/shifter" 8 | 9 | "tinygo.org/x/tinydraw" 10 | "tinygo.org/x/tinyfont" 11 | "tinygo.org/x/tinyfont/proggy" 12 | ) 13 | 14 | func menu() int16 { 15 | display.FillScreen(color.RGBA{0, 0, 0, 255}) 16 | options := []string{ 17 | "Badge", 18 | "Snake", 19 | "Rainbow LEDs", 20 | "Accelerometer", 21 | "Game of Life", 22 | "Music!", 23 | } 24 | 25 | bgColor := color.RGBA{0, 40, 70, 255} 26 | display.FillScreen(bgColor) 27 | tinydraw.FilledTriangle(&display, 0, 128, 0, 45, 45, 0, color.RGBA{255, 255, 255, 255}) 28 | tinydraw.FilledTriangle(&display, 45, 0, 0, 128, 145, 0, color.RGBA{255, 255, 255, 255}) 29 | tinydraw.FilledTriangle(&display, 0, 128, 15, 128, 145, 0, color.RGBA{255, 255, 255, 255}) 30 | for i := int16(0); i < 8; i++ { 31 | tinydraw.Line(&display, 0, 110+i, 110+i, 0, bgColor) 32 | } 33 | 34 | selected := int16(0) 35 | numOpts := int16(len(options)) 36 | for i := int16(0); i < numOpts; i++ { 37 | tinydraw.Circle(&display, 32, 37+10*i, 4, color.RGBA{0, 0, 0, 255}) 38 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 39, 39+10*i, options[i], color.RGBA{0, 0, 0, 255}) 39 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 39, 40+10*i, options[i], color.RGBA{0, 0, 0, 255}) 40 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 39, 41+10*i, options[i], color.RGBA{0, 0, 0, 255}) 41 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 40, 41+10*i, options[i], color.RGBA{0, 0, 0, 255}) 42 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 41, 41+10*i, options[i], color.RGBA{0, 0, 0, 255}) 43 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 41, 40+10*i, options[i], color.RGBA{0, 0, 0, 255}) 44 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 41, 39+10*i, options[i], color.RGBA{0, 0, 0, 255}) 45 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 40, 39+10*i, options[i], color.RGBA{0, 0, 0, 255}) 46 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 40, 40+10*i, options[i], color.RGBA{250, 250, 0, 255}) 47 | } 48 | 49 | tinydraw.FilledCircle(&display, 32, 37, 2, color.RGBA{200, 200, 0, 255}) 50 | 51 | released := true 52 | for { 53 | pressed, _ := buttons.ReadInput() 54 | 55 | if released && buttons.Pins[shifter.BUTTON_UP].Get() && selected > 0 { 56 | selected-- 57 | tinydraw.FilledCircle(&display, 32, 37+10*selected, 2, color.RGBA{200, 200, 0, 255}) 58 | tinydraw.FilledCircle(&display, 32, 37+10*(selected+1), 2, color.RGBA{255, 255, 255, 255}) 59 | } 60 | if released && buttons.Pins[shifter.BUTTON_DOWN].Get() && selected < (numOpts-1) { 61 | selected++ 62 | tinydraw.FilledCircle(&display, 32, 37+10*selected, 2, color.RGBA{200, 200, 0, 255}) 63 | tinydraw.FilledCircle(&display, 32, 37+10*(selected-1), 2, color.RGBA{255, 255, 255, 255}) 64 | } 65 | if released && buttons.Pins[shifter.BUTTON_START].Get() { 66 | break 67 | } 68 | if pressed == 0 { 69 | released = true 70 | } else { 71 | released = false 72 | } 73 | time.Sleep(200 * time.Millisecond) 74 | } 75 | return selected 76 | } 77 | -------------------------------------------------------------------------------- /music.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/tinyfont" 9 | "tinygo.org/x/tinyfont/freesans" 10 | ) 11 | 12 | func Music() { 13 | white := color.RGBA{255, 255, 255, 255} 14 | display.FillScreen(white) 15 | 16 | tinyfont.WriteLine(&display, &freesans.Bold24pt7b, 0, 50, "MUSIC", color.RGBA{0, 100, 250, 255}) 17 | tinyfont.WriteLine(&display, &freesans.Bold9pt7b, 20, 100, "Press any key", color.RGBA{200, 0, 0, 255}) 18 | 19 | for { 20 | pressed, _ := buttons.Read8Input() 21 | if pressed&machine.BUTTON_SELECT_MASK > 0 { 22 | break 23 | } 24 | 25 | if pressed&machine.BUTTON_START_MASK > 0 { 26 | tone(5274) 27 | } 28 | if pressed&machine.BUTTON_A_MASK > 0 { 29 | tone(1046) 30 | } 31 | if pressed&machine.BUTTON_B_MASK > 0 { 32 | tone(1975) 33 | } 34 | 35 | if pressed&machine.BUTTON_LEFT_MASK > 0 { 36 | tone(329) 37 | } 38 | if pressed&machine.BUTTON_RIGHT_MASK > 0 { 39 | tone(739) 40 | } 41 | if pressed&machine.BUTTON_UP_MASK > 0 { 42 | tone(369) 43 | } 44 | if pressed&machine.BUTTON_DOWN_MASK > 0 { 45 | tone(523) 46 | } 47 | } 48 | } 49 | 50 | func tone(tone int) { 51 | for i := 0; i < 10; i++ { 52 | bzrPin.High() 53 | time.Sleep(time.Duration(tone) * time.Microsecond) 54 | 55 | bzrPin.Low() 56 | time.Sleep(time.Duration(tone) * time.Microsecond) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /snake.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "math/rand" 6 | "strconv" 7 | "strings" 8 | "time" 9 | 10 | "tinygo.org/x/tinyfont/proggy" 11 | 12 | "tinygo.org/x/drivers/shifter" 13 | "tinygo.org/x/tinyfont" 14 | "tinygo.org/x/tinyfont/freesans" 15 | ) 16 | 17 | const ( 18 | GameSplash = iota 19 | GameStart 20 | GamePlay 21 | GameOver 22 | GameQuit 23 | ) 24 | 25 | const ( 26 | SnakeUp = iota 27 | SnakeDown 28 | SnakeLeft 29 | SnakeRight 30 | ) 31 | 32 | const ( 33 | WIDTHBLOCKS = 16 34 | HEIGHTBLOCKS = 13 35 | ) 36 | 37 | var ( 38 | // Those variable are there for a more easy reading of the apple shape. 39 | re = colors[RED] // red 40 | bk = colors[BLACK] // background 41 | gr = colors[SNAKE] // green 42 | 43 | // The array is split for a visual purpose too. 44 | appleBuf = []color.RGBA{ 45 | bk, bk, bk, bk, bk, gr, gr, gr, bk, bk, 46 | bk, bk, bk, bk, gr, gr, gr, bk, bk, bk, 47 | bk, bk, bk, re, gr, gr, re, bk, bk, bk, 48 | bk, bk, re, re, re, re, re, re, bk, bk, 49 | bk, re, re, re, re, re, re, re, re, bk, 50 | bk, re, re, re, re, re, re, re, re, bk, 51 | bk, re, re, re, re, re, re, re, re, bk, 52 | bk, bk, re, re, re, re, re, re, bk, bk, 53 | bk, bk, bk, re, re, re, re, bk, bk, bk, 54 | bk, bk, bk, bk, bk, bk, bk, bk, bk, bk, 55 | } 56 | ) 57 | 58 | type Snake struct { 59 | body [208][2]int16 60 | length int16 61 | direction int16 62 | } 63 | 64 | type SnakeGame struct { 65 | snake Snake 66 | appleX, appleY int16 67 | status uint8 68 | score int 69 | frame, delay int 70 | } 71 | 72 | var splashed = false 73 | var scoreStr string 74 | 75 | func NewSnakeGame() *SnakeGame { 76 | return &SnakeGame{ 77 | snake: Snake{ 78 | body: [208][2]int16{ 79 | {0, 3}, 80 | {0, 2}, 81 | {0, 1}, 82 | }, 83 | length: 3, 84 | direction: SnakeLeft, 85 | }, 86 | appleX: 5, 87 | appleY: 5, 88 | status: GameSplash, 89 | delay: 120, 90 | } 91 | } 92 | 93 | func (g *SnakeGame) Splash() { 94 | if !splashed { 95 | g.splash() 96 | splashed = true 97 | time.Sleep(1500 * time.Millisecond) 98 | } 99 | } 100 | 101 | func (g *SnakeGame) Start() { 102 | display.FillScreen(bk) 103 | 104 | g.initSnake() 105 | g.drawSnake() 106 | g.createApple() 107 | 108 | g.status = GamePlay 109 | } 110 | 111 | func (g *SnakeGame) Play(direction int) { 112 | if direction != -1 && ((g.snake.direction == SnakeUp && direction != SnakeDown) || 113 | (g.snake.direction == SnakeDown && direction != SnakeUp) || 114 | (g.snake.direction == SnakeLeft && direction != SnakeRight) || 115 | (g.snake.direction == SnakeRight && direction != SnakeLeft)) { 116 | g.snake.direction = int16(direction) 117 | } 118 | 119 | g.moveSnake() 120 | } 121 | 122 | func (g *SnakeGame) Over() { 123 | display.FillScreen(bk) 124 | splashed = false 125 | 126 | g.status = GameOver 127 | } 128 | 129 | func (g *SnakeGame) splash() { 130 | display.FillScreen(bk) 131 | 132 | logo := ` 133 | ____ _ __ ___ __ __ ____ 134 | / __/ / |/ / / _ | / //_/ / __/ 135 | _\ \ / / / __ | / ,< / _/ 136 | /___/ /_/|_/ /_/ |_|/_/|_| /___/ 137 | 138 | _____ ___ __ ___ ____ 139 | / ___/ / _ | / |/ / / __/ 140 | / (_ / / __ | / /|_/ / / _/ 141 | \___/ /_/ |_|/_/ /_/ /___/ 142 | ` 143 | for i, line := range strings.Split(strings.TrimSuffix(logo, "\n"), "\n") { 144 | tinyfont.WriteLine(&display, &tinyfont.Tiny3x3a2pt7b, 12, int16(10+i*5), line+"\n", gr) 145 | } 146 | 147 | tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 30, 120, "Press START", colors[RED]) 148 | 149 | if g.score > 0 { 150 | scoreStr = strconv.Itoa(g.score) 151 | tinyfont.WriteLineRotated(&display, &proggy.TinySZ8pt7b, 140, 100, "SCORE: "+scoreStr, colors[TEXT], tinyfont.ROTATION_270) 152 | } 153 | } 154 | 155 | func (g *SnakeGame) initSnake() { 156 | g.snake.body[0][0] = 0 157 | g.snake.body[0][1] = 3 158 | g.snake.body[1][0] = 0 159 | g.snake.body[1][1] = 2 160 | g.snake.body[2][0] = 0 161 | g.snake.body[2][1] = 1 162 | 163 | g.snake.length = 3 164 | g.snake.direction = SnakeRight 165 | } 166 | 167 | func (g *SnakeGame) collisionWithSnake(x, y int16) bool { 168 | for i := int16(0); i < g.snake.length; i++ { 169 | if x == g.snake.body[i][0] && y == g.snake.body[i][1] { 170 | return true 171 | } 172 | } 173 | return false 174 | } 175 | 176 | func (g *SnakeGame) createApple() { 177 | g.appleX = int16(rand.Int31n(WIDTHBLOCKS)) 178 | g.appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 179 | for g.collisionWithSnake(g.appleX, g.appleY) { 180 | g.appleX = int16(rand.Int31n(WIDTHBLOCKS)) 181 | g.appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 182 | } 183 | g.drawApple(g.appleX, g.appleY) 184 | } 185 | 186 | func (g *SnakeGame) moveSnake() { 187 | x := g.snake.body[0][0] 188 | y := g.snake.body[0][1] 189 | 190 | switch g.snake.direction { 191 | case SnakeLeft: 192 | x-- 193 | break 194 | case SnakeUp: 195 | y-- 196 | break 197 | case SnakeDown: 198 | y++ 199 | break 200 | case SnakeRight: 201 | x++ 202 | break 203 | } 204 | if x >= WIDTHBLOCKS { 205 | x = 0 206 | } 207 | if x < 0 { 208 | x = WIDTHBLOCKS - 1 209 | } 210 | if y >= HEIGHTBLOCKS { 211 | y = 0 212 | } 213 | if y < 0 { 214 | y = HEIGHTBLOCKS - 1 215 | } 216 | 217 | if g.collisionWithSnake(x, y) { 218 | g.score = int(g.snake.length - 3) 219 | g.Over() 220 | 221 | return 222 | } 223 | 224 | // draw head 225 | g.drawSnakePartial(x, y, colors[SNAKE]) 226 | if x == g.appleX && y == g.appleY { 227 | g.snake.length++ 228 | g.createApple() 229 | } else { 230 | // remove tail 231 | g.drawSnakePartial(g.snake.body[g.snake.length-1][0], g.snake.body[g.snake.length-1][1], colors[BLACK]) 232 | } 233 | for i := g.snake.length - 1; i > 0; i-- { 234 | g.snake.body[i][0] = g.snake.body[i-1][0] 235 | g.snake.body[i][1] = g.snake.body[i-1][1] 236 | } 237 | g.snake.body[0][0] = x 238 | g.snake.body[0][1] = y 239 | } 240 | 241 | func (g *SnakeGame) drawApple(x, y int16) { 242 | display.FillRectangleWithBuffer(10*x, 10*y, 10, 10, appleBuf) 243 | } 244 | 245 | func (g *SnakeGame) drawSnake() { 246 | for i := int16(0); i < g.snake.length; i++ { 247 | g.drawSnakePartial(g.snake.body[i][0], g.snake.body[i][1], colors[SNAKE]) 248 | } 249 | } 250 | 251 | func (g *SnakeGame) drawSnakePartial(x, y int16, c color.RGBA) { 252 | modY := int16(9) 253 | if y == 12 { 254 | modY = 8 255 | } 256 | display.FillRectangle(10*x, 10*y, 9, modY, c) 257 | } 258 | 259 | func (g *SnakeGame) Loop() { 260 | g.status = GameSplash 261 | splashed = false 262 | for { 263 | g.update() 264 | if g.status == GameQuit { 265 | break 266 | } 267 | time.Sleep(100 * time.Millisecond) 268 | } 269 | } 270 | 271 | func (g *SnakeGame) update() { 272 | buttons.ReadInput() 273 | switch g.status { 274 | case GameSplash: 275 | g.Splash() 276 | if buttons.Pins[shifter.BUTTON_START].Get() { 277 | g.Start() 278 | } 279 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 280 | g.status = GameOver 281 | } 282 | break 283 | 284 | case GamePlay: 285 | switch { 286 | case buttons.Pins[shifter.BUTTON_SELECT].Get(): 287 | g.Over() 288 | break 289 | 290 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 291 | g.Play(SnakeRight) 292 | break 293 | 294 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 295 | g.Play(SnakeLeft) 296 | break 297 | 298 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 299 | g.Play(SnakeDown) 300 | break 301 | 302 | case buttons.Pins[shifter.BUTTON_UP].Get(): 303 | g.Play(SnakeUp) 304 | break 305 | 306 | default: 307 | g.Play(-1) 308 | break 309 | } 310 | break 311 | case GameQuit: 312 | case GameOver: 313 | g.Splash() 314 | 315 | if buttons.Pins[shifter.BUTTON_START].Get() { 316 | g.Start() 317 | } 318 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 319 | g.status = GameQuit 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /tutorial/badgelife/display.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | 6 | "image/color" 7 | "time" 8 | 9 | "tinygo.org/x/drivers/st7735" 10 | "tinygo.org/x/tinydraw" 11 | 12 | "github.com/acifani/vita/lib/game" 13 | ) 14 | 15 | var ( 16 | display st7735.Device 17 | 18 | gamebuffer []byte 19 | 20 | startx int16 = 24 21 | starty int16 = 8 22 | radius int16 = 2 23 | space int16 = 2 24 | 25 | black = color.RGBA{0, 0, 0, 255} 26 | white = color.RGBA{255, 255, 255, 255} 27 | ) 28 | 29 | func startGame() { 30 | machine.SPI1.Configure(machine.SPIConfig{ 31 | SCK: machine.SPI1_SCK_PIN, 32 | SDO: machine.SPI1_SDO_PIN, 33 | SDI: machine.SPI1_SDI_PIN, 34 | Frequency: 8000000, 35 | }) 36 | 37 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 38 | display.Configure(st7735.Config{ 39 | Rotation: st7735.ROTATION_90, 40 | }) 41 | 42 | display.FillScreen(black) 43 | 44 | gamebuffer = make([]byte, height*width) 45 | universe.Read(gamebuffer) 46 | 47 | for { 48 | drawGrid() 49 | display.Display() 50 | universe.Read(gamebuffer) 51 | 52 | universe.Tick() 53 | 54 | time.Sleep(10 * time.Millisecond) 55 | } 56 | } 57 | 58 | func drawGrid() { 59 | var rows, cols uint32 60 | c := black 61 | 62 | for rows = 0; rows < height; rows++ { 63 | for cols = 0; cols < width; cols++ { 64 | idx := universe.GetIndex(rows, cols) 65 | 66 | switch { 67 | case universe.Cell(idx) == gamebuffer[idx]: 68 | // no change, so skip 69 | continue 70 | case universe.Cell(idx) == game.Alive: 71 | c = white 72 | default: // game.Dead 73 | c = black 74 | } 75 | 76 | x := startx + int16(cols)*radius*2 - radius + int16(cols)*space 77 | y := starty + int16(rows)*radius*2 - radius + int16(rows)*space 78 | tinydraw.FilledCircle(&display, x, y, radius, c) 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tutorial/badgelife/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "tinygo.org/x/drivers/shifter" 7 | 8 | "github.com/acifani/vita/lib/game" 9 | ) 10 | 11 | var ( 12 | universe *game.Universe 13 | 14 | height uint32 = 20 15 | width uint32 = 20 16 | population = 20 17 | ) 18 | 19 | func main() { 20 | universe = game.NewUniverse(height, width) 21 | universe.Randomize(population) 22 | 23 | go startGame() 24 | 25 | buttons := shifter.NewButtons() 26 | buttons.Configure() 27 | 28 | for { 29 | buttons.ReadInput() 30 | 31 | if buttons.Pins[shifter.BUTTON_A].Get() { 32 | universe.Randomize(population) 33 | } 34 | 35 | if buttons.Pins[shifter.BUTTON_B].Get() { 36 | universe.Reset() 37 | } 38 | 39 | time.Sleep(time.Millisecond * 200) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tutorial/basics/README.md: -------------------------------------------------------------------------------- 1 | # GoBadge Tutorial 2 | 3 | ## What you need 4 | 5 | - GoBadge aka Adafruit PyBadge 6 | - Personal computer with Go 1.18/1.19 and TinyGo installed, and a serial port. 7 | 8 | ## Installation 9 | 10 | ### Go 11 | 12 | If somehow you have not installed Go on your computer already, you can download it here: 13 | 14 | https://go.dev/dl/ 15 | 16 | Now you are ready to install TinyGo. 17 | 18 | ### TinyGo 19 | 20 | Follow the instructions here for your operating system: 21 | 22 | https://tinygo.org/getting-started/ 23 | 24 | ## Connecting the GoBadge to your computer 25 | 26 | ![welcome to gopher badge](../../assets/welcome.jpg) 27 | 28 | Plug the GoBadge into your computer using a USB cable. There may be one provided in your starter kit. 29 | 30 | Make sure that the GoBadge is on. 31 | 32 | ![on off switch](../../assets/on_off.jpg) 33 | 34 | ## Running the code 35 | 36 | The TinyGo programs will run directly on the GoBadge's microcontroller. The procedure is basically: 37 | 38 | - Edit your TinyGo program. 39 | - Compile and flash it to your GoBadge. 40 | - The program executes from the GoBadge. You can disconnect the GoBadge from your computer (plug it into a battery, if it isn't already), the program executes directly on the microcontroller. 41 | 42 | Let's get started! 43 | 44 | ## Code 45 | 46 | ### step0.go - Built-in LED 47 | 48 | This tests that you can compile and flash your PyBadge with TinyGo code, by blinking the built-in LED (it's on the back). 49 | 50 | 51 | 52 | ``` 53 | tinygo flash -target gobadge ./step0 54 | ``` 55 | 56 | ![flashing the board](../../assets/getting_flashed.jpg) 57 | 58 | Once the PyBadge is flashed correctly, the built-in LED labeled "D13" (on the back) should start to turn on and off once per second. Now everything is setup correctly and you are ready to continue. 59 | 60 | ![step 0](./assets/step0.jpg) 61 | 62 | 63 | ### step1.go - Built-in LED, START Button 64 | 65 | Run the code. 66 | 67 | ``` 68 | tinygo flash -target gobadge ./step1 69 | ``` 70 | 71 | When you press the START button, the built-in LED should turn on. 72 | 73 | ![start button](./assets/step1.jpg) 74 | 75 | *Challenge:* 76 | See if you can modify [./step1/main.go](step1/main.go) so that the LED turns on if 77 | the _SELECT_ button is pressed instead of the _START_ button. 78 | 79 | ### step2.go - Neopixels 80 | 81 | Run the code. 82 | 83 | ``` 84 | tinygo flash -target gobadge ./step2 85 | ``` 86 | 87 | ![step 2 location](./assets/step2.jpg) 88 | 89 | 90 | The 5 neopixels should light up green and red alternatively. 91 | 92 | ![step 2](./assets/step2.gif) 93 | 94 | 95 | 96 | ### step3.go - Neopixels, Buttons 97 | 98 | Run the code. 99 | 100 | ``` 101 | tinygo flash -target gobadge ./step3 102 | ``` 103 | 104 | The 5 neopixels should light up in different colors depending on which button you press. 105 | 106 | What happens if you press more than one button at a time? 107 | 108 | try out `./step3b`, what does it do? 109 | 110 | After deploying it should look like this: 111 | 112 | ![step3b](./assets/step3b.gif) 113 | 114 | ### step4.go - Light sensor, Neopixels 115 | 116 | Run the code. 117 | 118 | ``` 119 | tinygo flash -target gobadge ./step4 120 | ``` 121 | 122 | 123 | ### step5.go - Display 124 | 125 | Run the code. 126 | 127 | ``` 128 | tinygo flash -target gobadge ./step5/main.go 129 | ``` 130 | 131 | The message "Hello Gophers!" should appear on the display. 132 | 133 | ![step5](./assets/step5.jpg) 134 | 135 | 136 | 137 | ### step6.go - Display, Buttons 138 | 139 | Run the code. 140 | 141 | ``` 142 | tinygo flash -target gobadge ./step6/main.go 143 | ``` 144 | 145 | ![step6](./assets/step6.jpg) 146 | 147 | 148 | The display will show some blue circle that represent that buttons on the board. 149 | When a button is pressed a ring will be shown around its corresponding circle. 150 | 151 | ### step7.go - Display, Accelerometer 152 | 153 | 154 | Run the code. 155 | 156 | ``` 157 | tinygo flash -target gobadge ./step7 158 | ``` 159 | 160 | ![step7](./assets/step7.jpg) 161 | 162 | The display will show a bar for each X,Y,Z axis. Move the Pybadge to see it in action. 163 | 164 | ### step8.go - Buzzer, Buttons 165 | 166 | Run the code. 167 | 168 | ``` 169 | tinygo flash -target gobadge ./step8/main.go 170 | ``` 171 | 172 | Press the buttons and create your melody. 173 | 174 | 175 | Good job in completing the basic tutorials. Now can check out the more complicated 176 | tutorials 177 | 178 | ### Snake Game 179 | 180 | [Play the famous Snake game on the pybadge.](../snake/README.md) 181 | 182 | ### My Name Is 183 | 184 | This example display you name. Use this to make a simple name badge 185 | [My Name is](../mynameis/README.md) 186 | 187 | Configure your name and use the awesome TinyGo-powered badge! 188 | 189 | Note: 190 | 191 | Find the different type of fonts you can use [here](https://github.com/tinygo-org/tinyfont) -------------------------------------------------------------------------------- /tutorial/basics/assets/step0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step0.jpg -------------------------------------------------------------------------------- /tutorial/basics/assets/step1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step1.jpg -------------------------------------------------------------------------------- /tutorial/basics/assets/step2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step2.gif -------------------------------------------------------------------------------- /tutorial/basics/assets/step2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step2.jpg -------------------------------------------------------------------------------- /tutorial/basics/assets/step3b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step3b.gif -------------------------------------------------------------------------------- /tutorial/basics/assets/step5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step5.jpg -------------------------------------------------------------------------------- /tutorial/basics/assets/step6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step6.jpg -------------------------------------------------------------------------------- /tutorial/basics/assets/step7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/basics/assets/step7.jpg -------------------------------------------------------------------------------- /tutorial/basics/step0/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | 10 | // get the pin that represents that LED on the back of the device D13 11 | led := machine.LED 12 | 13 | // configuring the LED pin mode for output 14 | led.Configure(machine.PinConfig{Mode: machine.PinOutput}) 15 | 16 | for { 17 | // turn off the LED 18 | led.Low() 19 | 20 | // wait 500 ms 21 | time.Sleep(time.Millisecond * 500) 22 | 23 | // turn on the LED 24 | led.High() 25 | 26 | // wait 500 ms 27 | time.Sleep(time.Millisecond * 500) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tutorial/basics/step1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | 7 | "tinygo.org/x/drivers/shifter" 8 | ) 9 | 10 | func main() { 11 | 12 | // get the pin that represents that LED on the back of the device D13 13 | led := machine.LED 14 | 15 | // configuring the LED pin mode for output 16 | led.Configure(machine.PinConfig{Mode: machine.PinOutput}) 17 | 18 | // get the buttons on the device, and configure them 19 | buttons := shifter.NewButtons() 20 | buttons.Configure() 21 | 22 | for { 23 | // read the latest input from the badge for all the buttons 24 | buttons.ReadInput() 25 | // was the start button pressed? 26 | // if so, turn on the LED, otherwise turn it off 27 | // to get other button states see: 28 | // https://github.com/tinygo-org/drivers/blob/v0.23.0/shifter/pybadge.go#L8-L17 29 | if buttons.Pins[shifter.BUTTON_START].Get() { 30 | led.High() 31 | } else { 32 | led.Low() 33 | } 34 | 35 | time.Sleep(time.Millisecond * 10) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tutorial/basics/step2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/ws2812" 9 | ) 10 | 11 | const ( 12 | NumberOfLEDs = 5 13 | ) 14 | 15 | var ( 16 | red = color.RGBA{255, 0, 0, 255} 17 | green = color.RGBA{0, 255, 0, 255} 18 | ) 19 | 20 | func main() { 21 | // get the LED strip pin for the NEOPixels 22 | neo := machine.NEOPIXELS 23 | // configure the pins for output 24 | neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) 25 | 26 | // configure LED strip driver 27 | leds := ws2812.New(neo) 28 | ledColors := make([]color.RGBA, NumberOfLEDs) 29 | 30 | // rg represents if the LED is going to be red or green 31 | rg := false 32 | for { 33 | for i := 0; i < NumberOfLEDs; i++ { 34 | if rg { 35 | ledColors[i] = red 36 | } else { 37 | ledColors[i] = green 38 | } 39 | // swap color for the next LED 40 | rg = !rg 41 | } 42 | // set the color of the LEDs 43 | leds.WriteColors(ledColors) 44 | // sleep for 300 ms 45 | time.Sleep(time.Millisecond * 300) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tutorial/basics/step3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | "tinygo.org/x/drivers/ws2812" 10 | ) 11 | 12 | const ( 13 | Red = iota 14 | MellonGreen 15 | Green 16 | Cyan 17 | Blue 18 | Purple 19 | White 20 | Off 21 | ) 22 | 23 | var colors = [...]color.RGBA{ 24 | color.RGBA{255, 0, 0, 255}, // RED 25 | color.RGBA{255, 255, 0, 255}, // MELLON_GREEN 26 | color.RGBA{0, 255, 0, 255}, // GREEN 27 | color.RGBA{0, 255, 255, 255}, // CYAN 28 | color.RGBA{0, 0, 255, 255}, // BLUE 29 | color.RGBA{255, 0, 255, 255}, // PURPLE 30 | color.RGBA{255, 255, 255, 255}, // WHITE 31 | color.RGBA{0, 0, 0, 255}, // OFF 32 | } 33 | 34 | func main() { 35 | 36 | // get and configure neopixels 37 | neo := machine.NEOPIXELS 38 | neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) 39 | 40 | leds := ws2812.New(neo) 41 | // a color for each led on the board 42 | ledColors := make([]color.RGBA, 5) 43 | 44 | // get and configure buttons on the board 45 | buttons := shifter.NewButtons() 46 | buttons.Configure() 47 | 48 | c := 0 49 | for { 50 | // read buttons states 51 | buttons.ReadInput() 52 | switch { 53 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 54 | c = Red 55 | case buttons.Pins[shifter.BUTTON_UP].Get(): 56 | c = MellonGreen 57 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 58 | c = Green 59 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 60 | c = Cyan 61 | case buttons.Pins[shifter.BUTTON_SELECT].Get(): 62 | c = White 63 | case buttons.Pins[shifter.BUTTON_START].Get(): 64 | c = Off 65 | case buttons.Pins[shifter.BUTTON_A].Get(): 66 | c = Blue 67 | case buttons.Pins[shifter.BUTTON_B].Get(): 68 | c = Purple 69 | } 70 | 71 | // set color for LEDs 72 | for i := range ledColors { 73 | ledColors[i] = colors[c] 74 | } 75 | 76 | leds.WriteColors(ledColors) 77 | 78 | time.Sleep(30 * time.Millisecond) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tutorial/basics/step3b/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | 10 | "tinygo.org/x/drivers/ws2812" 11 | ) 12 | 13 | func main() { 14 | 15 | // get and configure neopixels 16 | neo := machine.NEOPIXELS 17 | neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) 18 | 19 | leds := ws2812.New(neo) 20 | // a color for each led on the board 21 | ledColors := make([]color.RGBA, 5) 22 | 23 | // get and configure buttons on the board 24 | buttons := shifter.NewButtons() 25 | buttons.Configure() 26 | 27 | var k uint8 28 | for { 29 | buttons.ReadInput() 30 | if buttons.Pins[shifter.BUTTON_LEFT].Get() { 31 | k++ 32 | } 33 | if buttons.Pins[shifter.BUTTON_RIGHT].Get() { 34 | k-- 35 | } 36 | 37 | ledColors[0] = getRainbowRGB(k) 38 | ledColors[1] = getRainbowRGB(k + 10) 39 | ledColors[2] = getRainbowRGB(k + 20) 40 | ledColors[3] = getRainbowRGB(k + 30) 41 | ledColors[4] = getRainbowRGB(k + 40) 42 | leds.WriteColors(ledColors) 43 | 44 | time.Sleep(10 * time.Millisecond) 45 | } 46 | } 47 | 48 | func getRainbowRGB(i uint8) color.RGBA { 49 | if i < 85 { 50 | return color.RGBA{i * 3, 255 - i*3, 0, 255} 51 | } else if i < 170 { 52 | i -= 85 53 | return color.RGBA{255 - i*3, 0, i * 3, 255} 54 | } 55 | i -= 170 56 | return color.RGBA{0, i * 3, 255 - i*3, 255} 57 | } 58 | -------------------------------------------------------------------------------- /tutorial/basics/step4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | 6 | "image/color" 7 | "time" 8 | 9 | "tinygo.org/x/drivers/ws2812" 10 | ) 11 | 12 | var ( 13 | Red = color.RGBA{255, 0, 0, 255} 14 | Green = color.RGBA{0, 255, 0, 255} 15 | ) 16 | 17 | func main() { 18 | 19 | // get and configure neopixels 20 | neo := machine.NEOPIXELS 21 | neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) 22 | 23 | leds := ws2812.New(neo) 24 | ledColors := make([]color.RGBA, 5) 25 | 26 | // Initialize the Analog to digital subsystem 27 | machine.InitADC() 28 | light := machine.ADC{machine.LIGHTSENSOR} 29 | light.Configure(machine.ADCConfig{}) 30 | 31 | for { 32 | 33 | // clamp the light value from the sensor 34 | value := uint8(light.Get() / 256) 35 | c := Green 36 | if value < 25 { 37 | c = Red 38 | } 39 | for i := 0; i < 5; i++ { 40 | ledColors[i] = c 41 | } 42 | leds.WriteColors(ledColors) 43 | 44 | time.Sleep(100 * time.Millisecond) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tutorial/basics/step5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | 7 | "tinygo.org/x/drivers/st7735" 8 | "tinygo.org/x/tinyfont" 9 | "tinygo.org/x/tinyfont/freesans" 10 | ) 11 | 12 | func main() { 13 | // Setup the screen pins 14 | machine.SPI1.Configure(machine.SPIConfig{ 15 | SCK: machine.SPI1_SCK_PIN, 16 | SDO: machine.SPI1_SDO_PIN, 17 | SDI: machine.SPI1_SDI_PIN, 18 | Frequency: 8000000, 19 | }) 20 | // Setup the display 21 | display := st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 22 | display.Configure(st7735.Config{ 23 | Rotation: st7735.ROTATION_90, 24 | }) 25 | 26 | // Clear the screen to black 27 | display.FillScreen(color.RGBA{0, 0, 0, 255}) 28 | 29 | // Write "Hello" 10 pixels from the right and 50 pixels from the top, in mellon green 30 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, 10, 50, "Hello", color.RGBA{R: 255, G: 255, B: 0, A: 255}) 31 | tinyfont.WriteLine(&display, &freesans.Bold12pt7b, 40, 80, "Gophers!", color.RGBA{R: 255, G: 0, B: 255, A: 255}) 32 | } 33 | -------------------------------------------------------------------------------- /tutorial/basics/step6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | "tinygo.org/x/drivers/st7735" 10 | "tinygo.org/x/tinydraw" 11 | ) 12 | 13 | func main() { 14 | 15 | // Setup the SPI display pins 16 | machine.SPI1.Configure(machine.SPIConfig{ 17 | SCK: machine.SPI1_SCK_PIN, 18 | SDO: machine.SPI1_SDO_PIN, 19 | SDI: machine.SPI1_SDI_PIN, 20 | Frequency: 8000000, 21 | }) 22 | 23 | // Setup the display drivers 24 | display := st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 25 | display.Configure(st7735.Config{ 26 | Rotation: st7735.ROTATION_90, 27 | }) 28 | 29 | buttons := shifter.NewButtons() 30 | buttons.Configure() 31 | 32 | display.FillScreen(color.RGBA{255, 255, 255, 255}) 33 | 34 | circle := color.RGBA{0, 100, 250, 255} 35 | white := color.RGBA{255, 255, 255, 255} 36 | ring := color.RGBA{200, 0, 0, 255} 37 | 38 | // Clear the display to white 39 | display.FillScreen(white) 40 | 41 | // Draw blue circles to represent each of the buttons 42 | tinydraw.FilledCircle(&display, 25, 74, 8, circle) // LEFT 43 | tinydraw.FilledCircle(&display, 55, 74, 8, circle) // RIGHT 44 | tinydraw.FilledCircle(&display, 40, 59, 8, circle) // UP 45 | tinydraw.FilledCircle(&display, 40, 89, 8, circle) // DOWN 46 | 47 | tinydraw.FilledCircle(&display, 45, 30, 8, circle) // SELECT 48 | tinydraw.FilledCircle(&display, 120, 30, 8, circle) // START 49 | 50 | tinydraw.FilledCircle(&display, 120, 80, 8, circle) // B 51 | tinydraw.FilledCircle(&display, 135, 65, 8, circle) // A 52 | 53 | for { 54 | buttons.ReadInput() 55 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 56 | tinydraw.Circle(&display, 45, 30, 10, ring) 57 | } else { 58 | tinydraw.Circle(&display, 45, 30, 10, white) 59 | } 60 | if buttons.Pins[shifter.BUTTON_START].Get() { 61 | tinydraw.Circle(&display, 120, 30, 10, ring) 62 | } else { 63 | tinydraw.Circle(&display, 120, 30, 10, white) 64 | } 65 | if buttons.Pins[shifter.BUTTON_A].Get() { 66 | tinydraw.Circle(&display, 135, 65, 10, ring) 67 | } else { 68 | tinydraw.Circle(&display, 135, 65, 10, white) 69 | } 70 | if buttons.Pins[shifter.BUTTON_B].Get() { 71 | tinydraw.Circle(&display, 120, 80, 10, ring) 72 | } else { 73 | tinydraw.Circle(&display, 120, 80, 10, white) 74 | } 75 | if buttons.Pins[shifter.BUTTON_LEFT].Get() { 76 | tinydraw.Circle(&display, 25, 74, 10, ring) 77 | } else { 78 | tinydraw.Circle(&display, 25, 74, 10, white) 79 | } 80 | if buttons.Pins[shifter.BUTTON_RIGHT].Get() { 81 | tinydraw.Circle(&display, 55, 74, 10, ring) 82 | } else { 83 | tinydraw.Circle(&display, 55, 74, 10, white) 84 | } 85 | if buttons.Pins[shifter.BUTTON_UP].Get() { 86 | tinydraw.Circle(&display, 40, 59, 10, ring) 87 | } else { 88 | tinydraw.Circle(&display, 40, 59, 10, white) 89 | } 90 | if buttons.Pins[shifter.BUTTON_DOWN].Get() { 91 | tinydraw.Circle(&display, 40, 89, 10, ring) 92 | } else { 93 | tinydraw.Circle(&display, 40, 89, 10, white) 94 | } 95 | time.Sleep(50 * time.Millisecond) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tutorial/basics/step7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/lis3dh" 9 | "tinygo.org/x/tinyfont" 10 | "tinygo.org/x/tinyfont/proggy" 11 | 12 | "tinygo.org/x/drivers/st7735" 13 | "tinygo.org/x/tinydraw" 14 | ) 15 | 16 | func main() { 17 | machine.SPI1.Configure(machine.SPIConfig{ 18 | SCK: machine.SPI1_SCK_PIN, 19 | SDO: machine.SPI1_SDO_PIN, 20 | SDI: machine.SPI1_SDI_PIN, 21 | Frequency: 8000000, 22 | }) 23 | 24 | display := st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 25 | display.Configure(st7735.Config{ 26 | Rotation: st7735.ROTATION_90, 27 | }) 28 | 29 | machine.I2C0.Configure(machine.I2CConfig{SCL: machine.SCL_PIN, SDA: machine.SDA_PIN}) 30 | 31 | accel := lis3dh.New(machine.I2C0) 32 | accel.Address = lis3dh.Address0 33 | accel.Configure() 34 | 35 | white := color.RGBA{255, 255, 255, 255} 36 | red := color.RGBA{255, 0, 0, 255} 37 | green := color.RGBA{0, 255, 0, 255} 38 | blue := color.RGBA{0, 0, 255, 255} 39 | black := color.RGBA{0, 0, 0, 255} 40 | 41 | display.FillScreen(white) 42 | tinydraw.Rectangle(&display, 26, 30, 132, 7, black) 43 | tinydraw.Rectangle(&display, 26, 40, 132, 7, black) 44 | tinydraw.Rectangle(&display, 26, 50, 132, 7, black) 45 | 46 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 10, 80, "Move the PyBadge to see", black) 47 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 14, 90, "the accelerometer in", black) 48 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 60, 100, "action.", black) 49 | 50 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 36, "X:", black) 51 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 46, "Y:", black) 52 | tinyfont.WriteLine(&display, &proggy.TinySZ8pt7b, 8, 56, "Z:", black) 53 | 54 | x, y, z := accel.ReadRawAcceleration() 55 | for { 56 | x, y, z = accel.ReadRawAcceleration() 57 | x = x / 500 58 | y = y / 500 59 | z = z / 500 60 | if x > 64 { 61 | x = 64 62 | } 63 | if y > 64 { 64 | y = 64 65 | } 66 | if z > 64 { 67 | z = 64 68 | } 69 | if x < -64 { 70 | x = -64 71 | } 72 | if y < -64 { 73 | y = -64 74 | } 75 | if z < -64 { 76 | z = -64 77 | } 78 | display.FillRectangle(28, 32, 128, 2, white) 79 | display.FillRectangle(28, 42, 128, 2, white) 80 | display.FillRectangle(28, 52, 128, 2, white) 81 | if x < 0 { 82 | display.FillRectangle(92+x, 32, -x, 2, red) 83 | } else { 84 | display.FillRectangle(92, 32, x, 2, red) 85 | } 86 | if y < 0 { 87 | display.FillRectangle(92+y, 42, -y, 2, green) 88 | } else { 89 | display.FillRectangle(92, 42, y, 2, green) 90 | } 91 | if z < 0 { 92 | display.FillRectangle(92+z, 52, -z, 2, blue) 93 | } else { 94 | display.FillRectangle(92, 52, z, 2, blue) 95 | } 96 | 97 | println("X:", x, "Y:", y, "Z:", z) 98 | time.Sleep(time.Millisecond * 100) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tutorial/basics/step8/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "machine" 5 | "time" 6 | 7 | "tinygo.org/x/drivers/shifter" 8 | ) 9 | 10 | var bzrPin machine.Pin 11 | 12 | func main() { 13 | 14 | // Enable the speaker 15 | speaker := machine.SPEAKER_ENABLE 16 | speaker.Configure(machine.PinConfig{Mode: machine.PinOutput}) 17 | speaker.High() 18 | 19 | // buzzer setup 20 | bzrPin = machine.A0 21 | bzrPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) 22 | 23 | buttons := shifter.NewButtons() 24 | buttons.Configure() 25 | 26 | for { 27 | buttons.ReadInput() 28 | if buttons.Pins[shifter.BUTTON_LEFT].Get() { 29 | tone(329) 30 | } 31 | if buttons.Pins[shifter.BUTTON_UP].Get() { 32 | tone(369) 33 | } 34 | if buttons.Pins[shifter.BUTTON_DOWN].Get() { 35 | tone(523) 36 | } 37 | if buttons.Pins[shifter.BUTTON_RIGHT].Get() { 38 | tone(739) 39 | } 40 | if buttons.Pins[shifter.BUTTON_A].Get() { 41 | tone(1046) 42 | } 43 | if buttons.Pins[shifter.BUTTON_B].Get() { 44 | tone(1975) 45 | } 46 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 47 | tone(2637) 48 | } 49 | if buttons.Pins[shifter.BUTTON_START].Get() { 50 | tone(5274) 51 | } 52 | } 53 | } 54 | 55 | func tone(tone int) { 56 | for i := 0; i < 10; i++ { 57 | bzrPin.High() 58 | time.Sleep(time.Duration(tone) * time.Microsecond) 59 | 60 | bzrPin.Low() 61 | time.Sleep(time.Duration(tone) * time.Microsecond) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tutorial/flightbadge/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "strings" 6 | "time" 7 | 8 | "machine" 9 | "machine/usb/hid/keyboard" 10 | 11 | "tinygo.org/x/drivers/shifter" 12 | "tinygo.org/x/drivers/st7735" 13 | 14 | "tinygo.org/x/tinyfont/proggy" 15 | "tinygo.org/x/tinyterm" 16 | ) 17 | 18 | var ( 19 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 20 | 21 | terminal = tinyterm.NewTerminal(&display) 22 | 23 | black = color.RGBA{0, 0, 0, 255} 24 | white = color.RGBA{255, 255, 255, 255} 25 | red = color.RGBA{255, 0, 0, 255} 26 | blue = color.RGBA{0, 0, 255, 255} 27 | green = color.RGBA{0, 255, 0, 255} 28 | 29 | font = &proggy.TinySZ8pt7b 30 | ) 31 | 32 | var ( 33 | shifted bool 34 | lastKey string 35 | lastTime time.Time 36 | ) 37 | 38 | var logo = ` 39 | ___ _ _ _ _ 40 | | __| (_)__ _| |_| |_ 41 | | _|| | / _\ | ' \ _| 42 | |_|_|_|_\__, |_||_\__| 43 | | _ ) __|___/| |__ _ ___ 44 | | _ \/ _\ / _\ / _\ / -_) 45 | |___/\__,_\__,_\__, \___| 46 | |___/ 47 | ` 48 | 49 | func main() { 50 | go handleDisplay() 51 | 52 | buttons := shifter.NewButtons() 53 | buttons.Configure() 54 | 55 | for { 56 | buttons.ReadInput() 57 | 58 | // takeoff 59 | if buttons.Pins[shifter.BUTTON_START].Get() { 60 | handleKey("[") 61 | } 62 | 63 | // land 64 | if buttons.Pins[shifter.BUTTON_A].Get() { 65 | handleKey("]") 66 | } 67 | 68 | // front flip 69 | if buttons.Pins[shifter.BUTTON_SELECT].Get() { 70 | handleKey("t") 71 | } 72 | 73 | // hold down button B to shift to access second set of arrow commands 74 | if buttons.Pins[shifter.BUTTON_B].Get() { 75 | shifted = true 76 | } else { 77 | shifted = false 78 | } 79 | 80 | if buttons.Pins[shifter.BUTTON_LEFT].Get() { 81 | handleShiftedKey("j", "a") 82 | } 83 | 84 | if buttons.Pins[shifter.BUTTON_UP].Get() { 85 | handleShiftedKey("i", "w") 86 | } 87 | 88 | if buttons.Pins[shifter.BUTTON_DOWN].Get() { 89 | handleShiftedKey("k", "s") 90 | } 91 | 92 | if buttons.Pins[shifter.BUTTON_RIGHT].Get() { 93 | handleShiftedKey("l", "d") 94 | } 95 | 96 | time.Sleep(50 * time.Millisecond) 97 | } 98 | } 99 | 100 | func handleShiftedKey(key1, key2 string) { 101 | if shifted { 102 | handleKey(key1) 103 | return 104 | } 105 | handleKey(key2) 106 | } 107 | 108 | func handleKey(key string) { 109 | // simple debounce 110 | if key == lastKey && time.Since(lastTime) < 150*time.Millisecond { 111 | return 112 | } 113 | 114 | kb := keyboard.New() 115 | kb.Write([]byte(key)) 116 | 117 | lastKey, lastTime = key, time.Now() 118 | } 119 | 120 | func handleDisplay() { 121 | machine.SPI1.Configure(machine.SPIConfig{ 122 | SCK: machine.SPI1_SCK_PIN, 123 | SDO: machine.SPI1_SDO_PIN, 124 | SDI: machine.SPI1_SDI_PIN, 125 | Frequency: 8000000, 126 | }) 127 | 128 | display.Configure(st7735.Config{ 129 | Rotation: st7735.ROTATION_90, 130 | }) 131 | 132 | terminal.Configure(&tinyterm.Config{ 133 | Font: font, 134 | FontHeight: 10, 135 | FontOffset: 6, 136 | UseSoftwareScroll: true, 137 | }) 138 | 139 | display.FillScreen(black) 140 | 141 | showSplash() 142 | 143 | input := make([]byte, 64) 144 | i := 0 145 | 146 | for { 147 | if machine.Serial.Buffered() > 0 { 148 | data, _ := machine.Serial.ReadByte() 149 | 150 | switch data { 151 | case 13: 152 | // return key 153 | terminal.Write([]byte("\r\n")) 154 | terminal.Write(input[:i]) 155 | i = 0 156 | default: 157 | input[i] = data 158 | i++ 159 | } 160 | } 161 | time.Sleep(10 * time.Millisecond) 162 | } 163 | } 164 | 165 | func showSplash() { 166 | for _, line := range strings.Split(strings.TrimSuffix(logo, "\n"), "\n") { 167 | terminal.Write([]byte(line)) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /tutorial/mynameis/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | 7 | "tinygo.org/x/tinydraw" 8 | "tinygo.org/x/tinyfont" 9 | "tinygo.org/x/tinyfont/freesans" 10 | "tinygo.org/x/tinyfont/gophers" 11 | 12 | "tinygo.org/x/drivers/st7735" 13 | ) 14 | 15 | const ( 16 | WIDTH = 160 17 | HEIGHT = 128 18 | name = "@TinyGolang" 19 | ) 20 | 21 | func main() { 22 | machine.SPI1.Configure(machine.SPIConfig{ 23 | SCK: machine.SPI1_SCK_PIN, 24 | SDO: machine.SPI1_SDO_PIN, 25 | SDI: machine.SPI1_SDI_PIN, 26 | Frequency: 8000000, 27 | }) 28 | 29 | display := st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 30 | display.Configure(st7735.Config{ 31 | Rotation: st7735.ROTATION_90, 32 | }) 33 | 34 | display.FillScreen(color.RGBA{255, 255, 255, 255}) 35 | 36 | var r int16 = 8 37 | 38 | // black corners detail 39 | display.FillRectangle(0, 0, r, r, color.RGBA{0, 0, 0, 255}) 40 | display.FillRectangle(0, HEIGHT-r, r, r, color.RGBA{0, 0, 0, 255}) 41 | display.FillRectangle(WIDTH-r, 0, r, r, color.RGBA{0, 0, 0, 255}) 42 | display.FillRectangle(WIDTH-r, HEIGHT-r, r, r, color.RGBA{0, 0, 0, 255}) 43 | 44 | // round corners 45 | tinydraw.FilledCircle(&display, r, r, r, color.RGBA{255, 0, 0, 255}) 46 | tinydraw.FilledCircle(&display, WIDTH-r-1, r, r, color.RGBA{255, 0, 0, 255}) 47 | tinydraw.FilledCircle(&display, r, HEIGHT-r-1, r, color.RGBA{255, 0, 0, 255}) 48 | tinydraw.FilledCircle(&display, WIDTH-r-1, HEIGHT-r-1, r, color.RGBA{255, 0, 0, 255}) 49 | 50 | // top band 51 | display.FillRectangle(r, 0, WIDTH-2*r-1, r, color.RGBA{255, 0, 0, 255}) 52 | display.FillRectangle(0, r, WIDTH, 26, color.RGBA{255, 0, 0, 255}) 53 | 54 | // bottom band 55 | display.FillRectangle(r, HEIGHT-r-1, WIDTH-2*r-1, r+1, color.RGBA{255, 0, 0, 255}) 56 | display.FillRectangle(0, HEIGHT-2*r-1, WIDTH, r, color.RGBA{255, 0, 0, 255}) 57 | 58 | // top text : my NAME is 59 | w32, _ := tinyfont.LineWidth(&freesans.Regular12pt7b, "my NAME is") 60 | tinyfont.WriteLine(&display, &freesans.Regular12pt7b, (WIDTH-int16(w32))/2, 24, "my NAME is", color.RGBA{255, 255, 255, 255}) 61 | 62 | // middle text 63 | w32, _ = tinyfont.LineWidth(&freesans.Bold9pt7b, name) 64 | tinyfont.WriteLine(&display, &freesans.Bold9pt7b, (WIDTH-int16(w32))/2, 72, name, color.RGBA{0, 0, 0, 255}) 65 | 66 | // gophers fonts 67 | tinyfont.WriteLine(&display, &gophers.Regular32pt, WIDTH-48, 110, "BE", color.RGBA{0, 0, 0, 255}) 68 | } 69 | -------------------------------------------------------------------------------- /tutorial/snake/README.md: -------------------------------------------------------------------------------- 1 | # GoBadge Snake Tutorial 2 | 3 | In this tutorial we're going to build a _snake-like_ game from scratch. 4 | 5 | ## What you need 6 | 7 | - GoBadge aka Adafruit PyBadge 8 | - Personal computer with Go 1.18/1.19 and TinyGo installed, and a serial port. 9 | - Have complete the GoBdge tutorial 10 | 11 | ## Installation 12 | 13 | ### Go 14 | 15 | If somehow you have not installed Go on your computer already, you can download it here: 16 | 17 | https://go.dev/dl/ 18 | 19 | Now you are ready to install TinyGo. 20 | 21 | ### TinyGo 22 | 23 | Follow the instructions here for your operating system: 24 | 25 | https://tinygo.org/getting-started/ 26 | 27 | ## Connecting the GoBadge to your computer 28 | 29 | ![Adafruit GoBadge](./assets/pybadge_hello.jpg) 30 | 31 | Plug the GoBadge into your computer using a USB cable. There may be one provided in your starter kit. 32 | 33 | ## Running the code 34 | 35 | The TinyGo programs will run directly on the GoBadge's microcontoller. The procedure is basically: 36 | 37 | - Edit your TinyGo program. 38 | - Compile and flash it to your GoBadge. 39 | - The program executes from the GoBadge. You can disconnect the GoBadge from your computer and plug it into a battery if you wish, the program executes directly on the microcontroller. 40 | 41 | Let's get started! 42 | 43 | ## Code 44 | 45 | ### step0.go - Get a pixel on the screen 46 | 47 | This step is to get familiar with the display and the drawing functions. 48 | 49 | ![Adafruit PyBadge bootloader](./assets/pybadge_bootloader.jpg) 50 | 51 | ``` 52 | tinygo flash -target gobadge ./step0/main.go 53 | ``` 54 | 55 | Once the PyBadge is flashed correctly, a green pixel will appear on the middle of the screen. Feel free to change the values of `display.SetPixel` (towards the bottom of the ./step0/main.go file) and see where the pixel appears! 56 | 57 | ![A pixel on the screen](./assets/step0.jpg) 58 | 59 | ### step1.go - A pixel, but bigger! 60 | 61 | Run the code. 62 | 63 | ``` 64 | tinygo flash -target gobadge ./step1/main.go 65 | ``` 66 | 67 | ![A bigger pixel](./assets/step1.jpg) 68 | 69 | Instead of a pixel, we are drawing a 10x10 green rectangle. 70 | 71 | ### step2.go - I like to move it, move it 72 | 73 | Run the code. 74 | 75 | ``` 76 | tinygo flash -target gobadge ./step2/main.go 77 | ``` 78 | 79 | We listen to the input buttons and move our rectangle across the display. 80 | 81 | ![A pixel moving around](./assets/step2.gif) 82 | 83 | ### step3.go - Run, snake, run 84 | 85 | Run the code. 86 | 87 | ``` 88 | tinygo flash -target gobadge ./step3/main.go 89 | ``` 90 | 91 | Have you noticed the snake at the previous step was kind of slow? That was because display.FillScreen draws the whole display and is a slow process, we could improve the speed if only re-draw the pixels that has 92 | changed. 93 | 94 | ![Several pixels = a snake](./assets/step3.gif) 95 | 96 | ### step4.go - Welcome to the grid 97 | 98 | Run the code. 99 | 100 | ``` 101 | tinygo flash -target gobadge ./step4/main.go 102 | ``` 103 | 104 | In the previous step, the 10x10 _snake_ was moving by 1 pixel each time, we need to divide our display (160x128) in a 10x10 grid so the snake will move a whole block each time. 105 | 106 | ![Block by block](./assets/step4.gif) 107 | 108 | ### step5.go - Long snake is long 109 | 110 | Run the code. 111 | 112 | ``` 113 | tinygo flash -target gobadge ./step5/main.go 114 | ``` 115 | 116 | Our little snake grew from 1 block to 3 block length. 117 | 118 | ![1, 2, 3!](./assets/step5.jpg) 119 | 120 | ### step6.go - Time to grow up 121 | 122 | Feed our snake some red apples so it can grow 123 | 124 | ``` 125 | tinygo flash -target gobadge ./step6/main.go 126 | ``` 127 | 128 | ![I wanna grow up!](./assets/step6.jpg) 129 | 130 | The display will show some blue circles. When a button is pressed a ring will be shown around its corresponding circle. 131 | 132 | ### step7.go - Score & game mechanics 133 | 134 | Run the code. 135 | 136 | ``` 137 | tinygo flash -target gobadge ./step7/main.go 138 | ``` 139 | 140 | ![Let's play](./assets/step7_01.gif) 141 | 142 | Add game mechanics such as collision (game over) and score. 143 | 144 | ![Game over, try again!](./assets/step7_02.jpg) 145 | 146 | ### step8.go - Get wild! 147 | 148 | There's no step 8, it's time to get creative and modify the game as you wish, try adding sounds or different colors 149 | -------------------------------------------------------------------------------- /tutorial/snake/assets/step0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step0.jpg -------------------------------------------------------------------------------- /tutorial/snake/assets/step1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step1.jpg -------------------------------------------------------------------------------- /tutorial/snake/assets/step2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step2.gif -------------------------------------------------------------------------------- /tutorial/snake/assets/step3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step3.gif -------------------------------------------------------------------------------- /tutorial/snake/assets/step4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step4.gif -------------------------------------------------------------------------------- /tutorial/snake/assets/step5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step5.jpg -------------------------------------------------------------------------------- /tutorial/snake/assets/step6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step6.jpg -------------------------------------------------------------------------------- /tutorial/snake/assets/step7_01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step7_01.gif -------------------------------------------------------------------------------- /tutorial/snake/assets/step7_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinygo-org/gobadge/861c707374e3fec1443339b3474ed923894cb7ce/tutorial/snake/assets/step7_02.jpg -------------------------------------------------------------------------------- /tutorial/snake/step0/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/st7735" 9 | ) 10 | 11 | var display st7735.Device 12 | 13 | func main() { 14 | // Setup the SPI connection of the GoBadge 15 | machine.SPI1.Configure(machine.SPIConfig{ 16 | SCK: machine.SPI1_SCK_PIN, 17 | SDO: machine.SPI1_SDO_PIN, 18 | SDI: machine.SPI1_SDI_PIN, 19 | Frequency: 8000000, 20 | }) 21 | 22 | // Create a new display device 23 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 24 | display.Configure(st7735.Config{ 25 | Rotation: st7735.ROTATION_90, 26 | }) 27 | 28 | green := color.RGBA{0, 255, 0, 255} 29 | black := color.RGBA{0, 0, 0, 255} 30 | 31 | // fill the whole screen with black 32 | display.FillScreen(black) 33 | 34 | w, h := display.Size() 35 | // draw a green pixel at the middle of the screen 36 | display.SetPixel(w/2, h/2, green) 37 | for { 38 | time.Sleep(1 * time.Second) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tutorial/snake/step1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/st7735" 9 | ) 10 | 11 | var display st7735.Device 12 | 13 | func main() { 14 | // Setup the SPI connection of the GoBadge 15 | machine.SPI1.Configure(machine.SPIConfig{ 16 | SCK: machine.SPI1_SCK_PIN, 17 | SDO: machine.SPI1_SDO_PIN, 18 | SDI: machine.SPI1_SDI_PIN, 19 | Frequency: 8000000, 20 | }) 21 | 22 | // Create a new display device 23 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 24 | display.Configure(st7735.Config{ 25 | Rotation: st7735.ROTATION_90, 26 | }) 27 | 28 | green := color.RGBA{0, 255, 0, 255} 29 | black := color.RGBA{0, 0, 0, 255} 30 | 31 | // fill the whole screen with black 32 | display.FillScreen(black) 33 | 34 | w, h := display.Size() 35 | // draw a green 10x10 rectangle at the middle of the screen 36 | display.FillRectangle((w-10)/2, (h-10)/2, 10, 10, green) 37 | for { 38 | time.Sleep(1 * time.Second) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tutorial/snake/step2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | "tinygo.org/x/drivers/st7735" 10 | ) 11 | 12 | var display st7735.Device 13 | 14 | func main() { 15 | // Setup the SPI connection of the GoBadge 16 | machine.SPI1.Configure(machine.SPIConfig{ 17 | SCK: machine.SPI1_SCK_PIN, 18 | SDO: machine.SPI1_SDO_PIN, 19 | SDI: machine.SPI1_SDI_PIN, 20 | Frequency: 8000000, 21 | }) 22 | 23 | // Create a new display device 24 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 25 | display.Configure(st7735.Config{ 26 | Rotation: st7735.ROTATION_90, 27 | }) 28 | 29 | // Setup the buttons 30 | buttons := shifter.NewButtons() 31 | buttons.Configure() 32 | 33 | green := color.RGBA{0, 255, 0, 255} 34 | black := color.RGBA{0, 0, 0, 255} 35 | 36 | // fill the whole screen with black 37 | display.FillScreen(black) 38 | 39 | w, h := display.Size() 40 | x := (w - 10) / 2 41 | y := (h - 10) / 2 42 | for { 43 | 44 | buttons.ReadInput() 45 | switch { 46 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 47 | x-- 48 | case buttons.Pins[shifter.BUTTON_UP].Get(): 49 | y-- 50 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 51 | y++ 52 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 53 | x++ 54 | } 55 | 56 | // clear the display and paint everything black 57 | display.FillScreen(black) 58 | 59 | // draw our little snake-rectangle 60 | display.FillRectangle(x, y, 10, 10, green) 61 | 62 | time.Sleep(100 * time.Millisecond) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tutorial/snake/step3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | "tinygo.org/x/drivers/st7735" 10 | ) 11 | 12 | var display st7735.Device 13 | 14 | func main() { 15 | // Setup the SPI connection of the GoBadge 16 | machine.SPI1.Configure(machine.SPIConfig{ 17 | SCK: machine.SPI1_SCK_PIN, 18 | SDO: machine.SPI1_SDO_PIN, 19 | SDI: machine.SPI1_SDI_PIN, 20 | Frequency: 8000000, 21 | }) 22 | 23 | // Create a new display device 24 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 25 | display.Configure(st7735.Config{ 26 | Rotation: st7735.ROTATION_90, 27 | }) 28 | 29 | // Setup the buttons 30 | buttons := shifter.NewButtons() 31 | buttons.Configure() 32 | 33 | green := color.RGBA{0, 255, 0, 255} 34 | black := color.RGBA{0, 0, 0, 255} 35 | 36 | // fill the whole screen with black 37 | display.FillScreen(black) 38 | 39 | w, h := display.Size() 40 | x := (w - 10) / 2 41 | y := (h - 10) / 2 42 | for { 43 | 44 | // "clear" our previous snake position 45 | display.FillRectangle(x, y, 10, 10, black) 46 | 47 | buttons.ReadInput() 48 | switch { 49 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 50 | x-- 51 | case buttons.Pins[shifter.BUTTON_UP].Get(): 52 | y-- 53 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 54 | y++ 55 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 56 | x++ 57 | } 58 | 59 | // draw our little snake-rectangle in their new position 60 | display.FillRectangle(x, y, 10, 10, green) 61 | 62 | time.Sleep(100 * time.Millisecond) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tutorial/snake/step4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/shifter" 9 | "tinygo.org/x/drivers/st7735" 10 | ) 11 | 12 | const ( 13 | WIDTHBLOCKS = 16 14 | HEIGHTBLOCKS = 13 15 | ) 16 | 17 | var display st7735.Device 18 | 19 | func main() { 20 | // Setup the SPI connection of the GoBadge 21 | machine.SPI1.Configure(machine.SPIConfig{ 22 | SCK: machine.SPI1_SCK_PIN, 23 | SDO: machine.SPI1_SDO_PIN, 24 | SDI: machine.SPI1_SDI_PIN, 25 | Frequency: 8000000, 26 | }) 27 | 28 | // Create a new display device 29 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 30 | display.Configure(st7735.Config{ 31 | Rotation: st7735.ROTATION_90, 32 | }) 33 | 34 | // Setup the buttons 35 | buttons := shifter.NewButtons() 36 | buttons.Configure() 37 | 38 | green := color.RGBA{0, 255, 0, 255} 39 | black := color.RGBA{0, 0, 0, 255} 40 | 41 | // fill the whole screen with black 42 | display.FillScreen(black) 43 | 44 | x := int16(8) 45 | y := int16(6) 46 | modY := int16(10) 47 | for { 48 | 49 | // "clear" our previous snake position 50 | if y == 12 { // since the screen is 128 pixels in height, the last row of the grid should be 8 pixels instead of 10 51 | modY = 8 52 | } else { 53 | modY = 10 54 | } 55 | display.FillRectangle(x*10, y*10, 10, modY, black) 56 | 57 | buttons.ReadInput() 58 | switch { 59 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 60 | x-- 61 | case buttons.Pins[shifter.BUTTON_UP].Get(): 62 | y-- 63 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 64 | y++ 65 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 66 | x++ 67 | } 68 | 69 | // control it doesn't get out of bounds 70 | if x >= WIDTHBLOCKS { 71 | x = 0 72 | } 73 | if x < 0 { 74 | x = WIDTHBLOCKS - 1 75 | } 76 | if y >= HEIGHTBLOCKS { 77 | y = 0 78 | } 79 | if y < 0 { 80 | y = HEIGHTBLOCKS - 1 81 | } 82 | 83 | // draw our little snake-rectangle in their new position 84 | if y == 12 { // since the screen is 128 pixels in height, the last row of the grid should be 8 pixels instead of 10 85 | modY = 8 86 | } else { 87 | modY = 10 88 | } 89 | display.FillRectangle(x*10, y*10, 10, modY, green) 90 | 91 | time.Sleep(100 * time.Millisecond) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tutorial/snake/step5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "math/rand" 7 | "time" 8 | 9 | "tinygo.org/x/drivers/shifter" 10 | "tinygo.org/x/drivers/st7735" 11 | ) 12 | 13 | const ( 14 | WIDTHBLOCKS = 16 15 | HEIGHTBLOCKS = 13 16 | ) 17 | 18 | const ( 19 | SnakeUp = iota 20 | SnakeDown 21 | SnakeLeft 22 | SnakeRight 23 | ) 24 | 25 | var display st7735.Device 26 | 27 | type Snake struct { 28 | body [3][2]int16 29 | direction int16 30 | } 31 | 32 | var snake = Snake{ 33 | body: [3][2]int16{ 34 | {0, 3}, 35 | {0, 2}, 36 | {0, 1}, 37 | }, 38 | direction: 3, 39 | } 40 | 41 | var appleX = int16(-1) 42 | var appleY = int16(-1) 43 | 44 | var red = color.RGBA{255, 0, 0, 255} 45 | var green = color.RGBA{0, 255, 0, 255} 46 | var black = color.RGBA{0, 0, 0, 255} 47 | 48 | func main() { 49 | // Setup the SPI connection of the GoBadge 50 | machine.SPI1.Configure(machine.SPIConfig{ 51 | SCK: machine.SPI1_SCK_PIN, 52 | SDO: machine.SPI1_SDO_PIN, 53 | SDI: machine.SPI1_SDI_PIN, 54 | Frequency: 8000000, 55 | }) 56 | 57 | // Create a new display device 58 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 59 | display.Configure(st7735.Config{ 60 | Rotation: st7735.ROTATION_90, 61 | }) 62 | 63 | // Setup the buttons 64 | buttons := shifter.NewButtons() 65 | buttons.Configure() 66 | 67 | // fill the whole screen with black 68 | display.FillScreen(black) 69 | 70 | drawSnake() 71 | for { 72 | buttons.ReadInput() 73 | switch { 74 | // add some checks so the snake doesn't go backwards 75 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 76 | if snake.direction != SnakeRight { 77 | snake.direction = SnakeLeft 78 | } 79 | case buttons.Pins[shifter.BUTTON_UP].Get(): 80 | if snake.direction != SnakeDown { 81 | snake.direction = SnakeUp 82 | } 83 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 84 | if snake.direction != SnakeUp { 85 | snake.direction = SnakeDown 86 | } 87 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 88 | if snake.direction != SnakeLeft { 89 | snake.direction = SnakeRight 90 | } 91 | } 92 | 93 | moveSnake() 94 | time.Sleep(100 * time.Millisecond) 95 | } 96 | } 97 | 98 | func moveSnake() { 99 | // get the coords of the head 100 | x := snake.body[0][0] 101 | y := snake.body[0][1] 102 | 103 | switch snake.direction { 104 | case SnakeLeft: 105 | x-- 106 | break 107 | case SnakeUp: 108 | y-- 109 | break 110 | case SnakeDown: 111 | y++ 112 | break 113 | case SnakeRight: 114 | x++ 115 | break 116 | } 117 | // check the bounds 118 | if x >= WIDTHBLOCKS { 119 | x = 0 120 | } 121 | if x < 0 { 122 | x = WIDTHBLOCKS - 1 123 | } 124 | if y >= HEIGHTBLOCKS { 125 | y = 0 126 | } 127 | if y < 0 { 128 | y = HEIGHTBLOCKS - 1 129 | } 130 | 131 | // draw head 132 | drawSnakePartial(x, y, green) 133 | 134 | // remove tail 135 | drawSnakePartial(snake.body[2][0], snake.body[2][1], black) 136 | 137 | // move each segment coords to the next one 138 | for i := 2; i > 0; i-- { 139 | snake.body[i][0] = snake.body[i-1][0] 140 | snake.body[i][1] = snake.body[i-1][1] 141 | } 142 | snake.body[0][0] = x 143 | snake.body[0][1] = y 144 | } 145 | 146 | func drawSnake() { 147 | for i := int16(0); i < 3; i++ { 148 | drawSnakePartial(snake.body[i][0], snake.body[i][1], green) 149 | } 150 | } 151 | 152 | func drawSnakePartial(x, y int16, c color.RGBA) { 153 | modY := int16(9) 154 | if y == 12 { 155 | modY = 8 156 | } 157 | // we changed the size of 10 to 9, so a black border is shown 158 | // around each segment of the snake 159 | display.FillRectangle(10*x, 10*y, 9, modY, c) 160 | } 161 | 162 | func createApple() { 163 | appleX = int16(rand.Int31n(WIDTHBLOCKS)) 164 | appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 165 | drawSnakePartial(appleX, appleY, red) 166 | } 167 | -------------------------------------------------------------------------------- /tutorial/snake/step6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "math/rand" 7 | "time" 8 | 9 | "tinygo.org/x/drivers/shifter" 10 | "tinygo.org/x/drivers/st7735" 11 | ) 12 | 13 | const ( 14 | WIDTHBLOCKS = 16 15 | HEIGHTBLOCKS = 13 16 | ) 17 | 18 | const ( 19 | SnakeUp = iota 20 | SnakeDown 21 | SnakeLeft 22 | SnakeRight 23 | ) 24 | 25 | var display st7735.Device 26 | 27 | type Snake struct { 28 | body [208][2]int16 29 | length int16 30 | direction int16 31 | } 32 | 33 | var snake = Snake{ 34 | body: [208][2]int16{ 35 | {0, 3}, 36 | {0, 2}, 37 | {0, 1}, 38 | }, 39 | length: 3, 40 | direction: 3, 41 | } 42 | 43 | var appleX = int16(-1) 44 | var appleY = int16(-1) 45 | 46 | var red = color.RGBA{255, 0, 0, 255} 47 | var green = color.RGBA{0, 255, 0, 255} 48 | var black = color.RGBA{0, 0, 0, 255} 49 | 50 | func main() { 51 | // Setup the SPI connection of the GoBadge 52 | machine.SPI1.Configure(machine.SPIConfig{ 53 | SCK: machine.SPI1_SCK_PIN, 54 | SDO: machine.SPI1_SDO_PIN, 55 | SDI: machine.SPI1_SDI_PIN, 56 | Frequency: 8000000, 57 | }) 58 | 59 | // Create a new display device 60 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 61 | display.Configure(st7735.Config{ 62 | Rotation: st7735.ROTATION_90, 63 | }) 64 | 65 | // Setup the buttons 66 | buttons := shifter.NewButtons() 67 | buttons.Configure() 68 | 69 | // fill the whole screen with black 70 | display.FillScreen(black) 71 | 72 | createApple() 73 | drawSnake() 74 | for { 75 | buttons.ReadInput() 76 | switch { 77 | // add some checks so the snake doesn't go backwards 78 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 79 | if snake.direction != SnakeRight { 80 | snake.direction = SnakeLeft 81 | } 82 | case buttons.Pins[shifter.BUTTON_UP].Get(): 83 | if snake.direction != SnakeDown { 84 | snake.direction = SnakeUp 85 | } 86 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 87 | if snake.direction != SnakeUp { 88 | snake.direction = SnakeDown 89 | } 90 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 91 | if snake.direction != SnakeLeft { 92 | snake.direction = SnakeRight 93 | } 94 | } 95 | 96 | moveSnake() 97 | time.Sleep(100 * time.Millisecond) 98 | } 99 | } 100 | 101 | func moveSnake() { 102 | // get the coords of the head 103 | x := snake.body[0][0] 104 | y := snake.body[0][1] 105 | 106 | switch snake.direction { 107 | case SnakeLeft: 108 | x-- 109 | break 110 | case SnakeUp: 111 | y-- 112 | break 113 | case SnakeDown: 114 | y++ 115 | break 116 | case SnakeRight: 117 | x++ 118 | break 119 | } 120 | // check the bounds 121 | if x >= WIDTHBLOCKS { 122 | x = 0 123 | } 124 | if x < 0 { 125 | x = WIDTHBLOCKS - 1 126 | } 127 | if y >= HEIGHTBLOCKS { 128 | y = 0 129 | } 130 | if y < 0 { 131 | y = HEIGHTBLOCKS - 1 132 | } 133 | 134 | // draw head 135 | drawSnakePartial(x, y, green) 136 | 137 | if x == appleX && y == appleY { 138 | // grow our snake if we eat the apple 139 | snake.length++ 140 | // create a new apple 141 | createApple() 142 | } else { 143 | // remove tail in case we do not eat the apple 144 | drawSnakePartial(snake.body[snake.length-1][0], snake.body[snake.length-1][1], black) 145 | } 146 | for i := snake.length - 1; i > 0; i-- { 147 | snake.body[i][0] = snake.body[i-1][0] 148 | snake.body[i][1] = snake.body[i-1][1] 149 | } 150 | snake.body[0][0] = x 151 | snake.body[0][1] = y 152 | } 153 | 154 | func drawSnake() { 155 | for i := int16(0); i < snake.length; i++ { 156 | drawSnakePartial(snake.body[i][0], snake.body[i][1], green) 157 | } 158 | } 159 | 160 | func drawSnakePartial(x, y int16, c color.RGBA) { 161 | modY := int16(9) 162 | if y == 12 { 163 | modY = 8 164 | } 165 | // we changed the size of 10 to 9, so a black border is shown 166 | // around each segment of the snake 167 | display.FillRectangle(10*x, 10*y, 9, modY, c) 168 | } 169 | 170 | func createApple() { 171 | appleX = int16(rand.Int31n(WIDTHBLOCKS)) 172 | appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 173 | drawSnakePartial(appleX, appleY, red) 174 | } 175 | -------------------------------------------------------------------------------- /tutorial/snake/step7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "math/rand" 7 | "strconv" 8 | "time" 9 | 10 | "tinygo.org/x/tinyfont" 11 | "tinygo.org/x/tinyfont/freesans" 12 | 13 | "tinygo.org/x/drivers/shifter" 14 | "tinygo.org/x/drivers/st7735" 15 | ) 16 | 17 | const ( 18 | WIDTHBLOCKS = 16 19 | HEIGHTBLOCKS = 13 20 | ) 21 | 22 | const ( 23 | SnakeUp = iota 24 | SnakeDown 25 | SnakeLeft 26 | SnakeRight 27 | ) 28 | 29 | var display st7735.Device 30 | var buttons shifter.Device 31 | 32 | type Snake struct { 33 | body [208][2]int16 34 | length int16 35 | direction int16 36 | } 37 | 38 | var snake = Snake{ 39 | body: [208][2]int16{ 40 | {0, 3}, 41 | {0, 2}, 42 | {0, 1}, 43 | }, 44 | length: 3, 45 | direction: 3, 46 | } 47 | var appleX = int16(-1) 48 | var appleY = int16(-1) 49 | 50 | var red = color.RGBA{255, 0, 0, 255} 51 | var green = color.RGBA{0, 255, 0, 255} 52 | var black = color.RGBA{0, 0, 0, 255} 53 | var white = color.RGBA{255, 255, 255, 255} 54 | 55 | func main() { 56 | // Setup the SPI connection of the GoBadge 57 | machine.SPI1.Configure(machine.SPIConfig{ 58 | SCK: machine.SPI1_SCK_PIN, 59 | SDO: machine.SPI1_SDO_PIN, 60 | SDI: machine.SPI1_SDI_PIN, 61 | Frequency: 8000000, 62 | }) 63 | 64 | // Create a new display device 65 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 66 | display.Configure(st7735.Config{ 67 | Rotation: st7735.ROTATION_90, 68 | }) 69 | 70 | // Setup the buttons 71 | buttons = shifter.NewButtons() 72 | buttons.Configure() 73 | 74 | // fill the whole screen with black 75 | display.FillScreen(black) 76 | 77 | drawSnake() 78 | createApple() 79 | for { 80 | buttons.ReadInput() 81 | switch { 82 | // add some checks so the snake doesn't go backwards 83 | case buttons.Pins[shifter.BUTTON_LEFT].Get(): 84 | if snake.direction != SnakeRight { 85 | snake.direction = SnakeLeft 86 | } 87 | case buttons.Pins[shifter.BUTTON_UP].Get(): 88 | if snake.direction != SnakeDown { 89 | snake.direction = SnakeUp 90 | } 91 | case buttons.Pins[shifter.BUTTON_DOWN].Get(): 92 | if snake.direction != SnakeUp { 93 | snake.direction = SnakeDown 94 | } 95 | case buttons.Pins[shifter.BUTTON_RIGHT].Get(): 96 | if snake.direction != SnakeLeft { 97 | snake.direction = SnakeRight 98 | } 99 | } 100 | 101 | moveSnake() 102 | time.Sleep(100 * time.Millisecond) 103 | } 104 | } 105 | 106 | func moveSnake() { 107 | // get the coords of the head 108 | x := snake.body[0][0] 109 | y := snake.body[0][1] 110 | 111 | switch snake.direction { 112 | case SnakeLeft: 113 | x-- 114 | break 115 | case SnakeUp: 116 | y-- 117 | break 118 | case SnakeDown: 119 | y++ 120 | break 121 | case SnakeRight: 122 | x++ 123 | break 124 | } 125 | // check the bounds 126 | if x >= WIDTHBLOCKS { 127 | x = 0 128 | } 129 | if x < 0 { 130 | x = WIDTHBLOCKS - 1 131 | } 132 | if y >= HEIGHTBLOCKS { 133 | y = 0 134 | } 135 | if y < 0 { 136 | y = HEIGHTBLOCKS - 1 137 | } 138 | 139 | if collisionWithSnake(x, y) { 140 | gameOver() 141 | } 142 | 143 | // draw head 144 | drawSnakePartial(x, y, green) 145 | 146 | if x == appleX && y == appleY { 147 | // grow our snake if we eat the apple 148 | snake.length++ 149 | // create a new apple 150 | createApple() 151 | } else { 152 | // remove tail in case we do not eat the apple 153 | drawSnakePartial(snake.body[snake.length-1][0], snake.body[snake.length-1][1], black) 154 | } 155 | for i := snake.length - 1; i > 0; i-- { 156 | snake.body[i][0] = snake.body[i-1][0] 157 | snake.body[i][1] = snake.body[i-1][1] 158 | } 159 | snake.body[0][0] = x 160 | snake.body[0][1] = y 161 | } 162 | 163 | func drawSnake() { 164 | for i := int16(0); i < 3; i++ { 165 | drawSnakePartial(snake.body[i][0], snake.body[i][1], green) 166 | } 167 | } 168 | 169 | func drawSnakePartial(x, y int16, c color.RGBA) { 170 | modY := int16(9) 171 | if y == 12 { 172 | modY = 8 173 | } 174 | // we changed the size of 10 to 9, so a black border is shown 175 | // around each segment of the snake 176 | display.FillRectangle(10*x, 10*y, 9, modY, c) 177 | } 178 | 179 | func createApple() { 180 | appleX = int16(rand.Int31n(WIDTHBLOCKS)) 181 | appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 182 | for collisionWithSnake(appleX, appleY) { 183 | appleX = int16(rand.Int31n(WIDTHBLOCKS)) 184 | appleY = int16(rand.Int31n(HEIGHTBLOCKS)) 185 | } 186 | drawSnakePartial(appleX, appleY, red) 187 | } 188 | 189 | func collisionWithSnake(x, y int16) bool { 190 | for i := int16(0); i < snake.length; i++ { 191 | if x == snake.body[i][0] && y == snake.body[i][1] { 192 | return true 193 | } 194 | } 195 | return false 196 | } 197 | 198 | func gameOver() { 199 | display.FillScreen(black) 200 | 201 | scoreStr := strconv.Itoa(int(snake.length - 3)) 202 | 203 | tinyfont.WriteLine(&display, &freesans.Regular12pt7b, 8, 50, "GAME OVER", white) 204 | tinyfont.WriteLine(&display, &freesans.Regular12pt7b, 8, 100, "Press START", white) 205 | tinyfont.WriteLine(&display, &tinyfont.TomThumb, 50, 120, "SCORE: "+scoreStr, white) 206 | 207 | time.Sleep(2 * time.Second) 208 | 209 | for { 210 | buttons.ReadInput() 211 | if buttons.Pins[shifter.BUTTON_START].Get() || buttons.Pins[shifter.BUTTON_SELECT].Get() { 212 | break 213 | } 214 | time.Sleep(100 * time.Millisecond) 215 | } 216 | 217 | // reset our game status 218 | snake = Snake{ 219 | body: [208][2]int16{ 220 | {0, 3}, 221 | {0, 2}, 222 | {0, 1}, 223 | }, 224 | length: 3, 225 | direction: SnakeRight, 226 | } 227 | display.FillScreen(black) 228 | drawSnake() 229 | createApple() 230 | } 231 | -------------------------------------------------------------------------------- /tutorial/terminal/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image/color" 5 | "machine" 6 | "time" 7 | 8 | "tinygo.org/x/drivers/st7735" 9 | "tinygo.org/x/tinyfont/proggy" 10 | "tinygo.org/x/tinyterm" 11 | ) 12 | 13 | const ( 14 | // CarriageReturn represents the character code for a new line. 15 | CarriageReturn = 10 16 | // NewLine represents the character code for a new line. 17 | NewLine = 13 18 | 19 | // bufSize represents the buffer size of the input before flushing memory 20 | bufSize = 128 21 | ) 22 | 23 | var ( 24 | // uart is the name of the serial port stream 25 | uart = machine.Serial 26 | // terminal represents the board terminal stream 27 | terminal = tinyterm.NewTerminal(&display) 28 | 29 | display = st7735.New(machine.SPI1, machine.TFT_RST, machine.TFT_DC, machine.TFT_CS, machine.TFT_LITE) 30 | 31 | // all the main colors in RGBA code. 32 | black = color.RGBA{0, 0, 0, 255} 33 | white = color.RGBA{255, 255, 255, 255} 34 | red = color.RGBA{255, 0, 0, 255} 35 | blue = color.RGBA{0, 0, 255, 255} 36 | green = color.RGBA{0, 255, 0, 255} 37 | 38 | // font is the font used to display the text 39 | font = &proggy.TinySZ8pt7b 40 | ) 41 | 42 | func main() { 43 | machine.SPI1.Configure(machine.SPIConfig{ 44 | SCK: machine.SPI1_SCK_PIN, 45 | SDO: machine.SPI1_SDO_PIN, 46 | SDI: machine.SPI1_SDI_PIN, 47 | Frequency: 8000000, 48 | }) 49 | 50 | display.Configure(st7735.Config{ 51 | Rotation: st7735.ROTATION_90, 52 | }) 53 | 54 | display.FillScreen(black) 55 | 56 | terminal.Configure(&tinyterm.Config{ 57 | Font: font, 58 | FontHeight: 10, 59 | FontOffset: 6, 60 | UseSoftwareScroll: true, 61 | }) 62 | 63 | // read the input 64 | input := make([]byte, bufSize) 65 | i := 0 66 | for { 67 | if uart.Buffered() > 0 { 68 | data, _ := uart.ReadByte() 69 | 70 | // check the type of data 71 | switch data { 72 | // new line or new character, let's print the input and flush the memory 73 | case CarriageReturn, NewLine: 74 | writeInputAndFlush(input, i) 75 | i = 0 76 | // any other character, let's echo it 77 | default: 78 | // just echo the character 79 | uart.WriteByte(data) 80 | input[i] = data 81 | 82 | _ = terminal.WriteByte(data) 83 | i++ 84 | 85 | // out of range, let's write the input and flush 86 | if i >= bufSize { 87 | writeInputAndFlush(input, i) 88 | 89 | i = 0 90 | } 91 | } 92 | } 93 | 94 | time.Sleep(50 * time.Millisecond) 95 | } 96 | } 97 | 98 | // writeInputAndFlush writes input on terminal and to serial port 99 | func writeInputAndFlush(input []byte, i int) { 100 | // write on the board 101 | terminal.Write([]byte("\r\n")) 102 | terminal.Write([]byte("You typed: ")) 103 | terminal.Write(input[:i]) 104 | 105 | // write on the serial port 106 | uart.Write([]byte("\r\n")) 107 | uart.Write([]byte("You typed: ")) 108 | uart.Write(input[:i]) 109 | 110 | // write new lines in terminal and to serial port 111 | terminal.Write([]byte("\r\n")) 112 | uart.Write([]byte("\r\n")) 113 | } 114 | --------------------------------------------------------------------------------