Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
make BINARY_NAME=display1306-${{ matrix.suffix }}${{ matrix.ext }} build

- name: Upload binary
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: display1306-${{ matrix.suffix }}
path: display1306-${{ matrix.suffix }}${{ matrix.ext }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BINARY_NAME ?= display1306

# Build the display1306 binary
build:
go build -C v2 -o ../$(BINARY_NAME) ./cmd/display1306
go build -o ../$(BINARY_NAME) ./cmd/display1306

# Run tests
test:
Expand Down
File renamed without changes.
14 changes: 11 additions & 3 deletions display/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,22 @@ func (d *Display) Close() error {
return nil
}

func (d *Display) Clear() error {
func (d *Display) ClearLines() error {
if !d.initialized {
return fmt.Errorf("driver has not been initialized")
}
for i := range d.buffer {
d.buffer[i] = ""
}
return d.Update()
return nil
}

func (d *Display) ClearScreen() error {
img := image1bit.NewVerticalLSB(d.driver.Bounds())
if err := d.driver.Draw(d.driver.Bounds(), img, image.Point{}); err != nil {
return fmt.Errorf("failed to draw on display: %w", err)
}
return nil
}

func (d *Display) PrintLine(line uint, text string) error {
Expand Down Expand Up @@ -144,7 +152,7 @@ func (d *Display) Update() error {
}

for i, textLine := range d.buffer {
screen.Dot = fixed.P(0, d.lineHeight*(1+i) - d.font.Metrics().Descent.Round())
screen.Dot = fixed.P(0, d.lineHeight*(1+i)-d.font.Metrics().Descent.Round())
screen.DrawString(textLine)
}
if err := d.driver.Draw(d.driver.Bounds(), img, image.Point{}); err != nil {
Expand Down
12 changes: 6 additions & 6 deletions display/display_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
"testing"

"github.com/larsks/display1306/display/fakedriver"
"github.com/larsks/display1306/v2/display/fakedriver"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
)
Expand Down Expand Up @@ -318,7 +318,7 @@ func TestDisplay_Close(t *testing.T) {
}
}

func TestDisplay_Clear(t *testing.T) {
func TestDisplay_ClearLines(t *testing.T) {
mock := NewTrackedFakeSSD1306()
display, err := NewDisplay().WithBusName("/dev/i2c-0").WithDriver(mock).Build()
assertNoError(t, err)
Expand All @@ -333,7 +333,7 @@ func TestDisplay_Clear(t *testing.T) {
display.buffer[1] = "Test line 2"

// Clear the display
display.Clear() //nolint:errcheck
display.ClearLines() //nolint:errcheck

// Verify all buffer lines are empty
for i, line := range display.buffer {
Expand Down Expand Up @@ -457,7 +457,7 @@ func TestDisplay_PrintLines(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Clear buffer before each test
display.Clear() //nolint:errcheck
display.ClearLines() //nolint:errcheck

err := display.PrintLines(tt.line, tt.text)

Expand Down Expand Up @@ -565,7 +565,7 @@ func TestDisplay_MethodsFailWithoutInit(t *testing.T) {
{
name: "Clear fails without init",
operation: func() error {
return display.Clear()
return display.ClearLines()
},
errorSubstr: "driver has not been initialized",
},
Expand Down Expand Up @@ -639,7 +639,7 @@ func TestDisplay_Integration(t *testing.T) {
}

// Clear and verify
display.Clear() //nolint:errcheck
display.ClearLines() //nolint:errcheck
for i, line := range display.buffer {
if line != "" {
t.Errorf("Expected buffer[%d] to be empty after clear, got %q", i, line)
Expand Down
61 changes: 46 additions & 15 deletions display/fakedriver/fakedriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"image/png"
"log"
"net/http"
"os"
"strconv"
"sync"

"periph.io/x/devices/v3/ssd1306/image1bit"
Expand All @@ -20,26 +22,55 @@ import (
var displayTemplate embed.FS

type FakeSSD1306 struct {
bounds image.Rectangle
mutex sync.Mutex
buffer *image.RGBA
server *http.Server
port string
clients map[chan string]bool
waitMode bool
startChan chan bool
started bool
bounds image.Rectangle
mutex sync.Mutex
buffer *image.RGBA
server *http.Server
listenAddress string
port uint
clients map[chan string]bool
waitMode bool
startChan chan bool
started bool
}

func getEnvWithDefault(name, defval string) string {
val := os.Getenv(name)
if val == "" {
return defval
}
return val
}

func NewFakeSSD1306() *FakeSSD1306 {
listenAddress := getEnvWithDefault("FAKESSD1306_LISTEN_ADDRESS", "127.0.0.1")
portStr := getEnvWithDefault("FAKESSD1306_PORT", "8080")

port, err := strconv.ParseUint(portStr, 10, 32)
if err != nil {
port = 8080
log.Printf("invalid port %s: using default port %d", portStr, port)
}

return &FakeSSD1306{
bounds: image.Rect(0, 0, 128, 64),
port: "8080",
clients: make(map[chan string]bool),
startChan: make(chan bool, 1),
bounds: image.Rect(0, 0, 128, 64),
listenAddress: listenAddress,
port: uint(port),
clients: make(map[chan string]bool),
startChan: make(chan bool, 1),
}
}

func (f *FakeSSD1306) WithPort(port uint) *FakeSSD1306 {
f.port = port
return f
}

func (f *FakeSSD1306) WithListenAddress(addr string) *FakeSSD1306 {
f.listenAddress = addr
return f
}

func (d *FakeSSD1306) SetWaitMode(waitMode bool) {
d.waitMode = waitMode
}
Expand Down Expand Up @@ -76,13 +107,13 @@ func (d *FakeSSD1306) Open() error {
mux.HandleFunc("/start", d.handleStart)

d.server = &http.Server{
Addr: ":" + d.port,
Addr: fmt.Sprintf("%s:%d", d.listenAddress, d.port),
Handler: mux,
}

// Start server in a goroutine
go func() {
log.Printf("SSD1306 Display Simulator running at http://localhost:%s", d.port)
log.Printf("SSD1306 Display Simulator running at http://localhost:%d", d.port)
if err := d.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Printf("HTTP server error: %v", err)
}
Expand Down
9 changes: 3 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
module github.com/larsks/display1306
module github.com/larsks/display1306/v2

go 1.23.4

require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/spf13/pflag v1.0.7
golang.org/x/image v0.28.0
periph.io/x/conn/v3 v3.7.2
periph.io/x/devices/v3 v3.7.4
periph.io/x/host/v3 v3.8.5
)

require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/spf13/pflag v1.0.6
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
periph.io/x/conn/v3 v3.7.2 h1:qt9dE6XGP5ljbFnCKRJ9OOCoiOyBGlw7JZgoi72zZ1s=
Expand Down
Loading