Compare commits

..

2 Commits

Author SHA1 Message Date
Ayke van Laethem c3d0697dbc [DRAFT] st7789: add async SPI operations 2023-12-08 21:53:25 +01:00
Ayke van Laethem 9b5840e3cd pixel: add Split method
This method is useful to split a buffer in two parts, so that the two
parts can be used independently.
2023-12-08 21:53:25 +01:00
155 changed files with 978 additions and 11656 deletions
-2
View File
@@ -1,2 +0,0 @@
# These are supported funding model platforms
open_collective: tinygo
-218
View File
@@ -1,221 +1,3 @@
0.32.0
---
- **enhancements**
- **bmp280**
- remove alloc on read sensor data
- **ws2812**
- add 200MHz support for the Cortex-M0/rp2040
- **bugfixes**
- **ssd1306**
- remove time.Sleep from SSD1306 SPI transfer code
- **tmc2209**
- tmc2209 bug fixes (#755)
- **docs**
- **contributing**
- add driver design pointer to CONTRIBUTING.md
0.31.0
---
---
- **enhancements**
- **spi**
- update all SPI usage to use either *machine.SPI or drivers.SPI
0.30.0
---
- **new devices**
- **comboat**
- Add wifi driver comboat for Elecrow W5 rp2040 and rp2350 devices (#741)
- **max6675**
- Add MAX6675 device
- **TMC2209**
- Added TMC2209 support (#727)
- **TMC5160**
- Added TMC5160 support (#725)
- **sharpmem**
- Add sharpmem (#724)
- **enhancements**
- **net**
- move to latest golang.org/x/net v0.33.0 (#732)
- **microphone**
- update microphone driver to use latest i2s interface
- **bugfixes**
- **net**
- fix typo in DHCP error message
- **aht20**
- Fixed bug in aht20 driver
- **hub75**
- fix data buffering
0.29.0
---
- **new devices**
- **epd1in54**
- Waveshare 1.54inch B/W e-Paper display (#704)
- **touch**
- add capacitive touch sensing on normal GPIO pins
- **INA219**
- I2C INA219 driver (#705)
- **pcf8591**
- add ADC only implementation for I2C ADC/DAC (#690)
- **enhancements**
- **pixel**
- add NewImageFromBytes() function to allow creating image from existing slice
- **servo**
- Add function `SetAngleWithMicroseconds` (#695)
- **onewire**
- onewire improvements
- **ssd1306**
- Add function `SetFlip` and `GetFlip` (#702)
- **uc8151**
- add FillRectangle() and SetScroll() functions to satisfy tinyterm.Displayer interface
- **ssd1306**
- add FillRectangle() and SetScroll() functions to satisfy tinyterm.Displayer interface
- **bugfixes**
- **pixel**
- fix Monochrome setPixel
- **docs**
- **readme**
- discuss need to change variables in examples
- **sponsor**
- Add sponsor button to key repositories
0.28.0
---
- **new devices**
- **epd2in66b**
- Waveshare 2.66inch E-Paper Display Module (B) for Raspberry Pi Pico (#673)
- **mcp9808**
- Add driver for MCP9808 i2c temperature sensor (#676)
- **enhancements**
- **encoders**
- add atsamd21, atsamd51, atsame5x
- **pixel**
- add support for Monochrome types such as the SSD1306 display
- **rtl8720dn**
- implement ConnectModeAP
- **servo**
- add function SetAngle() to simplify API for most common use case
- **ssd1306**
- add DrawBitmap() function to complete Displayer interface
- add rotation functions for Displayer interface
- add Sleep() function for Displayer interface
- **uc8151**
- improvements to speed and also add flicker-free mode based on @antirez code example
- update to support all functions needed by tinygl and board package Displayer interface
- **wifinina**
- implement ConnectModeAP
- **bugfixes**
- **ft6336**
- ignore bogus touch events
- **pixel**
- fix Image[Monochrome].Set for larger images
- **uc8151**
- correct DrawBitmap() also refactor SendCommand() and SendData() for clarity
- **ws2812**
- Fix typo and move initialization of neo to init()
- **examples**
- **ws2812**
- Simplify examples/ws2812
0.27.0
---
- **core**
- prepare for CGo changes in TinyGo
- **new devices**
- **adafruit4650**
- support for Adafruit 4650 feather OLED
- **net**
- new networking support based on tinygo net package
- **pixel**
- add package for efficiently working with raw pixel buffers
- **rotary**
- Adding driver for rotary encoder support
- **seesaw**
- Adding support for Adafruit Seesaw platform
- **sgp30**
- add SGP30 air quality sensor
- **sk6812**
- added support for SK6812 to WS2812 device (#610)
- **enhancements**
- **epd2in13**
- add Sleep method like other displays
- unify rotation configuration with other displays
- use better black/white approximation
- **ili9341**
- add DrawBitmap method
- **lora/lorawan**
- LoRa WAN US915 Support
- LoRa WAN add setter functions
- refactor shared functionality for channels/regions
- **mcp2515**
- Add more line speeds to mcp2515.go (#626)
- **rtl8720dn**
- use drivers package version as the driver version
- **ssd1306**
- improvements needed for Thumby SPI display
- **st7735**
- make the display generic over RGB565 and RGB444
- **st7789**
- add DrawBitmap method
- make the display generic over RGB565 and RGB444
- **wifinina**
- add ResetIsHigh cfg switch for MKR 1010 (copied from #561)
- maintenence. Also see PR #4085 in the main TinyGo repo
- use drivers package version as the driver version
- **bugfixes**
- **adxl345**
- Use int16 for ADXL345 readings (#656)
- **at24cx**
- fixed the description of the device struct
- **rtl8720dn**
- allow connecting to open wifi access points
- fix check for bad Wifi connect
- **sh1106**
- fix I2C interface and add smoketest
- fixed the description of the device struct
- **wifinina**
- add 'unknown failure' reason code for AP connect
- fix concurrency issues with multiple sockets
- fix wifinina UDP send
- **examples**
- **ds3231**
- fix the description in the example
- **lorawan**
- add missing functions for simulated interface
- modify atcmd and basic demo to support choosing any one of the supported regions at compile time by using ldflags
- **net**
- all networking examples now using netdev and netlink.
- **build**
- **all**
- fix broken testrunner
- migrated legacy I2C
- add natiu package for tests
- **smoketest**
- add stack-size param for net tests.
- allow stack-size flag as it is needed for net examples
0.26.0
---
- **core**
-3
View File
@@ -8,9 +8,6 @@ We would like your help to make this project better, so we appreciate any contri
We'd love to get your feedback on getting started with TinyGo. Run into any difficulty, confusion, or anything else? You are not alone. We want to know about your experience, so we can help the next people. Please open a Github issue with your questions, or you can also get in touch directly with us on our Slack channel at [https://gophers.slack.com/messages/CDJD3SUP6](https://gophers.slack.com/messages/CDJD3SUP6).
### Driver design
Before porting or writing a driver from scratch please read **[Driver Design for TinyGo](https://tinygo.org/docs/guides/driver-design)**.
### One of the TinyGo drivers is not working as you expect
Please open a Github issue with your problem, and we will be happy to assist.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2025 The TinyGo Authors. All rights reserved.
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
+1 -1
View File
@@ -19,7 +19,7 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst
# Recursively find all *_test.go files from cwd & reduce to unique dir names
HAS_TESTS = $(sort $(dir $(call rwildcard,,*_test.go)))
# Exclude anything we explicitly don't want to test for whatever reason
EXCLUDE_TESTS = image waveshare-epd/epd2in66b
EXCLUDE_TESTS = image
TESTS = $(filter-out $(addsuffix /%,$(EXCLUDE_TESTS)),$(HAS_TESTS))
unit-test:
+2 -24
View File
@@ -3,7 +3,7 @@
[![PkgGoDev](https://pkg.go.dev/badge/tinygo.org/x/drivers)](https://pkg.go.dev/tinygo.org/x/drivers) [![Build](https://github.com/tinygo-org/drivers/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/drivers/actions/workflows/build.yml)
This package provides a collection of over 100 different hardware drivers for devices such as sensors, displays, wireless adaptors, and actuators, that can be used together with [TinyGo](https://tinygo.org).
This package provides a collection of 101 different hardware drivers for devices such as sensors and displays that can be used together with [TinyGo](https://tinygo.org).
For the complete list, please see:
https://tinygo.org/docs/reference/devices/
@@ -16,7 +16,7 @@ go get tinygo.org/x/drivers
## How to use
Here is an example in TinyGo that uses the BMP180 digital barometer. This example should work on any board that supports I2C:
Here is an example in TinyGo that uses the BMP180 digital barometer:
```go
package main
@@ -53,28 +53,6 @@ func main() {
}
```
## Examples Using GPIO or SPI
If compiling these examples directly you are likely to need to make minor changes to the defined variables to map the pins for the board you are using. For example, this block in main.go:
```golang
var (
spi = machine.SPI0
csPin = machine.D5
)
```
It might not be obvious, but you need to change these to match how you wired your specific board. Constants are [defined for each supported microcontroller](https://tinygo.org/docs/reference/microcontrollers/).
For example, to change the definitions for use on a Raspberry Pi Pico using typical wiring, you might need to do this:
```golang
var (
spi = machine.SPI0
csPin = machine.GP17
)
```
## Contributing
Your contributions are welcome!
+7 -7
View File
@@ -95,16 +95,16 @@ func (d *Device) Restart() {
func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
rx, ry, rz := d.ReadRawAcceleration()
x = int32(d.dataFormat.convertToIS(rx))
y = int32(d.dataFormat.convertToIS(ry))
z = int32(d.dataFormat.convertToIS(rz))
x = d.dataFormat.convertToIS(rx)
y = d.dataFormat.convertToIS(ry)
z = d.dataFormat.convertToIS(rz)
return
}
// ReadRawAcceleration reads the sensor values and returns the raw x, y and z axis
// from the adxl345.
func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
data := []byte{0, 0, 0, 0, 0, 0}
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data)
@@ -140,7 +140,7 @@ func (d *Device) SetRange(sensorRange Range) bool {
}
// convertToIS adjusts the raw values from the adxl345 with the range configuration
func (d *dataFormat) convertToIS(rawValue int16) int16 {
func (d *dataFormat) convertToIS(rawValue int32) int32 {
switch d.sensorRange {
case RANGE_2G:
return rawValue * 4 // rawValue * 2 * 1000 / 512
@@ -190,6 +190,6 @@ func (b *bwRate) toByte() (bits uint8) {
}
// readInt converts two bytes to int16
func readIntLE(msb byte, lsb byte) int16 {
return int16(uint16(msb) | uint16(lsb)<<8)
func readIntLE(msb byte, lsb byte) int32 {
return int32(uint16(msb) | uint16(lsb)<<8)
}
+2 -2
View File
@@ -29,7 +29,7 @@ func New(bus drivers.I2C) Device {
func (d *Device) Configure() {
// Check initialization state
status := d.Status()
if status&STATUS_CALIBRATED == 1 {
if status&0x08 == 1 {
// Device is initialized
return
}
@@ -69,7 +69,7 @@ func (d *Device) Read() error {
}
// If measurement complete, store values
if data[0]&STATUS_CALIBRATED != 0 && data[0]&STATUS_BUSY == 0 {
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
return nil
+2 -1
View File
@@ -5,6 +5,7 @@ package apa102 // import "tinygo.org/x/drivers/apa102"
import (
"image/color"
"machine"
"tinygo.org/x/drivers"
)
@@ -36,7 +37,7 @@ func New(b drivers.SPI) *Device {
// NewSoftwareSPI returns a new APA102 driver that will use a software based
// implementation of the SPI protocol.
func NewSoftwareSPI(sckPin, sdoPin drivers.Pin, delay uint32) *Device {
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
}
+6 -7
View File
@@ -1,8 +1,6 @@
package apa102
import (
"tinygo.org/x/drivers"
)
import "machine"
// bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
// to mode 0 and ignores trying to receive data. Just enough for the APA102.
@@ -10,14 +8,15 @@ import (
// most purposes other than the APA102 package. It might be desirable to make
// this more generic and include it in the TinyGo "machine" package instead.
type bbSPI struct {
SCK drivers.Pin
SDO drivers.Pin
SCK machine.Pin
SDO machine.Pin
Delay uint32
}
// Configure sets the SCK and SDO pins to low.
// Note that the SCK and SDO pins must already be configured as outputs.
// Configure sets up the SCK and SDO pins as outputs and sets them low
func (s *bbSPI) Configure() {
s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
s.SCK.Low()
s.SDO.Low()
if s.Delay == 0 {
+7 -4
View File
@@ -1,6 +1,7 @@
package bmi160
import (
"machine"
"time"
"tinygo.org/x/drivers"
@@ -10,7 +11,7 @@ import (
// also an I2C interface, but it is not yet supported.
type DeviceSPI struct {
// Chip select pin
CSB drivers.Pin
CSB machine.Pin
buf [7]byte
@@ -21,16 +22,18 @@ type DeviceSPI struct {
// NewSPI returns a new device driver. The pin and SPI interface are not
// touched, provide a fully configured SPI object and call Configure to start
// using this device.
func NewSPI(csb drivers.Pin, spi drivers.SPI) *DeviceSPI {
func NewSPI(csb machine.Pin, spi drivers.SPI) *DeviceSPI {
return &DeviceSPI{
CSB: csb, // chip select
Bus: spi,
}
}
// Configure configures the BMI160 for use. The CSB pin anf the SPI interface
// should be configured already. This function configures the BMI160 only.
// Configure configures the BMI160 for use. It configures the CSB pin and
// configures the BMI160, but it does not configure the SPI interface (it is
// assumed to be up and running).
func (d *DeviceSPI) Configure() error {
d.CSB.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.CSB.High()
// The datasheet recommends doing a register read from address 0x7F to get
+8 -7
View File
@@ -23,7 +23,6 @@ type Filter uint
type Device struct {
bus drivers.I2C
Address uint16
buf [6]byte
cali calibrationCoefficients
Temperature Oversampling
Pressure Oversampling
@@ -135,8 +134,8 @@ func (d *Device) PrintCali() {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *Device) ReadTemperature() (temperature int32, err error) {
data := d.buf[:3]
if err = d.readData(REG_TEMP, data); err != nil {
data, err := d.readData(REG_TEMP, 3)
if err != nil {
return
}
@@ -159,8 +158,8 @@ func (d *Device) ReadTemperature() (temperature int32, err error) {
// ReadPressure returns the pressure in milli pascals (mPa).
func (d *Device) ReadPressure() (pressure int32, err error) {
// First 3 bytes are Pressure, last 3 bytes are Temperature
data := d.buf[:6]
if err = d.readData(REG_PRES, data); err != nil {
data, err := d.readData(REG_PRES, 6)
if err != nil {
return
}
@@ -204,7 +203,7 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
}
// readData reads n number of bytes of the specified register
func (d *Device) readData(register int, data []byte) error {
func (d *Device) readData(register int, n int) ([]byte, error) {
// If not in normal mode, set the mode to FORCED mode, to prevent incorrect measurements
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
if d.Mode != MODE_NORMAL {
@@ -219,7 +218,9 @@ func (d *Device) readData(register int, data []byte) error {
}
// Read the requested register
return legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
data := make([]byte, n)
err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
return data, err
}
// convert3Bytes converts three bytes to int32
+4 -4
View File
@@ -2,20 +2,20 @@
package buzzer // import "tinygo.org/x/drivers/buzzer"
import (
"time"
"machine"
"tinygo.org/x/drivers"
"time"
)
// Device wraps a GPIO connection to a buzzer.
type Device struct {
pin drivers.Pin
pin machine.Pin
High bool
BPM float64
}
// New returns a new buzzer driver given which pin to use
func New(pin drivers.Pin) Device {
func New(pin machine.Pin) Device {
return Device{
pin: pin,
High: false,
-711
View File
@@ -1,711 +0,0 @@
// Package comboat implements WiFi driver for the Aithinker-Combo-AT WiFi
// device found on the Elecrow W5 rp2040 and rp2350 devices. Ths WiFi device
// is a RTL8720d variant. The driver interface is via AT command set over UART
// (see reference docs below).
//
// NOTE: the driver doesn't support UDP/TCP server connections in STA mode,
// currently. UDP/TCP/TLS client connections are supported in STA mode.
//
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/instruction/index.html
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/command-set/index.html
// https://aithinker-combo-guide.readthedocs.io/en/latest/docs/command-examples/index.html
package comboat // import "tinygo.org/x/drivers/comboat"
import (
"bytes"
"errors"
"fmt"
"io"
"machine"
"net"
"net/netip"
"strconv"
"sync"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/netdev"
"tinygo.org/x/drivers/netlink"
)
type Config struct {
BaudRate uint32
Uart *machine.UART
Tx machine.Pin
Rx machine.Pin
}
type socket struct {
protocol int
id string
rx chan []byte
remainder []byte
laddr netip.AddrPort // Set in Bind()
}
type device struct {
cfg *Config
uart *machine.UART
uartMu sync.Mutex
mac net.HardwareAddr
ip netip.Addr
gateway netip.Addr
buf [1500]byte
pos int
last []byte
ok chan bool
txReady chan bool
accept chan string
err chan error
sockets [8]*socket
sync.Mutex
}
func NewDevice(cfg *Config) *device {
return &device{
cfg: cfg,
ok: make(chan bool),
txReady: make(chan bool),
accept: make(chan string),
err: make(chan error),
}
}
func logDebug(msg string) {
//println("[DEBUG] " + msg)
}
func logError(msg string) {
println("[ERROR] " + msg)
}
func split(resp []byte, part int, del, on string) string {
parts := bytes.Split(resp, []byte(del))
if part >= len(parts) {
return "Split parts error getting " + on
}
return string(parts[part])
}
func (d *device) getFWVersion() string {
return split(d.last, 1, ":", "FW version")
}
func (d *device) saveMAC() {
raw := split(d.last, 1, ":", "MAC")
if len(raw) > 11 {
macStr := fmt.Sprintf("%s:%s:%s:%s:%s:%s",
raw[0:2], raw[2:4], raw[4:6],
raw[6:8], raw[8:10], raw[10:12])
d.mac, _ = net.ParseMAC(macStr)
}
}
var countryCodes = map[int]string{
1: "JP Japan",
2: "American Samoa",
3: "CA Canada",
4: "US",
5: "CN China",
6: "Hong Kong, China",
7: "Taiwan, China",
8: "MO Macau, China",
9: "IL Israel",
10: "Singapore",
11: "KR South Korea",
12: "TR Türkiye",
13: "AU Australia",
14: "ZA South Africa",
15: "BR Brazil",
}
func (d *device) getCountry() (code string) {
code = split(d.last, 1, ":", "county code")
codeNum, err := strconv.Atoi(code)
if err != nil {
return
}
if val, ok := countryCodes[codeNum]; ok {
code = val
}
return
}
func (d *device) saveIP() {
ipStr := split(d.last, 7, ",", "IP address")
gwStr := split(d.last, 8, ",", "gateway address")
d.ip, _ = netip.ParseAddr(ipStr)
d.gateway, _ = netip.ParseAddr(gwStr)
}
func (d *device) execute(cmd string, timeout int) (err error) {
logDebug("EXECUTE " + cmd)
d.uartMu.Lock()
_, err = d.uart.Write([]byte(cmd + "\r\n"))
d.uartMu.Unlock()
if err != nil {
return
}
t := time.NewTicker(time.Duration(timeout) * time.Millisecond)
defer t.Stop()
select {
case <-t.C:
return errors.New("Timed out")
case <-d.ok:
return
case err = <-d.err:
return
}
}
func (d *device) send(cmd string, timeout int) (err error) {
logDebug("EXECUTE " + cmd)
d.uartMu.Lock()
_, err = d.uart.Write([]byte(cmd + "\r\n"))
d.uartMu.Unlock()
if err != nil {
return
}
t := time.NewTicker(time.Duration(timeout) * time.Millisecond)
defer t.Stop()
select {
case <-t.C:
return errors.New("Timed out")
case <-d.txReady:
return
case err = <-d.err:
return
}
}
func (d *device) findSocket(id string) (*socket, error) {
for _, s := range d.sockets {
if s.id == id {
return s, nil
}
}
return nil, errors.New("Socket not found with id: " + id)
}
func (d *device) getSocket(sockfd int) (*socket, error) {
if sockfd < 0 || sockfd+1 > len(d.sockets) {
return nil, netdev.ErrInvalidSocketFd
}
if d.sockets[sockfd] == nil {
return nil, netdev.ErrInvalidSocketFd
}
return d.sockets[sockfd], nil
}
func (d *device) handle(event []byte) {
logDebug("GOT EVENT " + string(event))
switch {
// SocketDisconnect,<id>
case bytes.HasPrefix(event, []byte("SocketDisconnect")):
id := split(event, 1, ",", "SocketDisconnect")
s, err := d.findSocket(id)
if err == nil {
close(s.rx) // Sends io.EOF
}
// SocketSeed,<id>,<server id>
case bytes.HasPrefix(event, []byte("SocketSeed,2,1")):
//d.uart.Write([]byte("AT+SOCKET?" + "\r\n"))
}
}
func (d *device) processUART() {
if d.pos == 1 && d.buf[0] == '>' {
d.pos = 0
logDebug("GOT >")
d.txReady <- true
}
sofar := d.buf[:d.pos]
if !bytes.HasSuffix(sofar, []byte("\r\n")) {
return
}
// Strip CR/LF off end
sofar = sofar[:len(sofar)-2]
switch {
case bytes.HasPrefix(sofar, []byte("+EVENT:SocketDown")):
// +EVENT:SocketDown,<id>,<length>,<data>
parts := bytes.SplitN(sofar, []byte(","), 4)
if len(parts) != 4 {
logError("Error parsing +EVENT:SocketDown: " + string(sofar))
d.pos = 0
return
}
id := string(parts[1])
length, err := strconv.Atoi(string(parts[2]))
if err != nil {
logError("Error parsing length from: " + string(parts[2]))
d.pos = 0
return
}
if length != len(parts[3]) {
// This can happen if <data> actually contains a CR/LF.
// Return without resetting d.pos to continue reading
// in the full <data>.
return
}
s, err := d.findSocket(id)
if err != nil {
logError(err.Error())
d.pos = 0
return
}
logDebug("GOT +EVENT:SocketDown," + id + "," + string(parts[2]))
d.pos = 0
data := make([]byte, len(parts[3]))
copy(data, parts[3])
s.rx <- data
case bytes.HasPrefix(sofar, []byte("OK")):
d.pos = 0
logDebug("GOT OK")
d.ok <- true
case bytes.HasPrefix(sofar, []byte("ERROR")):
d.pos = 0
logDebug("GOT ERROR")
errStr := getErrStr(d.last)
d.err <- errors.New(errStr)
case bytes.HasPrefix(sofar, []byte("+EVENT:")):
d.pos = 0
event := sofar[len("+EVENT:"):]
d.handle(event)
default:
// Catch everything else and store in d.last
d.pos = 0
size := len(sofar)
if size > 0 {
d.last = make([]byte, size)
copy(d.last, sofar[:size])
logDebug("GOT LINE " + string(d.last))
}
}
}
func (d *device) serviceUART() {
for {
d.uartMu.Lock()
for d.uart.Buffered() > 0 {
if d.pos >= len(d.buf) {
println("Trying to write past buffer")
d.pos = 0
break
}
var err error
d.buf[d.pos], err = d.uart.ReadByte()
if err == nil {
d.pos++
d.processUART()
}
}
d.uartMu.Unlock()
time.Sleep(10 * time.Millisecond)
}
}
func (d *device) NetConnect(params *netlink.ConnectParams) error {
d.Lock()
defer d.Unlock()
d.uart = d.cfg.Uart
d.uart.Configure(machine.UARTConfig{
BaudRate: d.cfg.BaudRate,
TX: d.cfg.Tx,
RX: d.cfg.Rx,
})
go d.serviceUART()
fmt.Printf("\r\n")
fmt.Printf("TinyGo Combo-AT WiFi network device driver\r\n")
fmt.Printf("\r\n")
fmt.Printf("Driver version : %s\r\n", drivers.Version)
if len(params.Ssid) == 0 {
return netlink.ErrMissingSSID
}
// AT Test to see if device is alive
if err := d.execute("AT", 1000); err != nil {
return err
}
// Disable echo
if err := d.execute("ATE0", 1000); err != nil {
return err
}
// Get FW version
if err := d.execute("AT+GMR", 1000); err != nil {
return err
}
fmt.Printf("Combo-AT firmware version : %s\r\n", d.getFWVersion())
// Get/save MAC addresses
if err := d.execute("AT+CIPSTAMAC_DEF?", 1000); err != nil {
return err
}
d.saveMAC()
fmt.Printf("MAC address : %s\r\n", d.mac.String())
// Set country code US
if err := d.execute("AT+WCOUNTRY=4", 1000); err != nil {
return err
}
// Get country code
if err := d.execute("AT+WCOUNTRY?", 1000); err != nil {
return err
}
fmt.Printf("WiFi country code : %s\r\n", d.getCountry())
// Set Wi-Fi working mode to STA and save to flash
if err := d.execute("AT+WMODE=1,1", 1000); err != nil {
return err
}
// Connect to Wifi AP (keep trying until connected)
fmt.Printf("\r\n")
cmd := "AT+WJAP=" + params.Ssid + "," + params.Passphrase
for {
fmt.Printf("Connecting to WiFi SSID '%s'...", params.Ssid)
if err := d.execute(cmd, 20000); err != nil {
fmt.Printf("FAILED (%s)\r\n", err.Error())
continue
}
break
}
fmt.Printf("CONNECTED\r\n")
// Automatically reconnect to Wi-Fi after power on
if err := d.execute("AT+WAUTOCONN=1", 1000); err != nil {
return err
}
// Get/save IP/gateway addresses
if err := d.execute("AT+WJAP?", 1000); err != nil {
return err
}
d.saveIP()
fmt.Printf("\r\n")
fmt.Printf("DHCP-assigned IP : %s\r\n", d.ip)
fmt.Printf("DHCP-assigned gateway : %s\r\n", d.gateway)
fmt.Printf("\r\n")
// Set socket receiving mode to active
if err := d.execute("AT+SOCKETRECVCFG=1", 1000); err != nil {
return err
}
return nil
}
func (d *device) NetDisconnect() {
d.Lock()
defer d.Unlock()
// Disconnect from WiFi AP
d.execute("AT+WDISCONNECT", 1000)
}
func (d *device) NetNotify(cb func(netlink.Event)) {
fmt.Printf("\r\n%s\r\n", netlink.ErrNotSupported)
}
func (d *device) GetHardwareAddr() (net.HardwareAddr, error) {
return d.mac, nil
}
func (d *device) _getHostByName(name string) (ip netip.Addr, err error) {
if err = d.execute("AT+WDOMAIN="+name, 1000); err != nil {
return
}
ipStr := split(d.last, 1, ":", "host by name")
return netip.ParseAddr(ipStr)
}
func (d *device) GetHostByName(name string) (ip netip.Addr, err error) {
// If it's already a dotted-network address, and not a host name,
// return it
ip, err = netip.ParseAddr(name)
if err == nil {
return
}
d.Lock()
defer d.Unlock()
return d._getHostByName(name)
}
func (d *device) Addr() (netip.Addr, error) {
return d.ip, nil
}
func (d *device) Socket(domain, stype, protocol int) (int, error) {
switch domain {
case netdev.AF_INET:
default:
return -1, netdev.ErrFamilyNotSupported
}
switch {
case protocol == netdev.IPPROTO_TCP && stype == netdev.SOCK_STREAM:
case protocol == netdev.IPPROTO_TLS && stype == netdev.SOCK_STREAM:
case protocol == netdev.IPPROTO_UDP && stype == netdev.SOCK_DGRAM:
default:
return -1, netdev.ErrProtocolNotSupported
}
d.Lock()
defer d.Unlock()
// Search for empty slot in sockets array
for fd, s := range d.sockets {
if s == nil {
// Found one
d.sockets[fd] = &socket{
protocol: protocol,
rx: make(chan []byte, 10),
}
return fd, nil
}
}
return -1, netdev.ErrNoMoreSockets
}
func (d *device) Bind(sockfd int, ip netip.AddrPort) error {
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return err
}
s.laddr = ip
return nil
}
func (d *device) Connect(sockfd int, host string, ip netip.AddrPort) error {
var addr string
var cmd string
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return err
}
if host == "" {
addr = ip.Addr().String()
} else {
ip, err := d._getHostByName(host)
if err != nil {
return err
}
addr = ip.String()
}
port := strconv.Itoa(int(ip.Port()))
switch s.protocol {
case netdev.IPPROTO_UDP:
cmd = "AT+SOCKET=2," + addr + "," + port
case netdev.IPPROTO_TCP:
cmd = "AT+SOCKET=4," + addr + "," + port
case netdev.IPPROTO_TLS:
cmd = "AT+SOCKET=7," + addr + "," + port
}
if cmd == "" {
return netdev.ErrProtocolNotSupported
}
if err := d.execute(cmd, 20000); err != nil {
return err
}
s.id = split(d.last, 1, "=", "connection ID")
return nil
}
func (d *device) Listen(sockfd, backlog int) error {
// TODO Creating a TCP server socket isn't working when in STA mode,
// TODO returning error "Socket bind error".
// TODO The reference example shows a TCP server example in AP mode.
/*
var cmd string
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return err
}
port := strconv.Itoa(int(s.laddr.Port()))
switch s.protocol {
case netdev.IPPROTO_UDP:
cmd = "AT+SOCKET=1," + port
case netdev.IPPROTO_TCP:
cmd = "AT+SOCKET=3," + port
}
if cmd == "" {
return netdev.ErrProtocolNotSupported
}
if err := d.execute(cmd, 20000); err != nil {
return err
}
s.id = split(d.last, 1, "=", "connection ID")
*/
return netdev.ErrNotSupported
}
func (d *device) Accept(sockfd int) (int, netip.AddrPort, error) {
return 0, netip.AddrPort{}, netdev.ErrNotSupported
}
func (d *device) Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return 0, err
}
cmd := fmt.Sprintf("AT+SOCKETSEND=%s,%d", s.id, len(buf))
if err := d.send(cmd, 1000); err != nil {
return 0, err
}
// AT+SOCKETSEND will sub-packet send data into 1024-byte chunks,
// automatically, so send the full buffer in one shot, even if it's
// bigger than 1024 bytes.
d.uartMu.Lock()
n, err := d.uart.Write(buf)
d.uartMu.Unlock()
if err != nil {
return 0, err
}
// Expecting "OK" after good send, or "ERROR"
t := time.NewTicker(time.Duration(1000) * time.Millisecond)
defer t.Stop()
select {
case <-t.C:
return 0, errors.New("Timed out")
case <-d.ok:
return n, nil
case err = <-d.err:
return 0, err
}
}
func (d *device) Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error) {
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return 0, err
}
// 1. Use leftover data first
if len(s.remainder) > 0 {
n := copy(buf, s.remainder)
s.remainder = s.remainder[n:]
return n, nil
}
// 2. Get new data from the channel
data, ok := <-s.rx
if !ok {
// Socket closed, return EOF
return 0, io.EOF
}
// 3. Copy data, handle leftovers
n := copy(buf, data)
if n < len(data) {
s.remainder = data[n:]
}
return n, nil
}
func (d *device) Close(sockfd int) error {
d.Lock()
defer d.Unlock()
s, err := d.getSocket(sockfd)
if err != nil {
return err
}
// Delete socket only if connection was successful (s.id is set)
if s.id != "" {
cmd := fmt.Sprintf("AT+SOCKETDEL=%s", s.id)
if err = d.execute(cmd, 1000); err != nil {
return err
}
}
d.sockets[sockfd] = nil
return nil
}
func (d *device) SetSockOpt(sockfd, level, opt int, value interface{}) error {
return netdev.ErrNotSupported
}
-86
View File
@@ -1,86 +0,0 @@
package comboat
import (
"bytes"
"strconv"
)
var errStrings = map[int]string{
// System framework related error codes
0: "success",
1: "The command is not supported (the combo framework contains the command but the current platform has not transplanted or adapted to support it)",
2: "The command parameters contain unsupported operations (the current platform only supports some operations for this command)",
3: "The instruction format is incorrect (this refers to the wrong number of parameters, for example, two parameters are required, but only one parameter is entered)",
4: "Parameter error (the content of the parameter is wrong, for example, a number between 0 and 9 is required, but 10 or xyz is passed in, which is a parameter error)",
5: "Parameter length error (command length exceeds the maximum supported length)",
31: "The current command has not ended and needs to report the status asynchronously. This value is used by the state machine to determine the use of the command and no message is returned.",
32: "Unknown error (or unhandled error type)",
// Common error codes
33: "malloc error",
34: "Failed to read buf",
35: "Failed to write buf",
36: "Configuration error (configuration error loaded from memory, for example, we set port -1 for OTA upgrade, and check port error when executing AT+OTA, then configuration error will be reported)",
37: "Failed to create task",
38: "Flash read and write failure",
39: "Serial port configuration error, unsupported baud rate",
40: "Serial port configuration error, unsupported data bits",
41: "Serial port configuration error, unsupported stop bit",
42: "Serial port configuration error, unsupported parity bit",
43: "Serial port configuration error, unsupported flow control",
44: "Serial port configuration failed",
45: "Wrong username/password",
46: "Low power mode error or unsupported low power mode",
47: "Uninitialized configuration data error (including io mapping data)",
63: "General error code (without other information)",
// Wi-Fi related error codes
64: "Wi-Fi not initialized or initialization failed",
65: "Wi-Fi mode error (unable to connect to Wi-Fi in single AP mode)",
66: "Wi-Fi connection failed",
67: "Wi-Fi connection successful, error in obtaining IP (DHCP)",
68: "Failed to obtain encryption method",
69: "The specified AP was not found.",
70: "Wi-Fi scan start failed",
71: "Wi-Fi scan timeout",
72: "Failed to enable AP hotspot",
73: "Failed to obtain the Wi-Fi information of the router or the AP information that you enabled yourself",
74: "The network card (STA/AP) is not running",
75: "Wi-Fi country code error (unsupported Wi-Fi country code)",
76: "The current network configuration mode is wrong.",
95: "Wi-Fi connection unknown error",
// Socket related error codes
96: "Failed to create socket",
97: "Socket connection failed",
98: "DNS Failure",
99: "The socket status is wrong (for example, TCP is not connected yet)",
100: "Socket type error",
101: "Socket send failed",
102: "Socket receive failed",
103: "Socket monitoring thread creation failed",
104: "Socket bind error",
105: "The current connection cannot be transparently linked (wrong socket type or number)",
106: "PING test failed (all packets lost)",
107: "Wi-Fi country code error (unsupported Wi-Fi country code)",
108: "SSL Config Error",
109: "SSL verification error (usually caused by unsupported SSL encryption type or certificate error)",
127: "Unknown socket error",
}
func getErrStr(errLine []byte) (errStr string) {
errStr = "Can't parse ERROR response"
tokens := bytes.Split(errLine, []byte(":"))
if len(tokens) > 1 {
errCode, err := strconv.Atoi(string(tokens[1]))
if err == nil {
errStr = errStrings[errCode]
}
}
return
}
+2 -2
View File
@@ -19,7 +19,7 @@ type OneWireDevice interface {
Write(uint8)
Read() uint8
Select([]uint8) error
Сrc8([]uint8) uint8
Сrc8([]uint8, int) uint8
}
// Device wraps a connection to an 1-Wire devices.
@@ -69,7 +69,7 @@ func (d Device) ReadTemperatureRaw(romid []uint8) ([]uint8, error) {
for i := 0; i < 9; i++ {
spb[i] = d.owd.Read()
}
if d.owd.Сrc8(spb) != 0 {
if d.owd.Сrc8(spb, 8) != spb[8] {
return nil, errReadTemperature
}
return spb[:2:2], nil
+9 -8
View File
@@ -3,9 +3,8 @@ package easystepper // import "tinygo.org/x/drivers/easystepper"
import (
"errors"
"machine"
"time"
"tinygo.org/x/drivers"
)
// StepMode determines the coil sequence used to perform a single step
@@ -34,7 +33,7 @@ func (sm StepMode) stepCount() uint {
// DeviceConfig contains the configuration data for a single easystepper driver
type DeviceConfig struct {
// Pin1 ... Pin4 determines the pins to configure and use for the device
Pin1, Pin2, Pin3, Pin4 drivers.Pin
Pin1, Pin2, Pin3, Pin4 machine.Pin
// StepCount is the number of steps required to perform a full revolution of the stepper motor
StepCount uint
// RPM determines the speed of the stepper motor in 'Revolutions per Minute'
@@ -47,12 +46,12 @@ type DeviceConfig struct {
type DualDeviceConfig struct {
DeviceConfig
// Pin5 ... Pin8 determines the pins to configure and use for the second device
Pin5, Pin6, Pin7, Pin8 drivers.Pin
Pin5, Pin6, Pin7, Pin8 machine.Pin
}
// Device holds the pins and the delay between steps
type Device struct {
pins [4]drivers.Pin
pins [4]machine.Pin
stepDelay time.Duration
stepNumber uint8
stepMode StepMode
@@ -69,15 +68,17 @@ func New(config DeviceConfig) (*Device, error) {
return nil, errors.New("config.StepCount and config.RPM must be > 0")
}
return &Device{
pins: [4]drivers.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
pins: [4]machine.Pin{config.Pin1, config.Pin2, config.Pin3, config.Pin4},
stepDelay: time.Second * 60 / time.Duration((config.StepCount * config.RPM)),
stepMode: config.Mode,
}, nil
}
// Configure does nothing, as it assumes that the pins of the Device have already
// been configured by the user as outputs.
// Configure configures the pins of the Device
func (d *Device) Configure() {
for _, pin := range d.pins {
pin.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
}
// NewDual returns a new dual easystepper driver given 8 pins, number of steps and rpm
-34
View File
@@ -1,34 +0,0 @@
package encoders
type QuadratureDevice struct {
cfg QuadratureConfig
impl quadratureImpl
}
type QuadratureConfig struct {
Precision int
}
type quadratureImpl interface {
configure(cfg QuadratureConfig) error
readValue() int
writeValue(int)
}
func (enc *QuadratureDevice) Configure(cfg QuadratureConfig) error {
if cfg.Precision < 1 {
cfg.Precision = 4
}
enc.cfg = cfg
return enc.impl.configure(cfg)
}
// Position returns the stored int value for the encoder
func (enc *QuadratureDevice) Position() int {
return enc.impl.readValue() / enc.cfg.Precision
}
// SetPosition overwrites the currently stored value with the specified int value
func (enc *QuadratureDevice) SetPosition(v int) {
enc.impl.writeValue(v * enc.cfg.Precision)
}
-69
View File
@@ -1,69 +0,0 @@
//go:build tinygo && (rp2040 || stm32 || k210 || esp32c3 || nrf || sam || (avr && (atmega328p || atmega328pb)))
// Implementation based on:
// https://gist.github.com/aykevl/3fc1683ed77bb0a9c07559dfe857304a
// Note: build constraints in this file list targets that define machine.PinToggle.
// If this is supported for additional targets in the future, they can be added above.
package encoders
import (
"machine"
"runtime/volatile"
)
var (
states = []int8{0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0}
)
// NewQuadratureViaInterrupt returns a rotary encoder device that uses GPIO
// interrupts and a lookup table to keep track of quadrature state changes.
//
// This constructur is only available for TinyGo targets for which machine.PinToggle
// is defined as a valid interrupt type.
func NewQuadratureViaInterrupt(pinA, pinB machine.Pin) *QuadratureDevice {
return &QuadratureDevice{impl: &quadInterruptImpl{pinA: pinA, pinB: pinB, oldAB: 0b00000011}}
}
type quadInterruptImpl struct {
pinA machine.Pin
pinB machine.Pin
// precision int
oldAB int
value volatile.Register32
}
func (enc *quadInterruptImpl) configure(cfg QuadratureConfig) error {
enc.pinA.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
enc.pinA.SetInterrupt(machine.PinToggle, enc.interrupt)
enc.pinB.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
enc.pinB.SetInterrupt(machine.PinToggle, enc.interrupt)
return nil
}
func (enc *quadInterruptImpl) interrupt(pin machine.Pin) {
aHigh, bHigh := enc.pinA.Get(), enc.pinB.Get()
enc.oldAB <<= 2
if aHigh {
enc.oldAB |= 1 << 1
}
if bHigh {
enc.oldAB |= 1
}
enc.writeValue(enc.readValue() + int(states[enc.oldAB&0x0f]))
}
// readValue gets the value using volatile operations and returns it as an int
func (enc *quadInterruptImpl) readValue() int {
return int(enc.value.Get())
}
// writeValue set the value to the specified int using volatile operations
func (enc *quadInterruptImpl) writeValue(v int) {
enc.value.Set(uint32(v))
}
+4 -3
View File
@@ -122,7 +122,7 @@ func (d *Device) NetDisconnect() {
}
func (d *Device) NetNotify(cb func(netlink.Event)) {
fmt.Printf("\r\n%s\r\n", netlink.ErrNotSupported)
// Not supported
}
func (d *Device) GetHostByName(name string) (netip.Addr, error) {
@@ -218,8 +218,8 @@ func (d *Device) Listen(sockfd int, backlog int) error {
return nil
}
func (d *Device) Accept(sockfd int) (int, netip.AddrPort, error) {
return -1, netip.AddrPort{}, netdev.ErrNotSupported
func (d *Device) Accept(sockfd int, ip netip.AddrPort) (int, error) {
return -1, netdev.ErrNotSupported
}
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
@@ -473,6 +473,7 @@ func (d *Device) parseIPD(end int) error {
}
// load up the socket data
//d.data = append(d.data, d.response[e+1:end]...)
d.data = append(d.data, d.response[e+1:e+1+v]...)
return nil
}
@@ -1,28 +0,0 @@
//go:build macropad_rp2040
package main
import (
"machine"
"tinygo.org/x/drivers/encoders"
)
var (
enc = encoders.NewQuadratureViaInterrupt(machine.ROT_A, machine.ROT_B)
)
func main() {
enc.Configure(encoders.QuadratureConfig{
Precision: 4,
})
for oldValue := 0; ; {
if newValue := enc.Position(); newValue != oldValue {
println("value: ", newValue)
oldValue = newValue
}
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
console_example.RunFor(
flash.NewSPI(
machine.SPI1,
&machine.SPI1,
machine.SPI1_SDO_PIN,
machine.SPI1_SDI_PIN,
machine.SPI1_SCK_PIN,
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS I2C Example")
machine.I2C0.Configure(machine.I2CConfig{})
ublox := gps.NewI2CWithAddress(machine.I2C0, gps.UBLOX_I2C_ADDRESS)
ublox := gps.NewI2C(machine.I2C0)
parser := gps.NewParser()
var fix gps.Fix
for {
-29
View File
@@ -1,29 +0,0 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/ina219"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
dev := ina219.New(machine.I2C0)
dev.Configure()
for {
busVoltage, shuntVoltage, current, power, err := dev.Measurements()
if err != nil {
println("Error reading measurements", err)
}
println("Bus Voltage:", busVoltage, "V")
println("Shunt Voltage:", shuntVoltage/100, "mV")
println("Current:", current, "mA")
println("Power:", power, "mW")
time.Sleep(10 * time.Millisecond)
}
}
-34
View File
@@ -1,34 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/max6675"
)
// example for reading temperature from a thermocouple
func main() {
// Pins are for an Adafruit Feather nRF52840 Express
machine.D5.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.D5.High()
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 1_000_000,
SCK: machine.SPI0_SCK_PIN,
SDI: machine.SPI0_SDI_PIN,
})
thermocouple := max6675.NewDevice(machine.SPI0, machine.D5)
for {
temp, err := thermocouple.Read()
if err != nil {
println(err)
return
}
fmt.Printf("%0.02f C : %0.02f F\n", temp, (temp*9/5)+32)
time.Sleep(time.Second)
}
}
-48
View File
@@ -1,48 +0,0 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/mcp9808"
)
func main() {
//tinygo monitor
time.Sleep(time.Millisecond * 5000)
//Configure I2C (in this case, I2C0 on RPI Pico), and wire the module accordingly
machine.I2C0.Configure(machine.I2CConfig{
SCL: machine.GP1,
SDA: machine.GP0,
})
//Create sensor
sensor := mcp9808.New(machine.I2C0)
if !sensor.Connected() {
println("MCP9808 not found")
return
} else {
println("MCP9808 found")
}
time.Sleep(time.Millisecond * 1000)
//Set resolution
sensor.SetResolution(mcp9808.Maximum)
time.Sleep(time.Millisecond * 1000)
//Read temp.
temp, err := sensor.ReadTemperature()
if err != nil {
println("MCP9808 error reading temperature")
println(err.Error())
return
} else {
fmt.Printf("Temperature: %.2f \n", temp)
}
return
}
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -9,7 +9,7 @@
// examples/net/webclient (for HTTP)
// examples/net/tlsclient (for HTTPS)
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal || challenger_rp2040 || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -4,7 +4,7 @@
// Note: It may be necessary to increase the stack size when using
// paho.mqtt.golang. Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal || challenger_rp2040 || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -3,7 +3,7 @@
// It creates a UDP connection to request the current time and parse the
// response from a NTP server. The system time is set to NTP time.
//go:build ninafw || wioterminal || challenger_rp2040 || comboat_fw
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
-30
View File
@@ -1,30 +0,0 @@
//go:build ninafw || wioterminal || comboat_fw
package main
import (
"log"
"time"
"tinygo.org/x/drivers/netlink"
"tinygo.org/x/drivers/netlink/probe"
)
var (
ssid string
pass string
)
func init() {
time.Sleep(2 * time.Second)
link, _ := probe.Probe()
err := link.NetConnect(&netlink.ConnectParams{
Ssid: ssid,
Passphrase: pass,
})
if err != nil {
log.Fatal(err)
}
}
-120
View File
@@ -1,120 +0,0 @@
// This example is the classic snake network test. The snake is feed a steady
// diet of pkts and the pkts work themselves thru the snake segments and exit
// the tail. Each snake segment is a TCP socket connection to a server. The
// server echos pkts received back to the snake, and serves each segment on a
// different port. (See server/main.go for server).
//
// snake | server
// |
// head ----->---|-->--+
// seg a | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg b | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg c | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// ... | |
// +---<-|--<--+
// | |
// +-->--|-->--+
// seg n | |
// tail -------<-|--<--+
// |
// The snake segments are linked by channels and each segment is run as a go
// func. This forces segments to connect and run concurrently, which is a good
// test of the underlying driver's ability to handle concurrent connections.
//go:build ninafw || wioterminal || comboat_fw
package main
import (
_ "embed"
"fmt"
"log"
"net"
"strings"
"time"
)
//go:embed main.go
var code string
var (
server string = "10.0.0.100:8080"
)
func segment(in chan []byte, out chan []byte) {
var buf [512]byte
for {
c, err := net.Dial("tcp", server)
for ; err != nil; c, err = net.Dial("tcp", server) {
println(err.Error())
time.Sleep(5 * time.Second)
}
for {
select {
case msg := <-in:
_, err := c.Write(msg)
if err != nil {
log.Fatal(err.Error())
}
time.Sleep(100 * time.Millisecond)
n, err := c.Read(buf[:])
if err != nil {
log.Fatal(err.Error())
}
out <- buf[:n]
}
}
}
}
func feedit(head chan []byte) {
for i := 0; i < 100; i++ {
head <- []byte(fmt.Sprintf("\n---%d---\n", i))
for _, line := range strings.Split(code, "\n") {
if len(line) == 0 {
line = " "
}
head <- []byte(line)
}
}
}
var head = make(chan []byte)
var a = make(chan []byte)
var b = make(chan []byte)
var c = make(chan []byte)
var d = make(chan []byte)
var e = make(chan []byte)
var f = make(chan []byte)
var tail = make(chan []byte)
func main() {
// The snake
go segment(head, a)
go segment(a, b)
go segment(b, c)
go segment(c, d)
go segment(d, e)
go segment(e, f)
go segment(f, tail)
go feedit(head)
for {
select {
case msg := <-tail:
println(string(msg))
}
}
}
-34
View File
@@ -1,34 +0,0 @@
package main
import (
"io"
"log"
"net"
)
func main() {
// Listen for connections
l, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err.Error())
}
defer l.Close()
println("Listening on port", ":8080")
for {
// Wait for a connection
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
println("Accepted connection from", conn.RemoteAddr().String())
// Service the new connection in a goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently
go func(c net.Conn) {
// Echo all incoming data
io.Copy(c, c)
// Shut down the connection
c.Close()
}(conn)
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
//
// nc -lk 8080
//go:build ninafw || wioterminal || challenger_rp2040 || comboat_fw
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040
package main
+1 -1
View File
@@ -5,7 +5,7 @@
//
// nc -lk 8080
//go:build ninafw || wioterminal || challenger_rp2040 || comboat_fw
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal || challenger_rp2040 || pico
package main
+2 -5
View File
@@ -7,7 +7,7 @@
//
// $ nc 10.0.0.2 8080 <file >copy ; cmp file copy
//go:build ninafw || wioterminal
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
@@ -30,18 +30,16 @@ var (
var buf [1024]byte
func echo(conn net.Conn) {
println("Client", conn.RemoteAddr(), "connected")
defer conn.Close()
_, err := io.CopyBuffer(conn, conn, buf[:])
if err != nil && err != io.EOF {
log.Fatal(err.Error())
}
println("Client", conn.RemoteAddr(), "closed")
}
func main() {
time.Sleep(2 * time.Second)
time.Sleep(time.Second)
link, _ := probe.Probe()
@@ -53,7 +51,6 @@ func main() {
log.Fatal(err)
}
println("Starting TCP server listening on", port)
l, err := net.Listen("tcp", port)
if err != nil {
log.Fatal(err.Error())
+1 -1
View File
@@ -5,7 +5,7 @@
//
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -17,7 +17,7 @@
// }
// ---------------------------------------------------------------------------
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal || comboat_fw
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -6,7 +6,7 @@
// Note: It may be necessary to increase the stack size when using
// "golang.org/x/net/websocket". Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
+1 -1
View File
@@ -3,7 +3,7 @@
// Note: It may be necessary to increase the stack size when using "net/http".
// Use the -stack-size=4KB command line option.
//go:build ninafw || wioterminal
//go:build pyportal || nano_rp2040 || metro_m4_airlift || arduino_mkrwifi1010 || matrixportal_m4 || wioterminal
package main
-28
View File
@@ -1,28 +0,0 @@
// Connects to a pcf8591 ADC via I2C.
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/pcf8591"
)
var (
i2c = machine.I2C0
)
func main() {
i2c.Configure(machine.I2CConfig{})
adc := pcf8591.New(i2c)
adc.Configure()
// get "CH0" aka "machine.ADC" interface to channel 0 from ADC.
p := adc.CH0
for {
val := p.Get()
println(val)
time.Sleep(50 * time.Millisecond)
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI1
spi = &machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SDCARD_SPI
spi = &machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI0
spi = &machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
+1 -1
View File
@@ -7,7 +7,7 @@ import (
)
func init() {
spi = machine.SPI2
spi = &machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
+13 -19
View File
@@ -25,25 +25,19 @@ func main() {
return
}
println("setting to 0°")
s.SetMicroseconds(1000)
time.Sleep(3 * time.Second)
println("setting to 45°")
s.SetMicroseconds(1500)
time.Sleep(3 * time.Second)
println("setting to 90°")
s.SetMicroseconds(2000)
time.Sleep(3 * time.Second)
for {
println("setting to 0°")
s.SetAngle(0)
time.Sleep(3 * time.Second)
println("setting to 45°")
s.SetAngle(45)
time.Sleep(3 * time.Second)
println("setting to 90°")
s.SetAngle(90)
time.Sleep(3 * time.Second)
println("setting to 135°")
s.SetAngle(135)
time.Sleep(3 * time.Second)
println("setting to 180°")
s.SetAngle(180)
time.Sleep(3 * time.Second)
time.Sleep(time.Second)
}
}
-90
View File
@@ -1,90 +0,0 @@
package main
import (
"image/color"
"machine"
"math/rand/v2"
"time"
"tinygo.org/x/drivers/sharpmem"
)
var (
// example wiring using a nice!view and nice!nano:
// (view) (nano)
// MOSI --> P0.24
// SCK ---> P0.22
// GND ---> GND
// VCC ---> 3.3V
// CS ----> P0.06
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN // SCK
sdoPin = machine.SPI0_SDO_PIN // MOSI
sdiPin = machine.SPI0_SDI_PIN // (any pin)
csPin = machine.P0_06 // CS
)
func main() {
time.Sleep(time.Second)
err := spi.Configure(machine.SPIConfig{
Frequency: 2000000,
SCK: sckPin,
SDO: sdoPin,
SDI: sdiPin,
Mode: 0,
LSBFirst: true,
})
if err != nil {
println("spi.Configure() failed, error:", err.Error())
return
}
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
display := sharpmem.New(spi, csPin)
cfg := sharpmem.ConfigLS011B7DH03
display.Configure(cfg)
// clear the display before first use
err = display.Clear()
if err != nil {
println("display.Clear() failed, error:", err.Error())
return
}
// random boxes pop into and out of existence
for {
x0 := int16(rand.IntN(int(cfg.Width - 7)))
y0 := int16(rand.IntN(int(cfg.Height - 7)))
for x2 := int16(0); x2 < 16; x2++ {
x2 := x2
c := color.RGBA{R: 255, G: 255, B: 255, A: 255}
if x2 >= 8 {
// effectively erases the box after it showed up
x2 = x2 - 8
c = color.RGBA{R: 0, G: 0, B: 0, A: 255}
}
for x := int16(0); x < x2; x++ {
for y := int16(0); y < 8; y++ {
display.SetPixel(x0+x, y0+y, c)
}
}
err = display.Display()
if err != nil {
println("display.Display() failed, error:", err.Error())
continue
}
time.Sleep(33 * time.Millisecond)
}
}
}
-50
View File
@@ -1,50 +0,0 @@
// This example using the SSD1306 OLED display over SPI on the Thumby board
// A very tiny 72x40 display.
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.SPI0.Configure(machine.SPIConfig{})
display := ssd1306.NewSPI(machine.SPI0, machine.THUMBY_DC_PIN, machine.THUMBY_RESET_PIN, machine.THUMBY_CS_PIN)
display.Configure(ssd1306.Config{
Width: 72,
Height: 40,
ResetCol: ssd1306.ResetValue{28, 99},
ResetPage: ssd1306.ResetValue{0, 5},
})
display.ClearDisplay()
x := int16(36)
y := int16(20)
deltaX := int16(1)
deltaY := int16(1)
for {
pixel := display.GetPixel(x, y)
c := color.RGBA{255, 255, 255, 255}
if pixel {
c = color.RGBA{0, 0, 0, 255}
}
display.SetPixel(x, y, c)
display.Display()
x += deltaX
y += deltaY
if x == 0 || x == 71 {
deltaX = -deltaX
}
if y == 0 || y == 39 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
-35
View File
@@ -1,35 +0,0 @@
package main
import (
"machine"
"tinygo.org/x/drivers/tmc2209"
)
func main() {
uart := machine.UART0
comm := tmc2209.NewUARTComm(*uart, 0)
// Create an instance of the TMC2209 with UART communication
tmc := tmc2209.NewTMC2209(comm, 0x00) // Replace 0x00 with the appropriate address
// Set up the TMC2209 driver
err := tmc.Setup()
if err != nil {
println("Failed to set up TMC2209: ", err)
}
// Write to a register (example: setting a register value)
err = tmc.WriteRegister(0x10, 0x12345678) // Replace 0x10 with the register address and 0x12345678 with the value
if err != nil {
println("Failed to write register:", err)
}
// Read from a register (example: reading a register value)
value, err := tmc.ReadRegister(0x10)
if err != nil {
println("Failed to read register: ", err)
}
// Output the read value
println("Register value: ", value)
}
-61
View File
@@ -1,61 +0,0 @@
// Connects to SPI1 on a RP2040 (Pico)
package main
import (
"machine"
"tinygo.org/x/drivers/tmc5160"
)
func main() {
// Step 1. Setup your protocol. SPI setup shown below
spi := machine.SPI1
spi.Configure(machine.SPIConfig{
Frequency: 12000000, // Upto 12 MHZ is pretty stable. Reduce to 5 or 6 Mhz if you are experiencing issues
Mode: 3,
LSBFirst: false,
})
// Step 2. Set up all associated Pins
csPin0 := machine.GPIO13
csPin0.Configure(machine.PinConfig{Mode: machine.PinOutput})
enn0 := machine.GPIO18
enn0.Configure(machine.PinConfig{Mode: machine.PinOutput})
// csPins is a map of all chip select pins in a multi driver setup.
//Only one pin csPin0 mapped to "0"is shown in this example, but add more mappings as required
csPins := map[uint8]machine.Pin{0: csPin0}
//bind csPin to driverAdddress
driverAddress := uint8(0) // Let's assume we are working with driver at address 0x01
// Step 3. Bind the communication interface to the protocol
comm := tmc5160.NewSPIComm(spi, csPins)
// Step 4. Define your stepper like this below
//stepper := tmc5160.NewStepper(angle , gearRatio vSupply rCoil , lCoil , iPeak , rSense , mSteps, fclk )
stepper := tmc5160.NewDefaultStepper() // Default Stepper should be used only for testing.
// Step 5. Instantiate your driver
driver := tmc5160.NewDriver(
comm,
driverAddress,
enn0,
stepper)
// Setting and getting mode
rampMode := tmc5160.NewRAMPMODE(comm, driverAddress)
err := rampMode.SetMode(tmc5160.PositioningMode)
if err != nil {
return
}
mode, err := rampMode.GetMode()
if err != nil {
println("Error getting mode:", err)
} else {
println("Current Mode:", mode)
}
// Read GCONF register
GCONF := tmc5160.NewGCONF()
gconfVal, err := driver.ReadRegister(tmc5160.GCONF)
// Uppack the register to get all the bits and bytes of the register
GCONF.Unpack(gconfVal)
//E.g. MultiStepFlit is retrieved from the GCONF register
println("GCONF:MultiStepFlit:", GCONF.MultistepFilt)
}
-69
View File
@@ -1,69 +0,0 @@
// Capacitive touch sensing example.
//
// This capacitive touch sensor works by charging a normal GPIO pin, then slowly
// discharging it through a 1MΩ resistor and seeing how long it takes to go from
// high to low.
//
// Use as follows:
// - Change touchPin below as needed.
// - Connect this pin to some metal surface, like a piece of aluminimum foil.
// Make sure this surface is covered (using paper, Scotch tape, etc).
// - Also connect this same pin to ground through a 1MΩ resistor.
//
// This sensor is very sensitive to noise on the power source, so you should
// probably try to limit it by running from a battery for example. Especially
// phone chargers can produce a lot of noise.
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/touch/capacitive"
)
const touchPin = machine.GP16 // Raspberry Pi Pico
func main() {
time.Sleep(time.Second * 2)
println("start")
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
led.Low()
// Configure the array of GPIO pins used for capacitive touch sensing.
// We're using only one pin.
array := capacitive.NewArray([]machine.Pin{touchPin})
// Use a dynamic threshold, meaning the GPIO pin is automatically calibrated
// and re-calibrated to adjust for varying environments (e.g. changing
// humidity).
array.SetDynamicThreshold(100)
wasTouching := false
for i := uint32(0); ; i++ {
// Update the GPIO pin. This must be called very often.
array.Update()
touching := array.Touching(0)
// Indicate whether the pin is touched via the LED.
led.Set(touching)
// Print something when the touch state changed.
if wasTouching != touching {
wasTouching = touching
if touching {
println(" touch!")
} else {
println(" release!")
}
}
// Print the current value, as a debugging aid. It's not really meant to
// be used directly.
if i%128 == 32 {
println("touch value:", array.RawValue(0))
}
}
}
+12 -40
View File
@@ -3,9 +3,7 @@ package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/uc8151"
)
@@ -16,56 +14,30 @@ func main() {
led = machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 12 * machine.MHz,
Frequency: 12000000,
SCK: machine.EPD_SCK_PIN,
SDO: machine.EPD_SDO_PIN,
})
display = uc8151.New(machine.SPI0, machine.EPD_CS_PIN, machine.EPD_DC_PIN, machine.EPD_RESET_PIN, machine.EPD_BUSY_PIN)
display.Configure(uc8151.Config{
Rotation: drivers.Rotation270,
Speed: uc8151.TURBO,
FlickerFree: true,
Blocking: false,
Rotation: uc8151.ROTATION_270,
Speed: uc8151.MEDIUM,
Blocking: true,
})
black := color.RGBA{1, 1, 1, 255}
display.ClearDisplay()
mod := int16(1)
for {
// checkerboard
for i := int16(0); i < 11; i++ {
if mod == 1 {
mod = 0
} else {
mod = 1
}
display.ClearBuffer()
for i := int16(0); i < 37; i++ {
for j := int16(0); j < 16; j++ {
if (i+j)%2 == mod {
showRect(i*8, j*8, 8, 8, black)
}
}
}
display.Display()
time.Sleep(500 * time.Millisecond)
}
// moving line
for i := int16(16); i < 21; i++ {
display.ClearBuffer()
for j := int16(0); j < 16; j++ {
if (i+j)%2 == 0 {
showRect(i*8, j*8, 8, 8, black)
}
display.Display()
time.Sleep(250 * time.Millisecond)
display.ClearBuffer()
display.Display()
for i := int16(0); i < 37; i++ {
for j := int16(0); j < 16; j++ {
if (i+j)%2 == 0 {
showRect(i*8, j*8, 8, 8, black)
}
}
}
display.Display()
}
func showRect(x int16, y int16, w int16, h int16, c color.RGBA) {
-36
View File
@@ -1,36 +0,0 @@
package main
import (
"image/color"
"machine"
"tinygo.org/x/drivers/waveshare-epd/epd1in54"
"tinygo.org/x/tinyfont"
"tinygo.org/x/tinyfont/gophers"
)
var (
spi0 = machine.SPI0
cs = machine.D10
dc = machine.D9
rst = machine.D6
busy = machine.D5
black = color.RGBA{R: 1, G: 1, B: 1, A: 255}
)
func main() {
display := epd1in54.New(spi0, cs, dc, rst, busy)
display.LDirInit(epd1in54.Config{})
display.Clear()
display.ClearBuffer()
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 150, 0, "A B C", black, tinyfont.ROTATION_90)
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 100, 0, "D E F", black, tinyfont.ROTATION_90)
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 50, 0, "G H I", black, tinyfont.ROTATION_90)
tinyfont.WriteLineRotated(&display, &gophers.Regular58pt, 0, 0, "J K L", black, tinyfont.ROTATION_90)
display.Display()
display.Sleep()
}
-84
View File
@@ -1,84 +0,0 @@
package main
import (
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/waveshare-epd/epd2in66b"
"tinygo.org/x/tinyfont"
"tinygo.org/x/tinyfont/freemono"
)
var (
black = color.RGBA{0, 0, 0, 0xff}
white = color.RGBA{0xff, 0xff, 0xff, 0xff}
red = color.RGBA{0xff, 0, 0, 0xff}
)
func main() {
machine.Serial.Configure(machine.UARTConfig{})
time.Sleep(2 * time.Second)
machine.SPI1.Configure(machine.SPIConfig{
Frequency: epd2in66b.Baudrate,
})
println("started")
// in case you have a Pico module, you can directly use
// dev, err := epd2in66b.NewPicoModule()
display := epd2in66b.New(machine.SPI1)
cfg := epd2in66b.Config{
DataPin: machine.GP8,
ChipSelectPin: machine.GP9,
ResetPin: machine.GP12,
BusyPin: machine.GP13,
}
err := display.Configure(cfg)
if err != nil {
panic(err)
}
err = display.Reset()
if err != nil {
panic(err)
}
println("draw checkerboard")
drawCheckerBoard(&display)
println("draw 'hello'")
tinyfont.WriteLineRotated(&display, &freemono.Bold24pt7b, 40, 10, "Hello!", white, tinyfont.ROTATION_90)
tinyfont.WriteLineRotated(&display, &freemono.Bold12pt7b, 10, 10, "tinygo rocks", white, tinyfont.ROTATION_90)
err = display.Display()
if err != nil {
panic(err)
}
}
func drawCheckerBoard(display drivers.Displayer) {
s := 8
width, height := display.Size()
for x := 0; x <= int(width)-s; x += s {
for y := 0; y <= int(height)-s; y += s {
c := red
if (x/s)%2 == (y/s)%2 {
c = black
}
showRect(display, x, y, s, s, c)
}
}
}
func showRect(display drivers.Displayer, x int, y int, w int, h int, c color.RGBA) {
for i := x; i < x+w; i++ {
for j := y; j < y+h; j++ {
display.SetPixel(int16(i), int16(j), c)
}
}
}
+4 -5
View File
@@ -4,8 +4,7 @@ package main
import "machine"
func init() {
// Replace neo in the code below to match the pin
// that you are using if different.
neo = machine.D2
}
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo = machine.D2
var led = machine.LED
+5 -6
View File
@@ -4,9 +4,8 @@ package main
import "machine"
func init() {
// This is the pin assignment for the Digispark only.
// Replace neo and led in the code below to match the pin
// that you are using if different.
neo = machine.Pin(0)
}
// This is the pin assignment for the Digispark only.
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = 0
var led = machine.LED
+4 -4
View File
@@ -12,12 +12,11 @@ import (
"tinygo.org/x/drivers/ws2812"
)
var (
neo machine.Pin
leds [10]color.RGBA
)
var leds [10]color.RGBA
func main() {
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
ws := ws2812.NewWS2812(neo)
@@ -36,6 +35,7 @@ func main() {
}
ws.WriteColors(leds[:])
led.Set(rg)
time.Sleep(100 * time.Millisecond)
}
}
+5 -6
View File
@@ -1,11 +1,10 @@
//go:build !digispark && !arduino
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3 && !thingplus_rp2040
package main
import "machine"
func init() {
// Replace neo in the code below to match the pin
// that you are using if different.
neo = machine.WS2812
}
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.WS2812
var led = machine.LED
+10
View File
@@ -0,0 +1,10 @@
//go:build qtpy || m5stamp_c3
package main
import "machine"
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.WS2812
var led = machine.NoPin
+12
View File
@@ -0,0 +1,12 @@
//go:build thingplus_rp2040
package main
import "machine"
// This is the pin assignment for the internal neopixel of the
// Sparkfun thingplus rp2040.
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.GPIO8
var led = machine.LED
+7 -6
View File
@@ -5,6 +5,8 @@
package ft6336
import (
"machine"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/touch"
@@ -15,11 +17,11 @@ type Device struct {
bus drivers.I2C
buf []byte
Address uint8
intPin drivers.Pin
intPin machine.Pin
}
// New returns FT6336 device for the provided I2C bus using default address.
func New(i2c drivers.I2C, intPin drivers.Pin) *Device {
func New(i2c drivers.I2C, intPin machine.Pin) *Device {
return &Device{
bus: i2c,
buf: make([]byte, 11),
@@ -32,10 +34,10 @@ func New(i2c drivers.I2C, intPin drivers.Pin) *Device {
type Config struct {
}
// Configure the FT6336 device. Note that the interrupt pin must be configured
// separately as an input.
// Configure the FT6336 device.
func (d *Device) Configure(config Config) error {
d.write1Byte(0xA4, 0x00)
d.intPin.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
return nil
}
@@ -78,8 +80,7 @@ func (d *Device) Read() []byte {
func (d *Device) ReadTouchPoint() touch.Point {
d.Read()
z := 0xFFFFF
switch d.buf[0] {
case 0, 255:
if d.buf[0] == 0 {
z = 0
}
+11 -7
View File
@@ -5,6 +5,7 @@ package gc9a01 // import "tinygo.org/x/drivers/gc9a01"
import (
"image/color"
"machine"
"time"
"errors"
@@ -21,10 +22,10 @@ type FrameRate uint8
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.Pin
resetPin drivers.Pin
csPin drivers.Pin
blPin drivers.Pin
dcPin machine.Pin
resetPin machine.Pin
csPin machine.Pin
blPin machine.Pin
width int16
height int16
columnOffsetCfg int16
@@ -50,9 +51,12 @@ type Config struct {
Height int16
}
// New creates a new ST7789 connection. The SPI wire must already be configured, along with the
// data/command and reset pins as outputs.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.Pin) Device {
// New creates a new ST7789 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
return Device{
bus: bus,
resetPin: resetPin,
+4 -9
View File
@@ -1,25 +1,20 @@
module tinygo.org/x/drivers
go 1.22.1
toolchain go1.23.1
go 1.18
require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/frankban/quicktest v1.10.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/orsinium-labs/tinymath v1.1.0
github.com/soypat/natiu-mqtt v0.5.1
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
golang.org/x/net v0.33.0
golang.org/x/net v0.7.0
tinygo.org/x/tinyfont v0.3.0
tinygo.org/x/tinyterm v0.1.0
)
require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-cmp v0.5.2 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.1.0 // indirect
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
)
+4 -8
View File
@@ -3,9 +3,8 @@ github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/frankban/quicktest v1.10.2 h1:19ARM85nVi4xH7xPXuc5eM/udya5ieh7b/Sv+d844Tk=
github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
@@ -13,15 +12,12 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/orsinium-labs/tinymath v1.1.0 h1:KomdsyLHB7vE3f1nRAJF2dyf1m/gnM2HxfTeV1vS5UA=
github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A=
github.com/soypat/natiu-mqtt v0.5.1 h1:rwaDmlvjzD2+3MCOjMZc4QEkDkNwDzbct2TJbpz+TPc=
github.com/soypat/natiu-mqtt v0.5.1/go.mod h1:xEta+cwop9izVCW7xOx2W+ct9PRMqr0gNVkvBPnQTc4=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
+1 -7
View File
@@ -69,16 +69,10 @@ func NewUART(uart drivers.UART) Device {
}
// NewI2C creates a new I2C GPS connection.
// Uses the default i2c address (0x42) for backward compatibility reasons.
func NewI2C(bus drivers.I2C) Device {
return NewI2CWithAddress(bus, I2C_ADDRESS)
}
// NewI2CWithAddress creates a new I2C GPS connection on the provided address
func NewI2CWithAddress(bus drivers.I2C, i2cAddress uint16) Device {
return Device{
bus: bus,
address: i2cAddress,
address: I2C_ADDRESS,
buffer: make([]byte, bufferSize),
bufIdx: bufferSize,
sentence: strings.Builder{},
+1 -5
View File
@@ -4,11 +4,7 @@ package gps
// The I2C address which this device listens to.
const (
// To ensure backward compatibility
I2C_ADDRESS = UBLOX_I2C_ADDRESS
UBLOX_I2C_ADDRESS = 0x42
PA1010D_I2C_ADDRESS = 0x10
I2C_ADDRESS = 0x42
)
const (
+7 -8
View File
@@ -5,31 +5,30 @@
package hcsr04
import (
"machine"
"time"
"tinygo.org/x/drivers"
)
const TIMEOUT = 23324 // max sensing distance (4m)
// Device holds the pins
type Device struct {
trigger drivers.Pin
echo drivers.Pin
trigger machine.Pin
echo machine.Pin
}
// New returns a new ultrasonic driver given 2 pins
func New(trigger, echo drivers.Pin) Device {
func New(trigger, echo machine.Pin) Device {
return Device{
trigger: trigger,
echo: echo,
}
}
// Configure expects that the pins of the Device have already
// been configured by the user. Trigger pin should be an output
// and echo pin should be an input.
// Configure configures the pins of the Device
func (d *Device) Configure() {
d.trigger.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.echo.Configure(machine.PinConfig{Mode: machine.PinInput})
}
// ReadDistance returns the distance of the object in mm
+1 -1
View File
@@ -167,7 +167,7 @@ func (d *Device) fillMatrixBuffer(x int16, y int16, r uint8, g uint8, b uint8) {
if r > colorTresh {
d.buffer[c][offsetR] |= 1 << bitSelect
} else {
d.buffer[c][offsetR] &^= 1 << bitSelect
d.buffer[c][offsetR] = d.buffer[c][offsetR] &^ 1 << bitSelect
}
if g > colorTresh {
d.buffer[(c+d.colorThirdStep)%d.colorDepth][offsetG] |= 1 << bitSelect
+2 -2
View File
@@ -8,10 +8,10 @@ import (
)
type spiDriver struct {
bus *machine.SPI
bus machine.SPI
}
func NewSPI(bus *machine.SPI, dc, cs, rst machine.Pin) *Device {
func NewSPI(bus machine.SPI, dc, cs, rst machine.Pin) *Device {
return &Device{
dc: dc,
cs: cs,
+2 -2
View File
@@ -8,10 +8,10 @@ import (
)
type spiDriver struct {
bus *machine.SPI
bus machine.SPI
}
func NewSPI(bus *machine.SPI, dc, cs, rst machine.Pin) *Device {
func NewSPI(bus machine.SPI, dc, cs, rst machine.Pin) *Device {
return &Device{
dc: dc,
cs: cs,
-183
View File
@@ -1,183 +0,0 @@
package ina219
type Config struct {
// BusVoltageRange sets the bus voltage range.
BusVoltageRange BusVoltageRange
// PGA sets the programmable gain amplifier.
PGA PGA
// BusADC sets the bus ADC resolution.
BusADC BusADC
// ShuntADC sets the shunt ADC resolution.
ShuntADC ShuntADC
// Mode sets the operating mode.
Mode Mode
// Calibration sets the calibration value for the expected
// voltage and current values.
Calibration Calibration
// 1000 / uA per bit
CurrentDivider float32
// 1mW per bit
PowerMultiplier float32
}
// RegisterValue returns the register value of the configuration.
func (c *Config) RegisterValue() uint16 {
return c.BusVoltageRange.RegisterValue() |
c.PGA.RegisterValue() |
c.BusADC.RegisterValue() |
c.ShuntADC.RegisterValue() |
c.Mode.RegisterValue()
}
// Generate a new configuration from a register value.
func NewConfig(config int16, calibration int16) Config {
return Config{
BusVoltageRange: BusVoltageRange(config >> 13 & 0x1),
PGA: PGA(config >> 11 & 0x3),
BusADC: BusADC(config >> 7 & 0xF),
ShuntADC: ShuntADC(config >> 3 & 0xF),
Mode: Mode(config & 0x7),
Calibration: Calibration(calibration),
}
}
// Configurations from
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
var (
// Config32V2A is a configuration for a 32V 2A range.
Config32V2A = Config{
BusVoltageRange: Range32V,
PGA: PGA8,
BusADC: ADC12,
ShuntADC: SADC12,
Mode: ModeContShuntBus,
Calibration: Calibration16V400mA,
CurrentDivider: 10.0,
PowerMultiplier: 2.0,
}
// Config32V1A is a configuration for a 32V 1A range.
Config32V1A = Config{
BusVoltageRange: Range32V,
PGA: PGA8,
BusADC: ADC12,
ShuntADC: SADC12,
Mode: ModeContShuntBus,
Calibration: Calibration32V1A,
CurrentDivider: 25.0,
PowerMultiplier: 0.8,
}
// Config16V400mA is a configuration for a 16V 400mA range.
Config16V400mA = Config{
BusVoltageRange: Range16V,
PGA: PGA1,
BusADC: ADC12,
ShuntADC: SADC12,
Mode: ModeContShuntBus,
Calibration: Calibration16V400mA,
CurrentDivider: 20.0,
PowerMultiplier: 1.0,
}
)
// BusVoltageRange is the bus voltage range.
type BusVoltageRange int8
const (
Range16V BusVoltageRange = 0 // 0-16V
Range32V BusVoltageRange = 1 // 0-32V
)
func (r BusVoltageRange) RegisterValue() uint16 {
return uint16(r) << 13
}
// PGA is the programmable gain amplifier.
type PGA int8
const (
PGA1 PGA = 0 // 40mV
PGA2 PGA = 1 // 80mV
PGA4 PGA = 2 // 160mV
PGA8 PGA = 3 // 320mV
)
func (p PGA) RegisterValue() uint16 {
return uint16(p) << 11
}
// BusADC is the bus ADC resolution.
type BusADC int8
const (
ADC9 BusADC = 0 // 9-bit
ADC10 BusADC = 1 // 10-bit
ADC11 BusADC = 2 // 11-bit
ADC12 BusADC = 3 // 12-bit
)
func (b BusADC) RegisterValue() uint16 {
return uint16(b) << 7
}
// ShuntADC is the shunt ADC resolution.
type ShuntADC int8
const (
SADC9 ShuntADC = 0 // 9-bit
SADC10 ShuntADC = 1 // 10-bit
SADC11 ShuntADC = 2 // 11-bit
SADC12 ShuntADC = 3 // 12-bit
)
func (s ShuntADC) RegisterValue() uint16 {
return uint16(s) << 3
}
// Mode is the operating mode.
type Mode int8
const (
ModePowerDown Mode = 0 // power-down
ModeTrigShunt Mode = 1 // triggered shunt voltage
ModeTrigBus Mode = 2 // triggered bus voltage
ModeTrigShuntBus Mode = 3 // triggered shunt and bus voltage
ModeADCOff Mode = 4 // ADC off
ModeContShunt Mode = 5 // continuous shunt voltage
ModeContBus Mode = 6 // continuous bus voltage
ModeContShuntBus Mode = 7 // continuous shunt and bus voltage
)
// ModeTriggered is a mask for triggered modes.
const ModeTriggeredMask Mode = 0x4
// ModeTriggered returns true if the mode is a triggered mode.
func ModeTriggered(m Mode) bool {
return m != ModePowerDown && m&ModeTriggeredMask == 0
}
func (m Mode) RegisterValue() uint16 {
return uint16(m)
}
// Calibration is the calibration register for the INA219. Values from:
// https://github.com/adafruit/Adafruit_INA219/blob/master/Adafruit_INA219.cpp
type Calibration uint16
const (
Calibration32V2A Calibration = 4096
Calibration32V1A Calibration = 10240
Calibration16V400mA Calibration = 8192
)
func (c Calibration) RegisterValue() uint16 {
return uint16(c)
}
-13
View File
@@ -1,13 +0,0 @@
package ina219
type ErrOverflow struct{}
func (e ErrOverflow) Error() string { return "overflow" }
type ErrNotReady struct{}
func (e ErrNotReady) Error() string { return "not ready" }
type ErrConfigMismatch struct{}
func (e ErrConfigMismatch) Error() string { return "config mismatch" }
-202
View File
@@ -1,202 +0,0 @@
package ina219
import (
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
// An INA219 device.
type Device struct {
bus drivers.I2C
Address uint16
config Config
}
// Create a new INA219 device with the default configuration
// and the given I2C bus at the default address.
//
// Set Address after New to change the address.
//
// Call Configure after New to write the configuration to the
// device. If you don't call Configure, the device may have a
// different configuration and the power divider and current
// multiplier are probably wrong.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
config: Config32V2A,
}
}
// Set the configuration for the device. This only changes the
// configuration in memory, not on the device. Call Configure
// to write the configuration to the device.
func (d *Device) SetConfig(config Config) {
d.config = config
}
// Write the current configuration to the device.
func (d *Device) Configure() (err error) {
if err = d.WriteRegister(
RegConfig,
d.config.RegisterValue(),
); err != nil {
return
}
if err = d.WriteRegister(
RegCalibration,
d.config.Calibration.RegisterValue(),
); err != nil {
return
}
var readConfig Config
// make sure the configuration is read back correctly
if readConfig, err = d.ReadConfig(); err != nil {
return
} else if readConfig.RegisterValue() != d.config.RegisterValue() {
err = ErrConfigMismatch{}
} else if readConfig.Calibration.RegisterValue() != d.config.Calibration.RegisterValue() {
err = ErrConfigMismatch{}
}
return
}
// Trigger a conversion. This is only necessary if the device is in
// trigger mode. In continuous mode (the default), the device will
// automatically trigger conversions and this has no effect. See
// config.go.
//
// Triggering a conversion or reading the "power" register resets
// the conversion ready bit.
func (d *Device) Trigger() (err error) {
// Only trigger if the mode is one of the triggered modes.
if ModeTriggered(d.config.Mode) {
err = d.WriteRegister(RegConfig, d.config.RegisterValue())
}
return
}
// Measurements reads the bus voltage, shunt voltage, current, and power
// from the device.
func (d *Device) Measurements() (
busVoltage int16,
shuntVoltage int16,
current float32,
power float32,
err error,
) {
// Attempt to read bus voltage first, so we can check for overflow
// or conversion not ready.
if busVoltage, err = d.BusVoltage(); err != nil {
return
}
// Read the rest of the values, reading Power last, which resets
// the conversion ready bit (relevant for triggered modes).
if shuntVoltage, err = d.ShuntVoltage(); err != nil {
return
}
if current, err = d.Current(); err != nil {
return
}
if power, err = d.Power(); err != nil {
return
}
return
}
// BusVoltage reads the "bus" voltage in millivolts.
//
// It returns an error if the value is invalid due to overflow
// or if the conversion is not ready yet. In a continuous mode
// there should always be a measurement available after the
// device is ready. See above notes on Trigger.
func (d *Device) BusVoltage() (voltage int16, err error) {
val, err := d.ReadRegister(RegBusVoltage)
if err != nil {
return
}
// The overflow bit is set, so the values are invalid.
if val&(1<<0) != 0 {
err = ErrOverflow{}
return
}
// The conversion is not ready yet.
if ModeTriggered(d.config.Mode) && val&(1<<1) != 0 {
err = ErrNotReady{}
return
}
voltage = (int16(val) >> 3) * 4
return
}
// ShuntVoltage reads the "shunt" voltage in 100ths of a millivolt.
func (d *Device) ShuntVoltage() (voltage int16, err error) {
return d.ReadRegister(RegShuntVoltage)
}
// Current reads the current in milliamps.
func (d *Device) Current() (current float32, err error) {
val, err := d.ReadRegister(RegCurrent)
if err != nil {
return
}
current = float32(val) / d.config.CurrentDivider
return
}
// Power reads the power in milliwatts.
func (d *Device) Power() (power float32, err error) {
val, err := d.ReadRegister(RegPower)
if err != nil {
return
}
power = float32(val) * d.config.PowerMultiplier
return
}
// Read the configuration from the device.
func (d *Device) ReadConfig() (config Config, err error) {
var cfg, cal int16
if cfg, err = d.ReadRegister(RegConfig); err != nil {
return
}
if cal, err = d.ReadRegister(RegCalibration); err != nil {
return
}
config = NewConfig(cfg, cal)
return
}
// Read a register from the device.
func (d *Device) ReadRegister(reg uint8) (val int16, err error) {
buf := make([]byte, 2)
err = legacy.ReadRegister(d.bus, uint8(d.Address), reg, buf)
if err != nil {
return
}
val = int16(buf[0])<<8 | int16(buf[1]&0xff)
return
}
// Write to a register on the device.
func (d *Device) WriteRegister(reg uint8, val uint16) error {
buf := []byte{byte(val >> 8), byte(val & 0xff)}
return legacy.WriteRegister(d.bus, uint8(d.Address), reg, buf)
}
-232
View File
@@ -1,232 +0,0 @@
package ina219
import (
"fmt"
"testing"
qt "github.com/frankban/quicktest"
"tinygo.org/x/drivers/tester"
)
func TestDefaultAddress(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
c.Assert(dev.Address, qt.Equals, uint16(Address))
}
func TestBusVoltage(t *testing.T) {
t.Run("valid", func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegBusVoltage: (4200 << 3) / 4, // 4.2V
}
bus.AddDevice(fake)
dev := New(bus)
voltage, err := dev.BusVoltage()
c.Assert(err, qt.IsNil)
c.Assert(voltage, qt.Equals, int16(4200))
})
t.Run("overflow", func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegBusVoltage: (1 >> 0), // overflow
}
bus.AddDevice(fake)
dev := New(bus)
_, err := dev.BusVoltage()
c.Assert(err, qt.Not(qt.IsNil))
c.Assert(err, qt.ErrorMatches, ErrOverflow{}.Error())
})
t.Run("not ready", func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegBusVoltage: ((4200 << 3) / 4) | (1 << 1), // not ready
}
bus.AddDevice(fake)
dev := New(bus)
dev.config.Mode = ModeTrigBus
_, err := dev.BusVoltage()
c.Assert(err, qt.Not(qt.IsNil))
c.Assert(err, qt.ErrorMatches, ErrNotReady{}.Error())
})
}
func TestShuntVoltage(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegShuntVoltage: 0x1234,
}
bus.AddDevice(fake)
dev := New(bus)
voltage, err := dev.ShuntVoltage()
c.Assert(err, qt.IsNil)
c.Assert(voltage, qt.Equals, int16(0x1234))
}
func TestCurrent(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegCurrent: 420 * 6.9, // 420mA
}
bus.AddDevice(fake)
dev := New(bus)
dev.config.CurrentDivider = 6.9
current, err := dev.Current()
c.Assert(err, qt.IsNil)
c.Assert(current, qt.Equals, float32(420))
}
func TestPower(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegPower: 420 / 0.8, // 420mW
}
bus.AddDevice(fake)
dev := New(bus)
dev.config.PowerMultiplier = 0.8
power, err := dev.Power()
c.Assert(err, qt.IsNil)
c.Assert(power, qt.Equals, float32(420))
}
func TestReadConfig(t *testing.T) {
// use the default configurations
for _, tc := range []Config{
Config16V400mA,
Config32V2A,
Config32V1A,
} {
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
t.Run(n, func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = map[uint8]uint16{
RegConfig: tc.RegisterValue(),
RegCalibration: tc.Calibration.RegisterValue(),
}
bus.AddDevice(fake)
dev := New(bus)
config, err := dev.ReadConfig()
c.Assert(err, qt.IsNil)
c.Assert(config.BusADC, qt.Equals, tc.BusADC)
c.Assert(config.BusVoltageRange, qt.Equals, tc.BusVoltageRange)
c.Assert(config.Calibration, qt.Equals, tc.Calibration)
c.Assert(config.Mode, qt.Equals, tc.Mode)
c.Assert(config.PGA, qt.Equals, tc.PGA)
c.Assert(config.ShuntADC, qt.Equals, tc.ShuntADC)
})
}
}
func TestWriteConfig(t *testing.T) {
// use the default configurations
for _, tc := range []Config{
Config16V400mA,
Config32V2A,
Config32V1A,
} {
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
t.Run(n, func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
bus.AddDevice(fake)
fake.Registers = map[uint8]uint16{
RegConfig: 0,
RegCalibration: 0,
}
dev := New(bus)
dev.config = tc
err := dev.Configure()
c.Assert(err, qt.IsNil)
c.Assert(fake.Registers[RegConfig], qt.Equals, tc.RegisterValue())
c.Assert(fake.Registers[RegCalibration], qt.Equals, tc.Calibration.RegisterValue())
})
}
}
func TestSetConfig(t *testing.T) {
for _, tc := range []Config{
Config16V400mA,
Config32V2A,
Config32V1A,
} {
n := fmt.Sprintf("%x/%x", tc.RegisterValue(), tc.Calibration.RegisterValue())
t.Run(n, func(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
dev.SetConfig(tc)
c.Assert(dev.config, qt.Equals, tc)
})
}
}
func TestTrigger(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
bus.AddDevice(fake)
fake.Registers = map[uint8]uint16{
RegConfig: Config32V2A.RegisterValue(),
}
dev := New(bus)
dev.config = Config32V2A
dev.config.Mode = ModeTrigBus
err := dev.Trigger()
c.Assert(err, qt.IsNil)
c.Assert(fake.Registers[RegConfig], qt.Equals, dev.config.RegisterValue())
}
func TestMeasurements(t *testing.T) {
bvVal := int16(4200)
svVal := int16(1234)
iVal := float32(420)
pVal := float32(420)
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
bus.AddDevice(fake)
fake.Registers = map[uint8]uint16{
RegBusVoltage: uint16(((4200 << 3) / 4) | (1 << 1)),
RegShuntVoltage: uint16(svVal),
RegCurrent: uint16(iVal * Config16V400mA.CurrentDivider),
RegPower: uint16(pVal / Config16V400mA.PowerMultiplier),
}
dev := New(bus)
dev.config = Config16V400mA
bv, sv, i, p, err := dev.Measurements()
c.Assert(err, qt.IsNil)
c.Assert(bv, qt.Equals, bvVal)
c.Assert(sv, qt.Equals, svVal)
c.Assert(i, qt.Equals, iVal)
c.Assert(p, qt.Equals, pVal)
}
-13
View File
@@ -1,13 +0,0 @@
package ina219
// The default I2C address for this device.
const Address = 0x40
const (
RegConfig uint8 = 0x0
RegShuntVoltage uint8 = 0x1
RegBusVoltage uint8 = 0x2
RegPower uint8 = 0x3
RegCurrent uint8 = 0x4
RegCalibration uint8 = 0x5
)
+24 -35
View File
@@ -8,6 +8,7 @@ import (
"errors"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
)
type AccelRange uint8
@@ -25,7 +26,7 @@ type Device struct {
accelSampleRate AccelSampleRate
gyroRange GyroRange
gyroSampleRate GyroSampleRate
buf [7]uint8 // up to 6 bytes for read + 1 byte for the register address
buf [6]uint8
}
// Configuration for LSM6DS3TR device.
@@ -83,20 +84,30 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
d.gyroSampleRate = GYRO_SR_104
}
data := d.buf[:1]
// Configure accelerometer
err = d.writeByte(CTRL1_XL, uint8(d.accelRange)|uint8(d.accelSampleRate))
data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
if err != nil {
return
}
// Enable ODR scaling
err = d.setBits(CTRL4_C, BW_SCAL_ODR_ENABLED)
// Set ODR bit
err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
data[0] |= BW_SCAL_ODR_ENABLED
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
if err != nil {
return
}
// Configure gyroscope
err = d.writeByte(CTRL2_G, uint8(d.gyroRange)|uint8(d.gyroSampleRate))
data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
if err != nil {
return
}
@@ -107,10 +118,8 @@ func (d *Device) doConfigure(cfg Configuration) (err error) {
// Connected returns whether a LSM6DS3TR has been found.
// It does a "who am I" request and checks the response.
func (d *Device) Connected() bool {
data, err := d.readBytes(WHO_AM_I, 1)
if err != nil {
return false
}
data := d.buf[:1]
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
return data[0] == 0x6A
}
@@ -119,7 +128,8 @@ func (d *Device) Connected() bool {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
data, err := d.readBytes(OUTX_L_XL, 6)
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_XL, data)
if err != nil {
return
}
@@ -143,7 +153,8 @@ func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *Device) ReadRotation() (x, y, z int32, err error) {
data, err := d.readBytes(OUTX_L_G, 6)
data := d.buf[:6]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
if err != nil {
return
}
@@ -166,7 +177,8 @@ func (d *Device) ReadRotation() (x, y, z int32, err error) {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
func (d *Device) ReadTemperature() (t int32, err error) {
data, err := d.readBytes(OUT_TEMP_L, 2)
data := d.buf[:2]
err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
if err != nil {
return
}
@@ -175,26 +187,3 @@ func (d *Device) ReadTemperature() (t int32, err error) {
t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
return
}
func (d *Device) readBytes(reg, size uint8) ([]byte, error) {
d.buf[0] = reg
err := d.bus.Tx(d.Address, d.buf[0:1], d.buf[1:size+1])
if err != nil {
return nil, err
}
return d.buf[1 : size+1], nil
}
func (d *Device) writeByte(reg, value uint8) error {
d.buf[0] = reg
d.buf[1] = value
return d.bus.Tx(d.Address, d.buf[0:2], nil)
}
func (d *Device) setBits(reg, bits uint8) error {
data, err := d.readBytes(reg, 1)
if err != nil {
return err
}
return d.writeByte(reg, (data[0]&^bits)|bits)
}
-52
View File
@@ -1,52 +0,0 @@
// Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6675.pdf
package max6675
import (
"errors"
"tinygo.org/x/drivers"
)
// ErrThermocoupleOpen is returned when the thermocouple input is open.
// i.e. not attached or faulty
var ErrThermocoupleOpen = errors.New("thermocouple input open")
type Device struct {
bus drivers.SPI
cs drivers.Pin
}
// Create a new Device to read from a MAX6675 thermocouple.
// Pins must be configured before use. Frequency for SPI
// should be 4.3MHz maximum.
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
return &Device{
bus: bus,
cs: cs,
}
}
// Read and return the temperature in celsius
func (d *Device) Read() (float32, error) {
var (
read []byte = []byte{0, 0}
value uint16
)
d.cs.Low()
if err := d.bus.Tx([]byte{0, 0}, read); err != nil {
return 0, err
}
d.cs.High()
// datasheet: Bit D2 is normally low and goes high if the thermocouple input is open.
if read[1]&0x04 == 0x04 {
return 0, ErrThermocoupleOpen
}
// data is 12 bits, split across the two bytes
// -XXXXXXX XXXXX---
value = (uint16(read[0]) << 5) | (uint16(read[1]) >> 3)
return float32(value) * 0.25, nil
}
+8 -5
View File
@@ -3,26 +3,29 @@
package max72xx
import (
"tinygo.org/x/drivers"
"machine"
)
type Device struct {
bus drivers.SPI
cs drivers.Pin
bus machine.SPI
cs machine.Pin
}
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
// The SPI frequency must not be higher than 10MHz.
// parameter cs: the datasheet also refers to this pin as "load" pin.
func NewDevice(bus drivers.SPI, cs drivers.Pin) *Device {
func NewDevice(bus machine.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs,
}
}
// Configure expects that the pin of the Device has already been configured by the user as output.
// Configure setups the pins.
func (driver *Device) Configure() {
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
driver.cs.Configure(outPutConfig)
}
// SetScanLimit sets the scan limit. Maximum is 8.
+6 -116
View File
@@ -8,6 +8,7 @@ package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
import (
"errors"
"fmt"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -16,7 +17,7 @@ import (
// Device wraps MCP2515 SPI CAN Module.
type Device struct {
spi SPI
cs drivers.Pin
cs machine.Pin
msg *CANMsg
mcpMode byte
}
@@ -35,7 +36,7 @@ const (
)
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI, csPin drivers.Pin) *Device {
func New(b drivers.SPI, csPin machine.Pin) *Device {
d := &Device{
spi: SPI{
bus: b,
@@ -49,9 +50,9 @@ func New(b drivers.SPI, csPin drivers.Pin) *Device {
return d
}
// Configure sets up the device for communication. It expects the SPI interface to be already
// configured, and the CS configured as output.
// Configure sets up the device for communication.
func (d *Device) Configure() {
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
const beginTimeoutValue int = 10
@@ -235,83 +236,16 @@ func (d *Device) getMode() (byte, error) {
}
func (d *Device) configRate(speed, clock byte) error {
// TODO: add another baudrate
var cfg1, cfg2, cfg3 byte
set := true
switch clock {
case Clock16MHz:
switch speed {
case CAN5kBps:
cfg1 = mcp16mHz5kBpsCfg1
cfg2 = mcp16mHz5kBpsCfg2
cfg3 = mcp16mHz5kBpsCfg3
case CAN10kBps:
cfg1 = mcp16mHz10kBpsCfg1
cfg2 = mcp16mHz10kBpsCfg2
cfg3 = mcp16mHz10kBpsCfg3
case CAN20kBps:
cfg1 = mcp16mHz20kBpsCfg1
cfg2 = mcp16mHz20kBpsCfg2
cfg3 = mcp16mHz20kBpsCfg3
case CAN25kBps:
cfg1 = mcp16mHz25kBpsCfg1
cfg2 = mcp16mHz25kBpsCfg2
cfg3 = mcp16mHz25kBpsCfg3
case CAN31k25Bps:
cfg1 = mcp16mHz31k25BpsCfg1
cfg2 = mcp16mHz31k25BpsCfg2
cfg3 = mcp16mHz31k25BpsCfg3
case CAN33kBps:
cfg1 = mcp16mHz33kBpsCfg1
cfg2 = mcp16mHz33kBpsCfg2
cfg3 = mcp16mHz33kBpsCfg3
case CAN40kBps:
cfg1 = mcp16mHz40kBpsCfg1
cfg2 = mcp16mHz40kBpsCfg2
cfg3 = mcp16mHz40kBpsCfg3
case CAN47kBps:
cfg1 = mcp16mHz47kBpsCfg1
cfg2 = mcp16mHz47kBpsCfg2
cfg3 = mcp16mHz47kBpsCfg3
case CAN50kBps:
cfg1 = mcp16mHz50kBpsCfg1
cfg2 = mcp16mHz50kBpsCfg2
cfg3 = mcp16mHz50kBpsCfg3
case CAN80kBps:
cfg1 = mcp16mHz80kBpsCfg1
cfg2 = mcp16mHz80kBpsCfg2
cfg3 = mcp16mHz80kBpsCfg3
case CAN83k3Bps:
cfg1 = mcp16mHz83k3BpsCfg1
cfg2 = mcp16mHz83k3BpsCfg2
cfg3 = mcp16mHz83k3BpsCfg3
case CAN95kBps:
cfg1 = mcp16mHz95kBpsCfg1
cfg2 = mcp16mHz95kBpsCfg2
cfg3 = mcp16mHz95kBpsCfg3
case CAN100kBps:
cfg1 = mcp16mHz100kBpsCfg1
cfg2 = mcp16mHz100kBpsCfg2
cfg3 = mcp16mHz100kBpsCfg3
case CAN125kBps:
cfg1 = mcp16mHz125kBpsCfg1
cfg2 = mcp16mHz125kBpsCfg2
cfg3 = mcp16mHz125kBpsCfg3
case CAN200kBps:
cfg1 = mcp16mHz200kBpsCfg1
cfg2 = mcp16mHz200kBpsCfg2
cfg3 = mcp16mHz200kBpsCfg3
case CAN250kBps:
cfg1 = mcp16mHz250kBpsCfg1
cfg2 = mcp16mHz250kBpsCfg2
cfg3 = mcp16mHz250kBpsCfg3
case CAN500kBps:
cfg1 = mcp16mHz500kBpsCfg1
cfg2 = mcp16mHz500kBpsCfg2
cfg3 = mcp16mHz500kBpsCfg3
case CAN666kBps:
cfg1 = mcp16mHz666kBpsCfg1
cfg2 = mcp16mHz666kBpsCfg2
cfg3 = mcp16mHz666kBpsCfg3
case CAN1000kBps:
cfg1 = mcp16mHz1000kBpsCfg1
cfg2 = mcp16mHz1000kBpsCfg2
@@ -321,50 +255,6 @@ func (d *Device) configRate(speed, clock byte) error {
}
case Clock8MHz:
switch speed {
case CAN5kBps:
cfg1 = mcp8mHz5kBpsCfg1
cfg2 = mcp8mHz5kBpsCfg2
cfg3 = mcp8mHz5kBpsCfg3
case CAN10kBps:
cfg1 = mcp8mHz10kBpsCfg1
cfg2 = mcp8mHz10kBpsCfg2
cfg3 = mcp8mHz10kBpsCfg3
case CAN20kBps:
cfg1 = mcp8mHz20kBpsCfg1
cfg2 = mcp8mHz20kBpsCfg2
cfg3 = mcp8mHz20kBpsCfg3
case CAN31k25Bps:
cfg1 = mcp8mHz31k25BpsCfg1
cfg2 = mcp8mHz31k25BpsCfg2
cfg3 = mcp8mHz31k25BpsCfg3
case CAN40kBps:
cfg1 = mcp8mHz40kBpsCfg1
cfg2 = mcp8mHz40kBpsCfg2
cfg3 = mcp8mHz40kBpsCfg3
case CAN50kBps:
cfg1 = mcp8mHz50kBpsCfg1
cfg2 = mcp8mHz50kBpsCfg2
cfg3 = mcp8mHz50kBpsCfg3
case CAN80kBps:
cfg1 = mcp8mHz80kBpsCfg1
cfg2 = mcp8mHz80kBpsCfg2
cfg3 = mcp8mHz80kBpsCfg3
case CAN100kBps:
cfg1 = mcp8mHz100kBpsCfg1
cfg2 = mcp8mHz100kBpsCfg2
cfg3 = mcp8mHz100kBpsCfg3
case CAN125kBps:
cfg1 = mcp8mHz125kBpsCfg1
cfg2 = mcp8mHz125kBpsCfg2
cfg3 = mcp8mHz125kBpsCfg3
case CAN200kBps:
cfg1 = mcp8mHz200kBpsCfg1
cfg2 = mcp8mHz200kBpsCfg2
cfg3 = mcp8mHz200kBpsCfg3
case CAN250kBps:
cfg1 = mcp8mHz250kBpsCfg1
cfg2 = mcp8mHz250kBpsCfg2
cfg3 = mcp8mHz250kBpsCfg3
case CAN500kBps:
cfg1 = mcp8mHz500kBpsCfg1
cfg2 = mcp8mHz500kBpsCfg2
-98
View File
@@ -1,98 +0,0 @@
// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor
//
// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf
// Module: https://www.adafruit.com/product/1782
// Only implemented: temperature reading, resolution read & set
package mcp9808
import (
"encoding/binary"
"errors"
"tinygo.org/x/drivers"
)
type Device struct {
bus drivers.I2C
Address uint16
}
func New(bus drivers.I2C) Device {
return Device{bus, MCP9808_I2CADDR_DEFAULT}
}
func (d *Device) Connected() bool {
data := make([]byte, 2)
d.Read(MCP9808_REG_DEVICE_ID, &data)
return binary.BigEndian.Uint16(data) == MCP9808_DEVICE_ID
}
func (d *Device) ReadTemperature() (float64, error) {
data := make([]byte, 2)
var temp float64
if err := d.Read(MCP9808_REG_AMBIENT_TEMP, &data); err != nil {
return 0, err
}
data[0] = data[0] & 0x1F
if data[0]&0x10 == 0x10 {
data[0] = data[0] & 0x0F
temp = float64(data[0])*16 + float64(data[1])/16.0 - 256
}
temp = float64(data[0])*16 + float64(data[1])/16.0
return temp, nil
}
func (d *Device) ReadResolution() (resolution, error) {
data := make([]byte, 2)
err := d.Read(MCP9808_REG_RESOLUTION, &data)
if err != nil {
return 0, err
}
switch data[0] {
case 0:
return Low, nil
case 1:
return Medium, nil
case 2:
return High, nil
case 3:
return Maximum, nil
default:
return 0, errors.New("unknown resolution")
}
}
func (d *Device) SetResolution(r resolution) error {
switch r {
case Low:
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x00}); err != nil {
return err
}
case Medium:
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x01}); err != nil {
return err
}
case High:
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x02}); err != nil {
return err
}
case Maximum:
if err := d.Write(MCP9808_REG_RESOLUTION, []byte{0x03}); err != nil {
return err
}
default:
return nil
}
return nil
}
func (d *Device) Write(register byte, data []byte) error {
buf := append([]byte{register}, data...)
return d.bus.Tx(d.Address, buf, nil)
}
func (d *Device) Read(register byte, data *[]byte) error {
return d.bus.Tx(d.Address, []byte{register}, *data)
}
-53
View File
@@ -1,53 +0,0 @@
// Package mcp9808 implements a driver for the MCP9808 High Accuracy I2C Temperature Sensor
//
// Datasheet: https://cdn-shop.adafruit.com/datasheets/MCP9808.pdf
// Module: https://www.adafruit.com/product/1782
package mcp9808
// Constants/addresses used for I2C.
const (
MCP9808_DEVICE_ID = 0x0400
MCP9808_MANUF_ID = 0x0054
MCP9808_I2CADDR_DEFAULT = 0x18 //default I2C address
MCP9808_REG_CONFIG = 0x01 //MCP9808 config register
MCP9808_REG_CONFIG_SHUTDOWN = 0x0100 //shutdown config
MCP9808_REG_CONFIG_CRITLOCKED = 0x0080 //critical trip lock
MCP9808_REG_CONFIG_WINLOCKED = 0x0040 //alarm window lock
MCP9808_REG_CONFIG_INTCLR = 0x0020 //interrupt clear
MCP9808_REG_CONFIG_ALERTSTAT = 0x0010 //alert output status
MCP9808_REG_CONFIG_ALERTCTRL = 0x0008 //alert output control
MCP9808_REG_CONFIG_ALERTSEL = 0x0004 //alert output select
MCP9808_REG_CONFIG_ALERTPOL = 0x0002 //alert output polarity
MCP9808_REG_CONFIG_ALERTMODE = 0x0001 //alert output mode
MCP9808_REG_UPPER_TEMP = 0x02 //upper alert boundary
MCP9808_REG_LOWER_TEMP = 0x03 //lower alert boundery
MCP9808_REG_CRIT_TEMP = 0x04 //critical temperature
MCP9808_REG_AMBIENT_TEMP = 0x05 //ambient temperature
MCP9808_REG_MANUF_ID = 0x06 //manufacturer ID
MCP9808_REG_DEVICE_ID = 0x07 //device ID
MCP9808_REG_RESOLUTION = 0x08 //resolution
)
/*
======= ============ ==============
value resolution reading Time
======= ============ ==============
0 0.5°C 30 ms
1 0.25°C 65 ms
2 0.125°C 130 ms
3 0.0625°C 250 ms
======= ============ ==============
*/
type resolution uint8
const (
Low resolution = iota
Medium
High
Maximum
)
+2 -2
View File
@@ -64,7 +64,7 @@ func (d *Device) Read(r []int32) (int, error) {
count := len(r)
// get the next group of samples
machine.I2S0.ReadStereo(d.buf)
machine.I2S0.Read(d.buf)
if len(r) > len(d.buf) {
count = len(d.buf)
@@ -83,7 +83,7 @@ func (d *Device) ReadWithFilter(r []int32) (int, error) {
for i := 0; i < len(r); i++ {
// get the next group of samples
machine.I2S0.ReadStereo(d.buf)
machine.I2S0.Read(d.buf)
// filter
sum = applySincFilter(d.buf)
+2 -4
View File
@@ -35,12 +35,10 @@ var (
var (
ErrFamilyNotSupported = errors.New("Address family not supported")
ErrProtocolNotSupported = errors.New("Socket protocol/type not supported")
ErrStartingDHCPClient = errors.New("Error starting DHCP client")
ErrStartingDHCPServer = errors.New("Error starting DHCP server")
ErrStartingDHCPClient = errors.New("Error starting DHPC client")
ErrNoMoreSockets = errors.New("No more sockets")
ErrClosingSocket = errors.New("Error closing socket")
ErrNotSupported = errors.New("Not supported")
ErrInvalidSocketFd = errors.New("Invalid socket fd")
)
// Duplicate of non-exported net.errTimeout
@@ -84,7 +82,7 @@ type Netdever interface {
Bind(sockfd int, ip netip.AddrPort) error
Connect(sockfd int, host string, ip netip.AddrPort) error
Listen(sockfd int, backlog int) error
Accept(sockfd int) (int, netip.AddrPort, error)
Accept(sockfd int, ip netip.AddrPort) (int, error)
Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
Close(sockfd int) error
-1
View File
@@ -13,7 +13,6 @@ var (
ErrConnectFailed = errors.New("Connect failed")
ErrConnectTimeout = errors.New("Connect timed out")
ErrMissingSSID = errors.New("Missing WiFi SSID")
ErrShortPassphrase = errors.New("Invalid Wifi Passphrase < 8 chars")
ErrAuthFailure = errors.New("Wifi authentication failure")
ErrAuthTypeNoGood = errors.New("Wifi authorization type not supported")
ErrConnectModeNoGood = errors.New("Connect mode not supported")
-26
View File
@@ -1,26 +0,0 @@
//go:build comboat_fw
package probe
import (
"machine"
"tinygo.org/x/drivers/comboat"
"tinygo.org/x/drivers/netdev"
"tinygo.org/x/drivers/netlink"
)
func Probe() (netlink.Netlinker, netdev.Netdever) {
cfg := comboat.Config{
BaudRate: 115200,
Uart: machine.UART1,
Tx: machine.UART1_TX_PIN,
Rx: machine.UART1_RX_PIN,
}
combo := comboat.NewDevice(&cfg)
netdev.UseNetdev(combo)
return combo, combo
}
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build ninafw && !arduino_mkrwifi1010
//go:build pyportal || arduino_nano33 || nano_rp2040 || metro_m4_airlift || matrixportal_m4
package probe
+9 -17
View File
@@ -27,9 +27,8 @@ type Config struct{}
// Errors list
var (
errNoPresence = errors.New("Error: OneWire. No devices on the bus.")
errTooManyDevices = errors.New("Error: OneWire. Too many devices on the bus.")
errReadAddress = errors.New("Error: OneWire. Read address error: CRC mismatch.")
errNoPresence = errors.New("Error: OneWire. No devices on the bus.")
errReadAddress = errors.New("Error: OneWire. Read address error: CRC mismatch.")
)
// New creates a new GPIO 1-Wire connection.
@@ -47,7 +46,7 @@ func (d *Device) Configure(config Config) {}
func (d Device) Reset() error {
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
time.Sleep(480 * time.Microsecond)
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
time.Sleep(70 * time.Microsecond)
precence := d.p.Get()
time.Sleep(410 * time.Microsecond)
@@ -62,11 +61,11 @@ func (d Device) WriteBit(data uint8) {
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
if data&1 == 1 { // Send '1'
time.Sleep(5 * time.Microsecond)
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
time.Sleep(60 * time.Microsecond)
} else { // Send '0'
time.Sleep(60 * time.Microsecond)
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
time.Sleep(5 * time.Microsecond)
}
}
@@ -83,7 +82,7 @@ func (d Device) Write(data uint8) {
func (d Device) ReadBit() (data uint8) {
d.p.Configure(machine.PinConfig{Mode: machine.PinOutput})
time.Sleep(3 * time.Microsecond)
d.p.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
d.p.Configure(machine.PinConfig{Mode: machine.PinInput})
time.Sleep(8 * time.Microsecond)
if d.p.Get() {
data = 1
@@ -112,7 +111,7 @@ func (d Device) ReadAddress() ([]uint8, error) {
for i := 0; i < 8; i++ {
romid[i] = d.Read()
}
if d.Сrc8(romid) != 0 {
if d.Сrc8(romid, 7) != romid[7] {
return nil, errReadAddress
}
return romid, nil
@@ -188,22 +187,15 @@ func (d Device) Search(cmd uint8) ([][]uint8, error) {
}
d.WriteBit(bit)
}
if d.Сrc8(lastAddress) != 0 {
continue
}
lastFork = lastZero
copy(romIDs[romIndex], lastAddress)
romIndex++
if romIndex >= 32 {
return romIDs, errTooManyDevices
}
}
return romIDs[:romIndex:romIndex], nil
}
// Crc8 compute a Dallas Semiconductor 8 bit CRC.
func (_ Device) Сrc8(buffer []uint8) (crc uint8) {
func (d Device) Сrc8(buffer []uint8, size int) (crc uint8) {
// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0
// Tiny 2x16 entry CRC table created by Arjen Lentz
// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table
@@ -213,7 +205,7 @@ func (_ Device) Сrc8(buffer []uint8) (crc uint8) {
0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8,
0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74,
}
for i := 0; i < len(buffer); i++ {
for i := 0; i < size; i++ {
crc = buffer[i] ^ crc // just re-using crc as intermediate
crc = crc8_table[crc&0x0f] ^ crc8_table[16+((crc>>4)&0x0f)]
}
+1 -2
View File
@@ -14,8 +14,7 @@ import (
)
type P1AM struct {
bus *machine.SPI
bus machine.SPI
slaveSelectPin, slaveAckPin, baseEnablePin machine.Pin
// SkipAutoConfig will skip loading a default configuration into each module.
+6 -5
View File
@@ -6,6 +6,7 @@ package pcd8544 // import "tinygo.org/x/drivers/pcd8544"
import (
"errors"
"image/color"
"machine"
"time"
"tinygo.org/x/drivers"
@@ -14,9 +15,9 @@ import (
// Device wraps an SPI connection.
type Device struct {
bus drivers.SPI
dcPin drivers.Pin
rstPin drivers.Pin
scePin drivers.Pin
dcPin machine.Pin
rstPin machine.Pin
scePin machine.Pin
buffer []byte
width int16
height int16
@@ -28,8 +29,8 @@ type Config struct {
Height int16
}
// New creates a new PCD8544 connection. The SPI bus and pins must already be configured.
func New(bus drivers.SPI, dcPin, rstPin, scePin drivers.Pin) *Device {
// New creates a new PCD8544 connection. The SPI bus must already be configured.
func New(bus drivers.SPI, dcPin, rstPin, scePin machine.Pin) *Device {
return &Device{
bus: bus,
dcPin: dcPin,
-84
View File
@@ -1,84 +0,0 @@
// Package pcf8591 implements a driver for the PCF8591 Analog to Digital/Digital to Analog Converter.
//
// Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF8591.pdf
package pcf8591 // import "tinygo.org/x/drivers/pcf8591"
import (
"machine"
"errors"
"tinygo.org/x/drivers"
)
// Device wraps PCF8591 ADC functions.
type Device struct {
bus drivers.I2C
Address uint16
CH0 ADCPin
CH1 ADCPin
CH2 ADCPin
CH3 ADCPin
}
// ADCPin is the implementation of the ADConverter interface.
type ADCPin struct {
machine.Pin
d *Device
}
// New returns a new PCF8591 driver. Pass in a fully configured I2C bus.
func New(b drivers.I2C) *Device {
d := &Device{
bus: b,
Address: defaultAddress,
}
// setup all channels
d.CH0 = d.GetADC(0)
d.CH1 = d.GetADC(1)
d.CH2 = d.GetADC(2)
d.CH3 = d.GetADC(3)
return d
}
// Configure here just for interface compatibility.
func (d *Device) Configure() {
}
// Read analog data from channel
func (d *Device) Read(ch int) (uint16, error) {
if ch < 0 || ch > 3 {
return 0, errors.New("invalid channel for pcf8591 Read")
}
return d.GetADC(ch).Get(), nil
}
// GetADC returns an ADC for a specific channel.
func (d *Device) GetADC(ch int) ADCPin {
return ADCPin{machine.Pin(ch), d}
}
// Get the current reading for a specific ADCPin.
func (p ADCPin) Get() uint16 {
// TODO: also implement DAC
tx := make([]byte, 2)
tx[0] = byte(p.Pin)
rx := make([]byte, 2)
// The result from the measurement triggered by the first write,
// however, the second write is required to get the result.
// See section 8.4 "A/D Conversion" in the datasheet for more info
p.d.bus.Tx(p.d.Address, tx, rx)
p.d.bus.Tx(p.d.Address, tx, rx)
// scale result to 16bit value like other ADCs
return uint16(rx[1]) << 8
}
// Configure here just for interface compatibility.
func (p ADCPin) Configure() {
}
-7
View File
@@ -1,7 +0,0 @@
package pcf8591
// PCF8591 Default Address
const defaultAddress = 0x48
// control bit for DAC
const PCF8591_ENABLE_DAC = 0x40
-10
View File
@@ -1,10 +0,0 @@
package drivers
// Pin is a digital pin interface. It is notably implemented by the
// machine.Pin type.
type Pin interface {
Get() bool
High()
Low()
Set(high bool)
}

Some files were not shown because too many files have changed in this diff Show More