seesaw: added example and smoketest

This commit is contained in:
Thomas Richner
2023-10-17 23:19:58 +02:00
committed by BCG
parent 933c9e127d
commit f7b80ef95a
7 changed files with 68 additions and 48 deletions
+29
View File
@@ -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)))
}
-9
View File
@@ -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)
+12 -3
View File
@@ -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)
}
-2
View File
@@ -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
+11 -15
View File
@@ -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)
+15 -19
View File
@@ -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)
}
+1
View File
@@ -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