From f7b80ef95ae2748ca6c0552058db5a56f239b19c Mon Sep 17 00:00:00 2001 From: Thomas Richner Date: Tue, 17 Oct 2023 23:19:58 +0200 Subject: [PATCH] seesaw: added example and smoketest --- examples/seesaw/main.go | 29 +++++++++++++++++++++++++++++ seesaw/README.MD | 9 --------- seesaw/mocki2c_test.go | 15 ++++++++++++--- seesaw/registers.go | 2 -- seesaw/seesaw.go | 26 +++++++++++--------------- seesaw/seesaw_test.go | 34 +++++++++++++++------------------- smoketest.sh | 1 + 7 files changed, 68 insertions(+), 48 deletions(-) create mode 100644 examples/seesaw/main.go delete mode 100644 seesaw/README.MD diff --git a/examples/seesaw/main.go b/examples/seesaw/main.go new file mode 100644 index 0000000..14460b0 --- /dev/null +++ b/examples/seesaw/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "machine" + "strconv" + "time" + "tinygo.org/x/drivers/seesaw" +) + +const readDelay = time.Microsecond * 3000 + +// example reading soil moisture with an Adafruit capacitive soil-sensor (4026) powered by a seesaw +// https://learn.adafruit.com/adafruit-stemma-soil-sensor-i2c-capacitive-moisture-sensor/overview +func main() { + machine.I2C0.Configure(machine.I2CConfig{}) + + dev := seesaw.New(machine.I2C0) + + dev.Address = 0x36 + + var buf [2]byte + err := dev.Read(seesaw.ModuleTouchBase, seesaw.FunctionTouchChannelOffset, buf[:], readDelay) + if err != nil { + panic(err) + } + moisture := uint16(buf[0])<<8 | uint16(buf[1]) + + println("soil moisture: " + strconv.Itoa(int(moisture))) +} diff --git a/seesaw/README.MD b/seesaw/README.MD deleted file mode 100644 index 0ce39bb..0000000 --- a/seesaw/README.MD +++ /dev/null @@ -1,9 +0,0 @@ -# Seesaw Driver - -This is a basic driver to interact with Adafruit's seesaw board. - -It exposes constants for the documented modules as well as their functions. Sub-packages -may contain more refined drivers based on those. - -- [Device Overview](https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout/overview) -- [Adafruit Datasheet](https://cdn-learn.adafruit.com/downloads/pdf/adafruit-seesaw-atsamd09-breakout.pdf) diff --git a/seesaw/mocki2c_test.go b/seesaw/mocki2c_test.go index 28d897e..9c6fa8c 100644 --- a/seesaw/mocki2c_test.go +++ b/seesaw/mocki2c_test.go @@ -3,6 +3,7 @@ package seesaw import ( "encoding/hex" "fmt" + "reflect" "testing" ) @@ -17,7 +18,9 @@ type mocki2c struct { } func (m *mocki2c) Tx(addr uint16, w, r []byte) error { - assertEquals(m.t, addr, m.addr) + if addr != m.addr { + m.t.Errorf("unexpected i2c address write, want: %v , got %v", m.addr, addr) + } if len(m.handlers) == 0 { ws := hex.EncodeToString(w) rs := hex.EncodeToString(r) @@ -38,8 +41,14 @@ func newMockDev(t *testing.T, addr uint16, handlers ...I2CHandleFunc) *mocki2c { func when(expectedWrite, returningRead []byte, returningError error) I2CHandleFunc { return func(t *testing.T, w, r []byte) error { - assertEquals(t, w, expectedWrite) - assertEquals(t, len(r), len(returningRead)) + if !reflect.DeepEqual(w, expectedWrite) { + t.Errorf("unexpected write. want: %v, got: %v", expectedWrite, w) + } + + if len(r) != len(returningRead) { + t.Errorf("read buffer has wrong size. want: %v, got: %v", len(returningRead), len(r)) + } + if r != nil { copy(r, returningRead) } diff --git a/seesaw/registers.go b/seesaw/registers.go index 27e6105..3d1ebe7 100644 --- a/seesaw/registers.go +++ b/seesaw/registers.go @@ -1,5 +1,3 @@ -// Package seesaw provides a driver for the "i2c to whathever interface" called seesaw -// documentation: https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout/overview package seesaw type ModuleBaseAddress byte diff --git a/seesaw/seesaw.go b/seesaw/seesaw.go index b5ed8ce..7d93021 100644 --- a/seesaw/seesaw.go +++ b/seesaw/seesaw.go @@ -1,14 +1,21 @@ // Package seesaw provides a driver implementation to communicate with Adafruit's seesaw chip. -// There are many Adafruit boards that use a seesaw. Moisture sensors, LED keyboards, ... +// There are many Adafruit boards that use a seesaw. Soil moisture sensors, LED keyboards, etc. +// +// - Documentation: https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout/overview +// - Arduino driver: https://github.com/adafruit/Adafruit_Seesaw +// - Seesaw firmware: https://github.com/adafruit/seesaw package seesaw import ( "errors" "strconv" "time" + "tinygo.org/x/drivers" ) +// DefaultAddress is the I2C address the chips have by default. Most boards +// built on top of it come with their own respective default addresses. const DefaultAddress = 0x49 // empirically determined standardDelay, the one from the official library seems to be too short (250us) @@ -19,16 +26,6 @@ const ( seesawHwIdCodeTINY8x7 = 0x87 // HW ID code for ATtiny817 ) -type Seesaw interface { - - // Read reads a number of bytes from the device after sending the read command and waiting 'delay'. The delays depend - // on the module and function and are documented in the seesaw datasheet - Read(module ModuleBaseAddress, function FunctionAddress, buf []byte, delay time.Duration) error - - // Write writes an entire array into a given module and function - Write(module ModuleBaseAddress, function FunctionAddress, buf []byte) error -} - type Device struct { bus drivers.I2C Address uint16 @@ -54,8 +51,7 @@ func (d *Device) SoftReset() error { } func (d *Device) waitForReset() error { - - //give the device a little bit of time to reset + // give the device a little bit of time to reset time.Sleep(time.Second) var lastErr error @@ -115,8 +111,8 @@ func (d *Device) Read(module ModuleBaseAddress, function FunctionAddress, buf [] return err } - //This is needed for the client seesaw device to flush its RX buffer and process the command. - //See seesaw datasheet for timings for specific modules. + // This is needed for the client seesaw device to flush its RX buffer and process the command. + // See seesaw datasheet for timings for specific modules. time.Sleep(delay) return d.bus.Tx(d.Address, nil, buf) diff --git a/seesaw/seesaw_test.go b/seesaw/seesaw_test.go index e25a53b..51a05fa 100644 --- a/seesaw/seesaw_test.go +++ b/seesaw/seesaw_test.go @@ -1,13 +1,13 @@ package seesaw import ( - "reflect" "testing" "time" + + "github.com/frankban/quicktest" ) func TestDevice_SoftReset_success(t *testing.T) { - mocked := newMockDev(t, 0x49, when([]byte{0x00, 0x7F, 0xFF}, nil, nil), when([]byte{0x00, 0x01}, nil, nil), @@ -17,11 +17,11 @@ func TestDevice_SoftReset_success(t *testing.T) { sut := New(mocked) err := sut.SoftReset() - assertEquals(t, err, nil) + qt := quicktest.New(t) + qt.Assert(err, quicktest.IsNil) } func TestDevice_WriteRegister(t *testing.T) { - write := byte(0x1F) mocked := newMockDev(t, 0x49, when([]byte{0x01, 0x04, write}, nil, nil), @@ -30,11 +30,11 @@ func TestDevice_WriteRegister(t *testing.T) { sut := New(mocked) err := sut.WriteRegister(ModuleGpioBase, FunctionGpioBulk, write) - assertEquals(t, err, nil) + qt := quicktest.New(t) + qt.Assert(err, quicktest.IsNil) } func TestDevice_ReadRegister(t *testing.T) { - read := byte(0x23) mocked := newMockDev(t, 0x49, when([]byte{0x0F, 0x10}, nil, nil), @@ -44,12 +44,12 @@ func TestDevice_ReadRegister(t *testing.T) { sut := New(mocked) r, err := sut.ReadRegister(ModuleTouchBase, FunctionTouchChannelOffset) - assertEquals(t, err, nil) - assertEquals(t, r, read) + qt := quicktest.New(t) + qt.Assert(err, quicktest.IsNil) + qt.Assert(r, quicktest.Equals, r) } func TestDevice_Read(t *testing.T) { - expectedRead := []byte{0x01, 0x02, 0x03, 0x04, 0x05} mocked := newMockDev(t, 0x49, when([]byte{0x0F, 0x10}, nil, nil), @@ -60,12 +60,13 @@ func TestDevice_Read(t *testing.T) { var buf [5]byte err := sut.Read(ModuleTouchBase, FunctionTouchChannelOffset, buf[:], time.Nanosecond) - assertEquals(t, err, nil) - assertEquals(t, buf[:], expectedRead) + + qt := quicktest.New(t) + qt.Assert(err, quicktest.IsNil) + qt.Assert(buf[:], quicktest.DeepEquals, expectedRead) } func TestDevice_Write(t *testing.T) { - expectedWrite := []byte{0x01, 0x02, 0x03, 0x04, 0x05} mocked := newMockDev(t, 0x49, when(append([]byte{0x0E, 0x04}, expectedWrite...), nil, nil), @@ -74,11 +75,6 @@ func TestDevice_Write(t *testing.T) { sut := New(mocked) err := sut.Write(ModuleNeoPixelBase, FunctionNeopixelBuf, expectedWrite) - assertEquals(t, err, nil) -} - -func assertEquals[e any](t *testing.T, actual, expected e) { - if !reflect.DeepEqual(actual, expected) { - t.Fatalf("actual %+v != %+v not equals expected", actual, expected) - } + qt := quicktest.New(t) + qt.Assert(err, quicktest.IsNil) } diff --git a/smoketest.sh b/smoketest.sh index b29dd7a..394f743 100755 --- a/smoketest.sh +++ b/smoketest.sh @@ -61,6 +61,7 @@ tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/ma tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go +tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/seesaw tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo tinygo build -size short -o ./build/test.hex -target=pico ./examples/sgp30 tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go