mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 18:48:41 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fc9dd0670 | |||
| 479beeeece | |||
| 2526660a96 | |||
| 4213d6f582 | |||
| 81cf507e4e | |||
| 86cc0e31f1 | |||
| e3e95cacfe | |||
| 8b3075fdba | |||
| 7d58709b7d | |||
| 789bbbd89f | |||
| ea944c8933 | |||
| d27859453c | |||
| 0ccd979f23 | |||
| a888570c8c | |||
| 5b2c2f800d | |||
| 0ec887c9d8 | |||
| c5dbe18be1 | |||
| 2bca84b8d1 | |||
| 690daebcd1 | |||
| 89770a7d05 | |||
| 8a39bb7aae | |||
| a106fd48ce | |||
| b2fdd3c333 | |||
| 42dc6eb068 | |||
| c00cb3abdd |
@@ -103,6 +103,8 @@ smoke-test:
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=microbit-v2 ./examples/microbitmatrix/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mpu6050/main.go
|
||||
@@ -209,6 +211,8 @@ endif
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=pico ./examples/qmi8658c/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
|
||||
@md5sum ./build/test.hex
|
||||
tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
|
||||
|
||||
@@ -52,7 +52,7 @@ func main() {
|
||||
|
||||
## Currently supported devices
|
||||
|
||||
The following 83 devices are supported.
|
||||
The following 90 devices are supported.
|
||||
|
||||
| Device Name | Interface Type |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
|
||||
@@ -112,6 +112,7 @@ The following 83 devices are supported.
|
||||
| [P1AM-100 Base Controller](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) | SPI |
|
||||
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
||||
| [PCF8563 real time clock](https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf) | I2C |
|
||||
| [QMI8658C accelerometer/gyroscope](https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf) | I2C |
|
||||
| [Resistive Touchscreen (4-wire)](http://ww1.microchip.com/downloads/en/Appnotes/doc8091.pdf) | GPIO |
|
||||
| [RTL8720DN 2.4G/5G Dual Bands Wireless and BLE5.0](https://www.seeedstudio.com/Realtek8720DN-2-4G-5G-Dual-Bands-Wireless-and-BLE5-0-Combo-Module-p-4442.html) | UART |
|
||||
| [SCD4x CO2 Sensor](https://sensirion.com/media/documents/C4B87CE6/627C2DCD/CD_DS_SCD40_SCD41_Datasheet_D1.pdf) | I2C |
|
||||
@@ -140,10 +141,10 @@ The following 83 devices are supported.
|
||||
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) | SPI |
|
||||
| [Waveshare 2.9" e-paper display (V1)](https://www.waveshare.com/w/upload/e/e6/2.9inch_e-Paper_Datasheet.pdf) | SPI |
|
||||
| [Waveshare 4.2" e-paper B/W display](https://www.waveshare.com/w/upload/6/6a/4.2inch-e-paper-specification.pdf) | SPI |
|
||||
| [Waveshare GC9A01 TFT round display](https://www.waveshare.com/w/upload/5/5e/GC9A01A.pdf) | SPI |
|
||||
| [Waveshare GC9A01 TFT round display](https://www.waveshare.com/w/upload/5/5e/GC9A01A.pdf) | SPI |
|
||||
| [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO |
|
||||
| [XPT2046 touch controller](http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf) | GPIO |
|
||||
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-transceiv-ers/sx1261) | SPI |
|
||||
| [Semtech SX126x Lora](https://www.semtech.com/products/wireless-rf/lora-connect/sx1261) | SPI |
|
||||
| [SSD1289 TFT color display](http://aitendo3.sakura.ne.jp/aitendo_data/product_img/lcd/tft2/M032C1289TP/3.2-SSD1289.pdf) | GPIO |
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// Configure sets up the APDS-9960 device.
|
||||
func (d *Device) Configure(cfg Configuration) {
|
||||
// configure device
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package apds9960
|
||||
|
||||
|
||||
+115
-5
@@ -7,6 +7,7 @@ package bme280
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers"
|
||||
)
|
||||
@@ -33,11 +34,27 @@ type calibrationCoefficients struct {
|
||||
h6 int8
|
||||
}
|
||||
|
||||
type Oversampling byte
|
||||
type Mode byte
|
||||
type FilterCoefficient byte
|
||||
type Period byte
|
||||
|
||||
// Config contains settings for filtering, sampling, and modes of operation
|
||||
type Config struct {
|
||||
Pressure Oversampling
|
||||
Temperature Oversampling
|
||||
Humidity Oversampling
|
||||
Period Period
|
||||
Mode Mode
|
||||
IIR FilterCoefficient
|
||||
}
|
||||
|
||||
// Device wraps an I2C connection to a BME280 device.
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
calibrationCoefficients calibrationCoefficients
|
||||
Config Config
|
||||
}
|
||||
|
||||
// New creates a new BME280 connection. The I2C bus must already be
|
||||
@@ -51,9 +68,34 @@ func New(bus drivers.I2C) Device {
|
||||
}
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication and
|
||||
// read the calibration coefficientes.
|
||||
// ConfigureWithSettings sets up the device for communication and
|
||||
// read the calibration coefficients.
|
||||
//
|
||||
// The default configuration is the Indoor Navigation settings
|
||||
// from the BME280 datasheet.
|
||||
func (d *Device) Configure() {
|
||||
d.ConfigureWithSettings(Config{})
|
||||
}
|
||||
|
||||
// ConfigureWithSettings sets up the device for communication and
|
||||
// read the calibration coefficients.
|
||||
//
|
||||
// The default configuration if config is left at defaults is
|
||||
// the Indoor Navigation settings from the BME280 datasheet.
|
||||
func (d *Device) ConfigureWithSettings(config Config) {
|
||||
d.Config = config
|
||||
|
||||
// If config is not initialized, use Indoor Navigation defaults.
|
||||
if d.Config == (Config{}) {
|
||||
d.Config = Config{
|
||||
Mode: ModeNormal,
|
||||
Period: Period0_5ms,
|
||||
Temperature: Sampling2X,
|
||||
Humidity: Sampling1X,
|
||||
Pressure: Sampling16X,
|
||||
IIR: Coeff16,
|
||||
}
|
||||
}
|
||||
|
||||
var data [24]byte
|
||||
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
|
||||
@@ -93,10 +135,18 @@ func (d *Device) Configure() {
|
||||
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
|
||||
d.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
|
||||
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{0x3f})
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{0xB7})
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{0x00})
|
||||
d.Reset()
|
||||
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
|
||||
|
||||
// Normal mode, start measuring now
|
||||
if d.Config.Mode == ModeNormal {
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||
byte(d.Config.Temperature<<5) |
|
||||
byte(d.Config.Pressure<<2) |
|
||||
byte(d.Config.Mode)})
|
||||
}
|
||||
}
|
||||
|
||||
// Connected returns whether a BME280 has been found.
|
||||
@@ -112,6 +162,20 @@ func (d *Device) Reset() {
|
||||
d.bus.WriteRegister(uint8(d.Address), CMD_RESET, []byte{0xB6})
|
||||
}
|
||||
|
||||
// SetMode can set the device to Sleep, Normal or Forced mode
|
||||
//
|
||||
// Calling this method is optional, Configure can be used to set the
|
||||
// initial mode if no mode change is desired. This method is most
|
||||
// useful to switch between Sleep and Normal modes.
|
||||
func (d *Device) SetMode(mode Mode) {
|
||||
d.Config.Mode = mode
|
||||
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||
byte(d.Config.Temperature<<5) |
|
||||
byte(d.Config.Pressure<<2) |
|
||||
byte(d.Config.Mode)})
|
||||
}
|
||||
|
||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
||||
func (d *Device) ReadTemperature() (int32, error) {
|
||||
data, err := d.readData()
|
||||
@@ -186,6 +250,16 @@ func readIntLE(msb byte, lsb byte) int16 {
|
||||
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
|
||||
// resulting in an slice with 8 bytes 0-2 = pressure / 3-5 = temperature / 6-7 = humidity
|
||||
func (d *Device) readData() (data [8]byte, err error) {
|
||||
if d.Config.Mode == ModeForced {
|
||||
// Write the CTRL_MEAS register to trigger a measurement
|
||||
d.bus.WriteRegister(uint8(d.Address), CTRL_MEAS_ADDR, []byte{
|
||||
byte(d.Config.Temperature<<5) |
|
||||
byte(d.Config.Pressure<<2) |
|
||||
byte(d.Config.Mode)})
|
||||
|
||||
time.Sleep(d.measurementDelay())
|
||||
}
|
||||
|
||||
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
|
||||
if err != nil {
|
||||
println(err)
|
||||
@@ -256,3 +330,39 @@ func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
|
||||
return int32(100 * h)
|
||||
|
||||
}
|
||||
|
||||
// measurementDelay returns how much time each measurement will take
|
||||
// on the device.
|
||||
//
|
||||
// This is used in forced mode to wait until a measurement is complete.
|
||||
func (d *Device) measurementDelay() time.Duration {
|
||||
const MeasOffset = 1250
|
||||
const MeasDur = 2300
|
||||
const HumMeasOffset = 575
|
||||
const MeasScalingFactor = 1000
|
||||
|
||||
// delay is based on over-sampling rate - this table converts from
|
||||
// setting to number samples
|
||||
sampleRateConv := []int{0, 1, 2, 4, 8, 16}
|
||||
|
||||
tempOsr := 16
|
||||
if d.Config.Temperature <= Sampling16X {
|
||||
tempOsr = sampleRateConv[d.Config.Temperature]
|
||||
}
|
||||
|
||||
presOsr := 16
|
||||
if d.Config.Temperature <= Sampling16X {
|
||||
presOsr = sampleRateConv[d.Config.Pressure]
|
||||
}
|
||||
|
||||
humOsr := 16
|
||||
if d.Config.Temperature <= Sampling16X {
|
||||
humOsr = sampleRateConv[d.Config.Humidity]
|
||||
}
|
||||
|
||||
max_delay := ((MeasOffset + (MeasDur * tempOsr) +
|
||||
((MeasDur * presOsr) + HumMeasOffset) +
|
||||
((MeasDur * humOsr) + HumMeasOffset)) / MeasScalingFactor)
|
||||
|
||||
return time.Duration(max_delay) * time.Millisecond
|
||||
}
|
||||
|
||||
@@ -20,6 +20,50 @@ const (
|
||||
CHIP_ID = 0x60
|
||||
)
|
||||
|
||||
// Increasing sampling rate increases precision but also the wait time for measurements. The datasheet has a table of
|
||||
// suggested values for oversampling, output data rates, and iir filter coefficients by use case.
|
||||
const (
|
||||
SamplingOff Oversampling = iota
|
||||
Sampling1X
|
||||
Sampling2X
|
||||
Sampling4X
|
||||
Sampling8X
|
||||
Sampling16X
|
||||
)
|
||||
|
||||
// In normal mode (the default) the sensor takes masurements periodically. In forced
|
||||
// mode, the sensor takes a measurement only when requested.
|
||||
//
|
||||
// For use-cases with infrequent sampling, forced mode is more power efficient.
|
||||
const (
|
||||
ModeNormal Mode = 0x03
|
||||
ModeForced Mode = 0x01
|
||||
ModeSleep Mode = 0x00
|
||||
)
|
||||
|
||||
// IIR filter coefficients, higher values means steadier measurements but slower reaction times
|
||||
const (
|
||||
Coeff0 FilterCoefficient = iota
|
||||
Coeff2
|
||||
Coeff4
|
||||
Coeff8
|
||||
Coeff16
|
||||
)
|
||||
|
||||
// Period of standby in normal mode which controls how often measurements are taken
|
||||
//
|
||||
// Note Period10ms and Period20ms are out of sequence, but are per the datasheet
|
||||
const (
|
||||
Period0_5ms Period = 0b000
|
||||
Period62_5ms = 0b001
|
||||
Period125ms = 0b010
|
||||
Period250ms = 0b011
|
||||
Period500ms = 0b100
|
||||
Period1000ms = 0b101
|
||||
Period10ms = 0b110
|
||||
Period20ms = 0b111
|
||||
)
|
||||
|
||||
const (
|
||||
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
||||
)
|
||||
|
||||
@@ -54,6 +54,12 @@ func (l *Device) Tone(hz, duration float64) (err error) {
|
||||
|
||||
tempo := ((60 / l.BPM) * (duration * 1000))
|
||||
|
||||
// no tone during rest, just let the duration pass.
|
||||
if hz == Rest {
|
||||
time.Sleep(time.Duration(tempo) * time.Millisecond)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0.0; i < tempo*1000; i += tone * 2.0 {
|
||||
if err = l.On(); err != nil {
|
||||
return
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package buzzer
|
||||
|
||||
const (
|
||||
Whole = 4
|
||||
Half = 2
|
||||
Quarter = 1
|
||||
Whole = 4.0
|
||||
Half = 2.0
|
||||
Quarter = 1.0
|
||||
Eighth = 0.500
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build mimxrt1062 || stm32f405 || atsamd51 || stm32f103xx || k210 || stm32f407
|
||||
// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !mimxrt1062 && !stm32f405 && !atsamd51 && !stm32f103xx && !k210 && !stm32f407
|
||||
// +build !mimxrt1062,!stm32f405,!atsamd51,!stm32f103xx,!k210,!stm32f407
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
|
||||
+3
-3
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
@@ -11,6 +10,7 @@ package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"runtime/interrupt"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -160,8 +160,8 @@ func (t *device) read() error {
|
||||
// interrupts
|
||||
func receiveSignals(pin machine.Pin, result []counter) {
|
||||
i := uint8(0)
|
||||
machine.UART1.Interrupt.Disable()
|
||||
defer machine.UART1.Interrupt.Enable()
|
||||
mask := interrupt.Disable()
|
||||
defer interrupt.Restore(mask)
|
||||
for ; i < 40; i++ {
|
||||
result[i*2] = expectChange(pin, false)
|
||||
result[i*2+1] = expectChange(pin, true)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
package dht // import "tinygo.org/x/drivers/dht"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build feather_m0 || feather_m4 || feather_m4_can || feather_nrf52840 || feather_nrf52840_sense || feather_stm32f405 || feather_rp2040
|
||||
// +build feather_m0 feather_m4 feather_m4_can feather_nrf52840 feather_nrf52840_sense feather_stm32f405 feather_rp2040
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build m5stack
|
||||
// +build m5stack
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build m5stack_core2
|
||||
// +build m5stack_core2
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package initdisplay
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Connects to an QMI8658C I2C accelerometer/gyroscope and print the read data.
|
||||
// This example was made with the "WaveShare RP2040 Round LCD 1.28in" in mind.
|
||||
// For more infor about this development board:
|
||||
// https://www.waveshare.com/wiki/RP2040-LCD-1.28
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
|
||||
imu "tinygo.org/x/drivers/qmi8658c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
i2c := machine.I2C1
|
||||
// This is the default pinout for the "WaveShare RP2040 Round LCD 1.28in"
|
||||
err := i2c.Configure(machine.I2CConfig{
|
||||
SDA: machine.GP6,
|
||||
SCL: machine.GP7,
|
||||
Frequency: 100000,
|
||||
})
|
||||
if err != nil {
|
||||
println("unable to configure I2C:", err)
|
||||
return
|
||||
}
|
||||
// Create a new device
|
||||
d := imu.New(i2c)
|
||||
|
||||
// Check if the device is connected
|
||||
if !d.Connected() {
|
||||
println("unable to connect to sensor")
|
||||
return
|
||||
}
|
||||
|
||||
// This IMU has multiple configurations like output data rate, multiple
|
||||
// measurements scales, low pass filters, low power modes, all the vailable
|
||||
// values can be found in the datasheet and were defined at registers file.
|
||||
// This is the default configuration which will be used if the `nil` value
|
||||
// is passed do the `Configure` method.
|
||||
config := imu.Config{
|
||||
SPIMode: imu.SPI_4_WIRE,
|
||||
SPIEndian: imu.SPI_BIG_ENDIAN,
|
||||
SPIAutoInc: imu.SPI_AUTO_INC,
|
||||
AccEnable: imu.ACC_ENABLE,
|
||||
AccScale: imu.ACC_8G,
|
||||
AccRate: imu.ACC_NORMAL_1000HZ,
|
||||
AccLowPass: imu.ACC_LOW_PASS_2_62,
|
||||
GyroEnable: imu.GYRO_FULL_ENABLE,
|
||||
GyroScale: imu.GYRO_512DPS,
|
||||
GyroRate: imu.GYRO_1000HZ,
|
||||
GyroLowPass: imu.GYRO_LOW_PASS_2_62,
|
||||
}
|
||||
d.Configure(config)
|
||||
|
||||
// Read the accelation, rotation and temperature data and print them.
|
||||
for {
|
||||
acc_x, acc_y, acc_z := d.ReadAcceleration()
|
||||
gyro_x, gyro_y, gyro_z := d.ReadRotation()
|
||||
temp, _ := d.ReadTemperature()
|
||||
println("-------------------------------")
|
||||
println("acc:", acc_x, acc_y, acc_z)
|
||||
println("gyro:", gyro_x, gyro_y, gyro_z)
|
||||
println("temp:", temp)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
@@ -100,9 +100,7 @@ func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
|
||||
} else if n == 0 {
|
||||
continue // no packet received yet
|
||||
} else if n != NTP_PACKET_SIZE {
|
||||
if n != NTP_PACKET_SIZE {
|
||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||
}
|
||||
return parseNTPpacket(), nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build feather_m4 || feather_m4_can || feather_nrf52840
|
||||
// +build feather_m4 feather_m4_can feather_nrf52840
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build grandcentral_m4
|
||||
// +build grandcentral_m4
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd21 && !p1am_100
|
||||
// +build atsamd21,!p1am_100
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build p1am_100
|
||||
// +build p1am_100
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pygamer
|
||||
// +build pygamer
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build thingplus_rp2040
|
||||
// +build thingplus_rp2040
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo
|
||||
// +build tinygo
|
||||
|
||||
package console
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build feather_m4 || feather_m4_can || feather_nrf52840
|
||||
// +build feather_m4 feather_m4_can feather_nrf52840
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build grandcentral_m4
|
||||
// +build grandcentral_m4
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd21 && !p1am_100
|
||||
// +build atsamd21,!p1am_100
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build p1am_100
|
||||
// +build p1am_100
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pygamer
|
||||
// +build pygamer
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pyportal
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build thingplus_rp2040
|
||||
// +build thingplus_rp2040
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build wioterminal
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build gnse
|
||||
// +build gnse
|
||||
|
||||
/*
|
||||
Generic Node Sensor Edition
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build lorae5
|
||||
// +build lorae5
|
||||
|
||||
package radio
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nucleowl55jc
|
||||
// +build nucleowl55jc
|
||||
|
||||
/*
|
||||
Nucleo WL55JC1
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build espat
|
||||
// +build espat
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build rtl8720dn
|
||||
// +build rtl8720dn
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build wifinina
|
||||
// +build wifinina
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -111,9 +111,7 @@ func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
|
||||
} else if n == 0 {
|
||||
continue // no packet received yet
|
||||
} else if n != NTP_PACKET_SIZE {
|
||||
if n != NTP_PACKET_SIZE {
|
||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||
}
|
||||
return parseNTPpacket(), nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nano_rp2040
|
||||
// +build nano_rp2040
|
||||
|
||||
// This examples shows how to control RGB LED connected to
|
||||
// NINA-W102 chip on Arduino Nano RP2040 Connect board
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net/http"
|
||||
"tinygo.org/x/drivers/wifinina"
|
||||
)
|
||||
|
||||
// You can override the settings with the init() in another source code:
|
||||
//
|
||||
// func init() {
|
||||
// ssid = "your-ssid"
|
||||
// pass = "your-password"
|
||||
// }
|
||||
//
|
||||
// Or use -ldflags option on tinygo command to set at compile-time:
|
||||
//
|
||||
// tinygo flash ... -ldflags '-X "main.ssid=xxx" -X "main.pass=xxx"' ...
|
||||
//
|
||||
|
||||
var (
|
||||
ssid string
|
||||
pass string
|
||||
)
|
||||
|
||||
var led = machine.LED
|
||||
|
||||
func main() {
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
err := run()
|
||||
for err != nil {
|
||||
fmt.Printf("error: %s\r\n", err.Error())
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
|
||||
spi := machine.NINA_SPI
|
||||
spi.Configure(machine.SPIConfig{
|
||||
Frequency: 8 * 1e6,
|
||||
SDO: machine.NINA_SDO,
|
||||
SDI: machine.NINA_SDI,
|
||||
SCK: machine.NINA_SCK,
|
||||
})
|
||||
|
||||
adaptor := wifinina.New(spi,
|
||||
machine.NINA_CS,
|
||||
machine.NINA_ACK,
|
||||
machine.NINA_GPIO0,
|
||||
machine.NINA_RESETN)
|
||||
adaptor.Configure()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
println("Connecting to " + ssid)
|
||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
println("Connected.")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
ip, subnet, gateway, err := adaptor.GetIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("IP Address : %s\r\n", ip)
|
||||
fmt.Printf("Mask : %s\r\n", subnet)
|
||||
fmt.Printf("Gateway : %s\r\n", gateway)
|
||||
|
||||
http.UseDriver(adaptor)
|
||||
|
||||
http.HandleFunc("/", root)
|
||||
http.HandleFunc("/hello", hello)
|
||||
http.HandleFunc("/cnt", cnt)
|
||||
http.HandleFunc("/6", sixlines)
|
||||
http.HandleFunc("/off", LED_OFF)
|
||||
http.HandleFunc("/on", LED_ON)
|
||||
|
||||
return http.ListenAndServe(":80", nil)
|
||||
}
|
||||
|
||||
func root(w http.ResponseWriter, r *http.Request) {
|
||||
access := 1
|
||||
|
||||
cookie, err := r.Cookie("access")
|
||||
if err != nil {
|
||||
if err == http.ErrNoCookie {
|
||||
cookie = &http.Cookie{
|
||||
Name: "access",
|
||||
Value: "1",
|
||||
}
|
||||
} else {
|
||||
http.Error(w, fmt.Sprintf("%s", err.Error()), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
v, err := strconv.ParseInt(cookie.Value, 10, 0)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("invalid cookie.Value : %s", cookie.Value), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
cookie.Value = fmt.Sprintf("%d", v+1)
|
||||
access = int(v) + 1
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
fmt.Fprintf(w, `
|
||||
<html>
|
||||
<head>
|
||||
<title>TinyGo HTTP Server</title>
|
||||
<script language="javascript" type="text/javascript">
|
||||
var counter = 0
|
||||
function ledOn() { fetch("/on"); }
|
||||
function ledOff() { fetch("/off"); }
|
||||
function fetchCnt() { fetch("/cnt").then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
||||
function incrCnt() { counter = counter + 1; fetch("/cnt?cnt=" + counter, { method: 'POST' }).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); }
|
||||
function setCnt() { fetch("/cnt", {
|
||||
method: "POST",
|
||||
body: "cnt=" + document.getElementsByName("cnt")[0].value,
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
}).then(response => response.json()).then(json => { counter = json.cnt; cnt.innerHTML = counter; }); return false; }
|
||||
function onLoad() { fetchCnt(); }
|
||||
</script>
|
||||
</head>
|
||||
<body onLoad="onLoad()">
|
||||
<h5>TinyGo HTTP Server</h5>
|
||||
|
||||
<p>
|
||||
access: %d
|
||||
</p>
|
||||
|
||||
<a href="/hello">/hello</a><br>
|
||||
<a href="/6">/6</a><br>
|
||||
|
||||
<p>
|
||||
LED<br>
|
||||
<a href="javascript:ledOn();">/on</a><br>
|
||||
<a href="javascript:ledOff();">/off</a><br>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<a href="/cnt">/cnt</a><br>
|
||||
cnt: <span id="cnt"></span><br>
|
||||
<a href="javascript:incrCnt()">incrCnt()</a><br>
|
||||
<form id="form1" style="display: inline" onSubmit="return setCnt()">
|
||||
<input type="text" name="cnt">
|
||||
<input type="button" value="set cnt", onClick="setCnt()">
|
||||
</form>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
`, access)
|
||||
}
|
||||
|
||||
func sixlines(w http.ResponseWriter, r *http.Request) {
|
||||
// https://fukuno.jig.jp/3267
|
||||
fmt.Fprint(w, `<body onload='onkeydown=e=>K=parseInt(e.key[5]||6,28)/3-8;Z=X=[B=A=12];Y=_=>`+
|
||||
`{for(C=[q=c=i=4];f=i--*K;c-=!Z[h+(K+6?p+K:C[i]=p*A-(p/9|0)*145)])p=B[i];for(c?0:K+6?h+=K:B=C;`+
|
||||
`i=K=q--;f+=Z[A+p])X[p=h+B[q]]=1;h+=A;if(f|B)for(Z=X,X=[l=228],B=[[-7,-20,6,h=17,-9,3,3][t=++t%7]-4,0,1,t-6?-A:2];l--;)`+
|
||||
`for(l%A?l-=l%A*!Z[l]:(P++,c=l+=A);--c>A;)Z[c]=Z[c-A];for(S="";i<240;S+=X[i]|(X[i]=Z[i]|=++i%A<2|i>228)?i%A?"■":"■<br>":" ");`+
|
||||
`D.innerHTML=S+P;setTimeout(Y,i-P)};Y(h=K=t=P=0)'id=D>`)
|
||||
}
|
||||
|
||||
func LED_ON(w http.ResponseWriter, r *http.Request) {
|
||||
led.High()
|
||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||
fmt.Fprintf(w, "led.High()")
|
||||
}
|
||||
|
||||
func LED_OFF(w http.ResponseWriter, r *http.Request) {
|
||||
led.Low()
|
||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||
fmt.Fprintf(w, "led.Low()")
|
||||
}
|
||||
|
||||
func hello(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(`Content-Type`, `text/plain; charset=UTF-8`)
|
||||
fmt.Fprintf(w, "hello")
|
||||
}
|
||||
|
||||
var counter int
|
||||
|
||||
func cnt(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
if r.Method == "POST" {
|
||||
c := r.Form.Get("cnt")
|
||||
if c != "" {
|
||||
i64, _ := strconv.ParseInt(c, 0, 0)
|
||||
counter = int(i64)
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set(`Content-Type`, `application/json`)
|
||||
fmt.Fprintf(w, `{"cnt": %d}`, counter)
|
||||
}
|
||||
|
||||
func message(msg string) {
|
||||
println(msg, "\r")
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build arduino
|
||||
// +build arduino
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build digispark
|
||||
// +build digispark
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !digispark && !arduino && !qtpy && !m5stamp_c3 && !thingplus_rp2040
|
||||
// +build !digispark,!arduino,!qtpy,!m5stamp_c3,!thingplus_rp2040
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build qtpy || m5stamp_c3
|
||||
// +build qtpy m5stamp_c3
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build qtpy
|
||||
// +build qtpy
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build thingplus_rp2040
|
||||
// +build thingplus_rp2040
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd51
|
||||
// +build atsamd51
|
||||
|
||||
package flash
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package hts221
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package hts221
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd51 || atsame5x
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build esp32
|
||||
// +build esp32
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nrf52840
|
||||
// +build nrf52840
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !esp32 && !atsamd51 && !atsame5x && !stm32f4 && !rp2040 && !nrf52840
|
||||
// +build !esp32,!atsamd51,!atsame5x,!stm32f4,!rp2040,!nrf52840
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build stm32f4
|
||||
// +build stm32f4
|
||||
|
||||
package i2csoft
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd51
|
||||
// +build atsamd51
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !atsamd51 && !atsame5x && !atsamd21
|
||||
// +build !atsamd51,!atsame5x,!atsamd21
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd21
|
||||
// +build atsamd21
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build atsamd51 || atsame5x
|
||||
// +build atsamd51 atsame5x
|
||||
|
||||
package ili9341
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
package png
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package lps22hb
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
package lps22hb
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ func (d *Device) Configure(cfg Configuration) (err error) {
|
||||
// -1000000.
|
||||
func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
|
||||
data := d.buf[:6]
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), ACCEL_OUT_X_L_A, data)
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), ACCEL_OUT_AUTO_INC, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -190,7 +190,7 @@ func (d *Device) ReadMagneticField() (x, y, z int32, err error) {
|
||||
}
|
||||
|
||||
data := d.buf[0:6]
|
||||
d.bus.ReadRegister(uint8(d.MagAddress), MAG_OUT_X_L_M, data)
|
||||
d.bus.ReadRegister(uint8(d.MagAddress), MAG_OUT_AUTO_INC, data)
|
||||
|
||||
x = int32(int16((uint16(data[1])<<8 | uint16(data[0]))))
|
||||
y = int32(int16((uint16(data[3])<<8 | uint16(data[2]))))
|
||||
@@ -219,7 +219,7 @@ func (d *Device) ReadCompass() (h int32, err error) {
|
||||
func (d *Device) ReadTemperature() (t int32, err error) {
|
||||
|
||||
data := d.buf[:2]
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_L_A, data)
|
||||
err = d.bus.ReadRegister(uint8(d.AccelAddress), OUT_TEMP_AUTO_INC, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+29
-20
@@ -6,31 +6,40 @@ const (
|
||||
ACCEL_ADDRESS = 0x19
|
||||
MAG_ADDRESS = 0x1E
|
||||
|
||||
// i2C 8-bit subaddress (SUB): the 7 LSb represent the actual register address
|
||||
// while the MSB enables address auto increment.
|
||||
// If the MSb of the SUB field is 1, the SUB (register address) is
|
||||
// automatically increased to allow multiple data read/writes.
|
||||
ADDR_AUTO_INC_MASK = 0x80
|
||||
|
||||
// accelerometer registers.
|
||||
ACCEL_WHO_AM_I = 0x0F
|
||||
ACCEL_CTRL_REG1_A = 0x20
|
||||
ACCEL_CTRL_REG4_A = 0x23
|
||||
ACCEL_OUT_X_L_A = 0x28
|
||||
ACCEL_OUT_X_H_A = 0x29
|
||||
ACCEL_OUT_Y_L_A = 0x2A
|
||||
ACCEL_OUT_Y_H_A = 0x2B
|
||||
ACCEL_OUT_Z_L_A = 0x2C
|
||||
ACCEL_OUT_Z_H_A = 0x2D
|
||||
ACCEL_WHO_AM_I = 0x0F
|
||||
ACCEL_CTRL_REG1_A = 0x20
|
||||
ACCEL_CTRL_REG4_A = 0x23
|
||||
ACCEL_OUT_X_L_A = 0x28
|
||||
ACCEL_OUT_X_H_A = 0x29
|
||||
ACCEL_OUT_Y_L_A = 0x2A
|
||||
ACCEL_OUT_Y_H_A = 0x2B
|
||||
ACCEL_OUT_Z_L_A = 0x2C
|
||||
ACCEL_OUT_Z_H_A = 0x2D
|
||||
ACCEL_OUT_AUTO_INC = ACCEL_OUT_X_L_A | ADDR_AUTO_INC_MASK
|
||||
|
||||
// magnetic sensor registers.
|
||||
MAG_WHO_AM_I = 0x4F
|
||||
MAG_MR_REG_M = 0x60
|
||||
MAG_OUT_X_L_M = 0x68
|
||||
MAG_OUT_X_H_M = 0x69
|
||||
MAG_OUT_Y_L_M = 0x6A
|
||||
MAG_OUT_Y_H_M = 0x6B
|
||||
MAG_OUT_Z_L_M = 0x6C
|
||||
MAG_OUT_Z_H_M = 0x6D
|
||||
MAG_WHO_AM_I = 0x4F
|
||||
MAG_MR_REG_M = 0x60
|
||||
MAG_OUT_X_L_M = 0x68
|
||||
MAG_OUT_X_H_M = 0x69
|
||||
MAG_OUT_Y_L_M = 0x6A
|
||||
MAG_OUT_Y_H_M = 0x6B
|
||||
MAG_OUT_Z_L_M = 0x6C
|
||||
MAG_OUT_Z_H_M = 0x6D
|
||||
MAG_OUT_AUTO_INC = MAG_OUT_X_L_M | ADDR_AUTO_INC_MASK
|
||||
|
||||
// temperature sensor registers.
|
||||
TEMP_CFG_REG_A = 0x1F
|
||||
OUT_TEMP_L_A = 0x0C
|
||||
OUT_TEMP_H_A = 0x0D
|
||||
TEMP_CFG_REG_A = 0x1F
|
||||
OUT_TEMP_L_A = 0x0C
|
||||
OUT_TEMP_H_A = 0x0D
|
||||
OUT_TEMP_AUTO_INC = OUT_TEMP_L_A | ADDR_AUTO_INC_MASK
|
||||
|
||||
// accelerometer power mode.
|
||||
ACCEL_POWER_NORMAL = 0x00 // default
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !xiao_ble
|
||||
// +build !xiao_ble
|
||||
|
||||
package lsm6ds3tr
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build xiao_ble
|
||||
// +build xiao_ble
|
||||
|
||||
package lsm6ds3tr
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !nano_33_ble
|
||||
// +build !nano_33_ble
|
||||
|
||||
package lsm9ds1
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build nano_33_ble
|
||||
// +build nano_33_ble
|
||||
|
||||
// Nano 33 BLE [Sense] has LSM9DS1 unit on-board.
|
||||
// This custom Configure function powers unit up
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build microbit
|
||||
// +build microbit
|
||||
|
||||
// Package microbitmatrix implements a driver for the BBC micro:bit's LED matrix.
|
||||
//
|
||||
@@ -8,9 +7,12 @@ package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 4 rotation orientations (0, 90, 180, 270), CW (clock wise)
|
||||
// 5 rows
|
||||
// 5 cols
|
||||
// target coordinates in machine rows (y) and cols (x)
|
||||
var matrixRotations = [4][5][5][2]uint8{
|
||||
{ // 0
|
||||
{{0, 0}, {1, 3}, {0, 1}, {1, 4}, {0, 2}},
|
||||
@@ -19,7 +21,7 @@ var matrixRotations = [4][5][5][2]uint8{
|
||||
{{0, 7}, {0, 6}, {0, 5}, {0, 4}, {0, 3}},
|
||||
{{2, 2}, {1, 6}, {2, 0}, {1, 5}, {2, 1}},
|
||||
},
|
||||
{ // 90 CCW
|
||||
{ // 90 CW
|
||||
{{0, 2}, {2, 7}, {1, 0}, {0, 3}, {2, 1}},
|
||||
{{1, 4}, {2, 6}, {2, 8}, {0, 4}, {1, 5}},
|
||||
{{0, 1}, {2, 5}, {1, 2}, {0, 5}, {2, 0}},
|
||||
@@ -42,71 +44,33 @@ var matrixRotations = [4][5][5][2]uint8{
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
ledRows = 3
|
||||
ledCols = 9
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
pin [12]machine.Pin
|
||||
buffer [3][9]bool
|
||||
pin [ledCols + ledRows]machine.Pin
|
||||
buffer [ledRows][ledCols]int8
|
||||
rotation uint8
|
||||
}
|
||||
|
||||
// Configure sets up the device.
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
d.SetRotation(cfg.Rotation)
|
||||
func (d *Device) assignPins() {
|
||||
d.pin[0] = machine.LED_COL_1
|
||||
d.pin[1] = machine.LED_COL_2
|
||||
d.pin[2] = machine.LED_COL_3
|
||||
d.pin[3] = machine.LED_COL_4
|
||||
d.pin[4] = machine.LED_COL_5
|
||||
d.pin[5] = machine.LED_COL_6
|
||||
d.pin[6] = machine.LED_COL_7
|
||||
d.pin[7] = machine.LED_COL_8
|
||||
d.pin[8] = machine.LED_COL_9
|
||||
|
||||
for i := machine.LED_COL_1; i <= machine.LED_ROW_3; i++ {
|
||||
d.pin[i-machine.LED_COL_1] = i
|
||||
d.pin[i-machine.LED_COL_1].Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
d.ClearDisplay()
|
||||
d.DisableAll()
|
||||
}
|
||||
d.pin[9] = machine.LED_ROW_1
|
||||
d.pin[10] = machine.LED_ROW_2
|
||||
d.pin[11] = machine.LED_ROW_3
|
||||
|
||||
// Display sends the buffer (if any) to the screen.
|
||||
func (d *Device) Display() error {
|
||||
for row := 0; row < 3; row++ {
|
||||
d.DisableAll()
|
||||
d.pin[9+row].High()
|
||||
|
||||
for col := 0; col < 9; col++ {
|
||||
if d.buffer[row][col] {
|
||||
d.pin[col].Low()
|
||||
}
|
||||
|
||||
}
|
||||
time.Sleep(time.Millisecond * 2)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay erases the internal buffer
|
||||
func (d *Device) ClearDisplay() {
|
||||
for row := 0; row < 3; row++ {
|
||||
for col := 0; col < 9; col++ {
|
||||
d.buffer[row][col] = false
|
||||
}
|
||||
for i := 0; i < len(d.pin); i++ {
|
||||
d.pin[i].Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
}
|
||||
|
||||
// DisableAll disables all the LEDs without modifying the buffer
|
||||
func (d *Device) DisableAll() {
|
||||
for i := machine.LED_COL_1; i <= machine.LED_COL_9; i++ {
|
||||
d.pin[i-machine.LED_COL_1].High()
|
||||
}
|
||||
for i := machine.LED_ROW_1; i <= machine.LED_ROW_3; i++ {
|
||||
d.pin[i-machine.LED_COL_1].Low()
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAll enables all the LEDs without modifying the buffer
|
||||
func (d *Device) EnableAll() {
|
||||
for i := machine.LED_COL_1; i <= machine.LED_COL_9; i++ {
|
||||
d.pin[i-machine.LED_COL_1].Low()
|
||||
}
|
||||
for i := machine.LED_ROW_1; i <= machine.LED_ROW_3; i++ {
|
||||
d.pin[i-machine.LED_COL_1].High()
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
func (d *Device) Size() (w, h int16) {
|
||||
return 5, 5
|
||||
}
|
||||
|
||||
@@ -1,57 +1,61 @@
|
||||
//go:build microbit_v2
|
||||
// +build microbit_v2
|
||||
|
||||
// Package microbitmatrix implements a driver for the BBC micro:bit version 2 LED matrix.
|
||||
//
|
||||
// Schematic:
|
||||
// Schematic: https://github.com/microbit-foundation/microbit-v2-hardware/blob/main/V2.00/MicroBit_V2.0.0_S_schematic.PDF
|
||||
package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix"
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 4 rotation orientations (0, 90, 180, 270), CW (clock wise)
|
||||
// 5 rows
|
||||
// 5 cols
|
||||
// target coordinates in machine rows (y) and cols (x)
|
||||
var matrixRotations = [4][5][5][2]uint8{
|
||||
{ // 0
|
||||
{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}},
|
||||
{{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}},
|
||||
{{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}},
|
||||
{{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}},
|
||||
{{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}},
|
||||
},
|
||||
{ // 90 CCW
|
||||
{{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}},
|
||||
{{3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}},
|
||||
{{2, 0}, {2, 1}, {2, 2}, {2, 3}, {2, 4}},
|
||||
{{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}},
|
||||
{{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}},
|
||||
{{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}},
|
||||
{{2, 0}, {2, 1}, {2, 2}, {2, 3}, {2, 4}},
|
||||
{{3, 0}, {3, 1}, {3, 2}, {3, 3}, {3, 4}},
|
||||
{{4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}},
|
||||
},
|
||||
{ // 90 CW
|
||||
{{0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4}},
|
||||
{{0, 3}, {1, 3}, {2, 3}, {3, 3}, {4, 3}},
|
||||
{{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}},
|
||||
{{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}},
|
||||
{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}},
|
||||
},
|
||||
{ // 180
|
||||
{{4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}},
|
||||
{{4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}},
|
||||
{{4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}},
|
||||
{{4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}},
|
||||
{{4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},
|
||||
{{4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}},
|
||||
{{3, 4}, {3, 3}, {3, 2}, {3, 1}, {3, 0}},
|
||||
{{2, 4}, {2, 3}, {2, 2}, {2, 1}, {2, 0}},
|
||||
{{1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}},
|
||||
{{0, 4}, {0, 3}, {0, 2}, {0, 1}, {0, 0}},
|
||||
},
|
||||
{ // 270
|
||||
{{0, 4}, {0, 3}, {0, 2}, {0, 1}, {0, 0}},
|
||||
{{1, 4}, {1, 3}, {1, 2}, {1, 1}, {1, 0}},
|
||||
{{2, 4}, {2, 3}, {2, 2}, {2, 1}, {2, 0}},
|
||||
{{3, 4}, {3, 3}, {3, 2}, {3, 1}, {3, 0}},
|
||||
{{4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}},
|
||||
{{4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}},
|
||||
{{4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}},
|
||||
{{4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}},
|
||||
{{4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}},
|
||||
{{4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}},
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
ledRows = 5
|
||||
ledCols = 5
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
pin [10]machine.Pin
|
||||
buffer [5][5]bool
|
||||
pin [ledCols + ledRows]machine.Pin
|
||||
buffer [ledRows][ledCols]int8
|
||||
rotation uint8
|
||||
}
|
||||
|
||||
// Configure sets up the device.
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
d.SetRotation(cfg.Rotation)
|
||||
|
||||
func (d *Device) assignPins() {
|
||||
d.pin[0] = machine.LED_COL_1
|
||||
d.pin[1] = machine.LED_COL_2
|
||||
d.pin[2] = machine.LED_COL_3
|
||||
@@ -64,59 +68,7 @@ func (d *Device) Configure(cfg Config) {
|
||||
d.pin[8] = machine.LED_ROW_4
|
||||
d.pin[9] = machine.LED_ROW_5
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := 0; i < len(d.pin); i++ {
|
||||
d.pin[i].Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
}
|
||||
|
||||
d.ClearDisplay()
|
||||
d.DisableAll()
|
||||
}
|
||||
|
||||
// Display sends the buffer (if any) to the screen.
|
||||
func (d *Device) Display() error {
|
||||
for x := 0; x < 5; x++ {
|
||||
d.DisableAll()
|
||||
d.pin[x].Low()
|
||||
|
||||
for y := 0; y < 5; y++ {
|
||||
if d.buffer[x][y] {
|
||||
d.pin[5+y].High()
|
||||
} else {
|
||||
d.pin[5+y].Low()
|
||||
}
|
||||
|
||||
}
|
||||
time.Sleep(time.Millisecond * 4)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay erases the internal buffer
|
||||
func (d *Device) ClearDisplay() {
|
||||
for row := 0; row < 5; row++ {
|
||||
for col := 0; col < 5; col++ {
|
||||
d.buffer[row][col] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DisableAll disables all the LEDs without modifying the buffer
|
||||
func (d *Device) DisableAll() {
|
||||
for i := 0; i < 5; i++ {
|
||||
d.pin[i].High()
|
||||
d.pin[5+i].Low()
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAll enables all the LEDs without modifying the buffer
|
||||
func (d *Device) EnableAll() {
|
||||
for i := 0; i < 5; i++ {
|
||||
d.pin[i].Low()
|
||||
d.pin[5+i].High()
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
func (d *Device) Size() (w, h int16) {
|
||||
return 5, 5
|
||||
}
|
||||
|
||||
@@ -1,42 +1,213 @@
|
||||
// Package microbitmatrix implements a driver for the BBC micro:bit's LED matrix.
|
||||
//
|
||||
// Schematic: https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf
|
||||
package microbitmatrix // import "tinygo.org/x/drivers/microbitmatrix"
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Rotation of the LED matrix.
|
||||
//
|
||||
// Valid values:
|
||||
//
|
||||
// 0: regular orientation, (0 degree rotation)
|
||||
// 1: 90 degree rotation clock wise
|
||||
// 2: 180 degree rotation clock wise
|
||||
// 3: 270 degree rotation clock wise
|
||||
Rotation uint8
|
||||
}
|
||||
|
||||
const (
|
||||
RotationNormal = 0
|
||||
Rotation90 = 1
|
||||
Rotation180 = 2
|
||||
Rotation270 = 3
|
||||
)
|
||||
|
||||
// New returns a new microbitmatrix driver.
|
||||
func New() Device {
|
||||
return Device{}
|
||||
}
|
||||
|
||||
// SetRotation changes the rotation of the LED matrix
|
||||
// Configure sets up the device.
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
d.SetRotation(cfg.Rotation)
|
||||
|
||||
d.assignPins()
|
||||
|
||||
d.ClearDisplay()
|
||||
d.DisableAll()
|
||||
}
|
||||
|
||||
// SetRotation changes the rotation of the LED matrix.
|
||||
//
|
||||
// Valid values for rotation:
|
||||
//
|
||||
// 0: regular orientation, (0 degree rotation)
|
||||
// 1: 90 degree rotation clock wise
|
||||
// 2: 180 degree rotation clock wise
|
||||
// 3: 270 degree rotation clock wise
|
||||
func (d *Device) SetRotation(rotation uint8) {
|
||||
d.rotation = rotation % 4
|
||||
}
|
||||
|
||||
// Source:
|
||||
// https://github.com/bbcmicrobit/micropython/blob/1252f887ddc790676bf9314a136bd17650b9c36c/source/microbit/microbitdisplay.cpp#L282
|
||||
var renderTimings = []time.Duration{
|
||||
0, // Bright, Ticks Duration, Relative power
|
||||
2, // 1, 2, 32µs, inf
|
||||
2, // 2, 4, 64µs, 200%
|
||||
4, // 3, 8, 128µs, 200%
|
||||
7, // 4, 15, 240µs, 187%
|
||||
13, // 5, 28, 448µs, 187%
|
||||
25, // 6, 53, 848µs, 189%
|
||||
49, // 7, 102, 1632µs, 192%
|
||||
97, // 8, 199, 3184µs, 195%
|
||||
}
|
||||
|
||||
// Source:
|
||||
// https://github.com/bbcmicrobit/micropython/blob/1252f887ddc790676bf9314a136bd17650b9c36c/source/microbit/microbitdisplay.cpp#L368
|
||||
const tickDuration = 16 * time.Microsecond
|
||||
|
||||
const (
|
||||
rowIdx = 0
|
||||
colIdx = 1
|
||||
)
|
||||
|
||||
// SetPixel modifies the internal buffer in a single pixel.
|
||||
//
|
||||
// The alpha channel of the RGBA is used to control the brightness of the LED
|
||||
// in 9 different levels.
|
||||
//
|
||||
// alpha channel, brightness level
|
||||
// 0 - 27, 9 (no transparency = highest brightness)
|
||||
// 28 - 55, 8
|
||||
// 56 - 83, 7
|
||||
// 84 - 111, 6
|
||||
// 112 - 139, 5
|
||||
// 140 - 167, 4
|
||||
// 168 - 195, 3
|
||||
// 196 - 223, 2
|
||||
// 224 - 251, 1 (very high transparency = lowest brightness)
|
||||
// 252 - 255, 0 (full transparency = off)
|
||||
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
||||
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
||||
return
|
||||
}
|
||||
col := x
|
||||
row := y
|
||||
if c.R != 0 || c.G != 0 || c.B != 0 {
|
||||
d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]] = true
|
||||
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = brightness(c.A)
|
||||
} else {
|
||||
d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]] = false
|
||||
d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// GetPixel returns if the specific pixels is enabled
|
||||
const (
|
||||
brightnessLevels = 9
|
||||
brightnessDivider = int8(255 / brightnessLevels)
|
||||
)
|
||||
|
||||
var (
|
||||
Brightness0 = color.RGBA{R: 0, G: 0, B: 0, A: 0}
|
||||
Brightness1 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*1}
|
||||
Brightness2 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*2}
|
||||
Brightness3 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*3}
|
||||
Brightness4 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*4}
|
||||
Brightness5 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*5}
|
||||
Brightness6 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*6}
|
||||
Brightness7 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*7}
|
||||
Brightness8 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*8}
|
||||
Brightness9 = color.RGBA{R: 255, G: 255, B: 255, A: 255 - uint8(brightnessDivider)*9}
|
||||
|
||||
BrightnessOff = Brightness0
|
||||
BrightnessFull = Brightness9
|
||||
)
|
||||
|
||||
func brightness(alpha uint8) int8 {
|
||||
return brightnessLevels - int8(alpha/uint8(brightnessDivider))
|
||||
}
|
||||
|
||||
// GetPixel returns if the specific pixels is enabled.
|
||||
func (d *Device) GetPixel(x int16, y int16) bool {
|
||||
if x < 0 || x >= 5 || y < 0 || y >= 5 {
|
||||
return false
|
||||
}
|
||||
return d.buffer[matrixRotations[d.rotation][y][x][0]][matrixRotations[d.rotation][y][x][1]]
|
||||
col := x
|
||||
row := y
|
||||
return d.buffer[matrixRotations[d.rotation][row][col][rowIdx]][matrixRotations[d.rotation][row][col][colIdx]] > 0
|
||||
}
|
||||
|
||||
const displayRefreshDelay = 8 * time.Millisecond
|
||||
|
||||
// Display sends the buffer (if any) to the screen.
|
||||
func (d *Device) Display() error {
|
||||
var displayBuffer [ledRows][ledCols]int8
|
||||
for row := 0; row < ledRows; row++ {
|
||||
for col := 0; col < ledCols; col++ {
|
||||
displayBuffer[row][col] = d.buffer[row][col]
|
||||
}
|
||||
}
|
||||
|
||||
for row := 0; row < ledRows; row++ {
|
||||
d.DisableAll()
|
||||
d.pin[ledCols+row].High()
|
||||
|
||||
for col := 0; col < ledCols; col++ {
|
||||
if displayBuffer[row][col] > 0 {
|
||||
d.pin[col].Low()
|
||||
}
|
||||
}
|
||||
|
||||
then := time.Now()
|
||||
var offset time.Duration = 0
|
||||
for _, ticks := range renderTimings {
|
||||
for time.Since(then).Nanoseconds() < int64(ticks*tickDuration+offset) {
|
||||
time.Sleep(offset / 10)
|
||||
}
|
||||
offset += ticks + tickDuration
|
||||
for col := 0; col < ledCols; col++ {
|
||||
displayBuffer[row][col]--
|
||||
if displayBuffer[row][col] <= 0 {
|
||||
d.pin[col].High()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(displayRefreshDelay)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearDisplay erases the internal buffer.
|
||||
func (d *Device) ClearDisplay() {
|
||||
for row := 0; row < ledRows; row++ {
|
||||
for col := 0; col < ledCols; col++ {
|
||||
d.buffer[row][col] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DisableAll disables all the LEDs without modifying the buffer.
|
||||
func (d *Device) DisableAll() {
|
||||
for i := 0; i < ledCols; i++ {
|
||||
d.pin[i].High()
|
||||
}
|
||||
for i := 0; i < ledRows; i++ {
|
||||
d.pin[ledCols+i].Low()
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAll enables all the LEDs without modifying the buffer.
|
||||
func (d *Device) EnableAll() {
|
||||
for i := 0; i < ledCols; i++ {
|
||||
d.pin[i].Low()
|
||||
}
|
||||
for i := 0; i < ledRows; i++ {
|
||||
d.pin[ledCols+i].High()
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the current size of the display.
|
||||
func (d *Device) Size() (w, h int16) {
|
||||
return 5, 5
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@ func (d Device) Connected() bool {
|
||||
}
|
||||
|
||||
// Configure sets up the device for communication.
|
||||
func (d Device) Configure() {
|
||||
d.bus.WriteRegister(uint8(d.Address), PWR_MGMT_1, []uint8{0})
|
||||
func (d Device) Configure() error {
|
||||
return d.bus.WriteRegister(uint8(d.Address), PWR_MGMT_1, []uint8{0})
|
||||
}
|
||||
|
||||
// ReadAcceleration reads the current acceleration from the device and returns
|
||||
|
||||
@@ -2,6 +2,8 @@ package http
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -211,3 +213,41 @@ func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response,
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
return c.Do(req)
|
||||
}
|
||||
|
||||
// PostForm issues a POST to the specified URL, with data's keys and
|
||||
// values URL-encoded as the request body.
|
||||
//
|
||||
// The Content-Type header is set to application/x-www-form-urlencoded.
|
||||
// To set other headers, use NewRequest and DefaultClient.Do.
|
||||
//
|
||||
// When err is nil, resp always contains a non-nil resp.Body.
|
||||
// Caller should close resp.Body when done reading from it.
|
||||
//
|
||||
// PostForm is a wrapper around DefaultClient.PostForm.
|
||||
//
|
||||
// See the Client.Do method documentation for details on how redirects
|
||||
// are handled.
|
||||
//
|
||||
// To make a request with a specified context.Context, use NewRequestWithContext
|
||||
// and DefaultClient.Do.
|
||||
func PostForm(url string, data url.Values) (resp *Response, err error) {
|
||||
return DefaultClient.PostForm(url, data)
|
||||
}
|
||||
|
||||
// PostForm issues a POST to the specified URL,
|
||||
// with data's keys and values URL-encoded as the request body.
|
||||
//
|
||||
// The Content-Type header is set to application/x-www-form-urlencoded.
|
||||
// To set other headers, use NewRequest and Client.Do.
|
||||
//
|
||||
// When err is nil, resp always contains a non-nil resp.Body.
|
||||
// Caller should close resp.Body when done reading from it.
|
||||
//
|
||||
// See the Client.Do method documentation for details on how redirects
|
||||
// are handled.
|
||||
//
|
||||
// To make a request with a specified context.Context, use NewRequestWithContext
|
||||
// and Client.Do.
|
||||
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
|
||||
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||
}
|
||||
|
||||
+140
-123
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -25,17 +26,43 @@ func (c *Client) Do(req *Request) (*Response, error) {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
transport := c.Transport
|
||||
if transport == nil {
|
||||
transport = DefaultTransport
|
||||
}
|
||||
res, err := transport.RoundTrip(req)
|
||||
|
||||
if c.Jar != nil {
|
||||
if rc := res.Cookies(); len(rc) > 0 {
|
||||
c.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
type Transport struct {
|
||||
}
|
||||
|
||||
var DefaultTransport RoundTripper
|
||||
|
||||
func init() {
|
||||
DefaultTransport = &Transport{}
|
||||
}
|
||||
|
||||
func (t *Transport) RoundTrip(req *Request) (*Response, error) {
|
||||
switch req.URL.Scheme {
|
||||
case "http":
|
||||
return c.doHTTP(req)
|
||||
return t.doHTTP(req)
|
||||
case "https":
|
||||
return c.doHTTPS(req)
|
||||
return t.doHTTPS(req)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid schemer : %s", req.URL.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) doHTTP(req *Request) (*Response, error) {
|
||||
func (t *Transport) doHTTP(req *Request) (*Response, error) {
|
||||
// make TCP connection
|
||||
ip := net.ParseIP(req.URL.Hostname())
|
||||
port := 80
|
||||
@@ -106,10 +133,10 @@ func (c *Client) doHTTP(req *Request) (*Response, error) {
|
||||
|
||||
}
|
||||
|
||||
return c.doResp(conn, req)
|
||||
return t.doResp(conn, req)
|
||||
}
|
||||
|
||||
func (c *Client) doHTTPS(req *Request) (*Response, error) {
|
||||
func (t *Transport) doHTTPS(req *Request) (*Response, error) {
|
||||
conn, err := tls.Dial("tcp", req.URL.Host, nil)
|
||||
retry := 0
|
||||
for ; err != nil; conn, err = tls.Dial("tcp", req.URL.Host, nil) {
|
||||
@@ -167,141 +194,131 @@ func (c *Client) doHTTPS(req *Request) (*Response, error) {
|
||||
|
||||
}
|
||||
|
||||
return c.doResp(conn, req)
|
||||
return t.doResp(conn, req)
|
||||
}
|
||||
|
||||
func (c *Client) doResp(conn net.Conn, req *Request) (*Response, error) {
|
||||
func (t *Transport) doResp(conn net.Conn, req *Request) (*Response, error) {
|
||||
resp := &Response{
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
|
||||
// Header
|
||||
var scanner *bufio.Scanner
|
||||
cont := true
|
||||
ofs := 0
|
||||
remain := int64(0)
|
||||
for cont {
|
||||
for n, err := conn.Read(buf[ofs:]); n > 0; n, err = conn.Read(buf[ofs:]) {
|
||||
if err != nil {
|
||||
println("Read error: " + err.Error())
|
||||
} else {
|
||||
// Take care of the case where "\r\n\r\n" is on the boundary of a buffer
|
||||
start := ofs
|
||||
if start > 3 {
|
||||
start -= 3
|
||||
}
|
||||
idx := bytes.Index(buf[start:ofs+n], []byte("\r\n\r\n"))
|
||||
if idx == -1 {
|
||||
ofs += n
|
||||
continue
|
||||
}
|
||||
idx += start + 4
|
||||
br := bufio.NewReader(conn)
|
||||
tp := textproto.NewReader(br)
|
||||
|
||||
scanner = bufio.NewScanner(bytes.NewReader(buf[0 : ofs+n]))
|
||||
if resp.Status == "" && scanner.Scan() {
|
||||
status := strings.SplitN(scanner.Text(), " ", 2)
|
||||
if len(status) != 2 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid status : %q", scanner.Text())
|
||||
}
|
||||
resp.Proto = status[0]
|
||||
fmt.Sscanf(status[0], "HTTP/%d.%d", &resp.ProtoMajor, &resp.ProtoMinor)
|
||||
|
||||
resp.Status = status[1]
|
||||
fmt.Sscanf(status[1], "%d", &resp.StatusCode)
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
if text == "" {
|
||||
// end of header
|
||||
if idx < n+ofs {
|
||||
ofs = ofs + n - idx
|
||||
for i := 0; i < ofs; i++ {
|
||||
buf[i] = buf[i+idx]
|
||||
}
|
||||
} else {
|
||||
ofs = 0
|
||||
}
|
||||
break
|
||||
} else {
|
||||
header := strings.SplitN(text, ": ", 2)
|
||||
if len(header) != 2 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid header : %q", text)
|
||||
}
|
||||
if resp.Header.Get(header[0]) == "" {
|
||||
resp.Header.Set(header[0], header[1])
|
||||
} else {
|
||||
resp.Header.Add(header[0], header[1])
|
||||
}
|
||||
|
||||
if strings.ToLower(header[0]) == "content-length" {
|
||||
resp.ContentLength, err = strconv.ParseInt(header[1], 10, 64)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
remain = resp.ContentLength
|
||||
}
|
||||
}
|
||||
}
|
||||
cont = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Body
|
||||
remain -= int64(ofs)
|
||||
if remain <= 0 {
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:ofs]))
|
||||
if c.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
c.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
return resp, conn.Close()
|
||||
}
|
||||
|
||||
cont = true
|
||||
lastRequestTime := time.Now()
|
||||
for cont {
|
||||
for {
|
||||
end := ofs + 0x400
|
||||
if len(buf) < end {
|
||||
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", end)
|
||||
}
|
||||
n, err := conn.Read(buf[ofs : ofs+0x400])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
for {
|
||||
line, err := tp.ReadLine()
|
||||
if err != nil {
|
||||
if err == io.ErrNoProgress {
|
||||
// default: no timeout
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status := strings.SplitN(line, " ", 2)
|
||||
if len(status) != 2 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("invalid status : %q", line)
|
||||
}
|
||||
resp.Proto = status[0]
|
||||
fmt.Sscanf(status[0], "HTTP/%d.%d", &resp.ProtoMajor, &resp.ProtoMinor)
|
||||
|
||||
resp.Status = status[1]
|
||||
fmt.Sscanf(status[1], "%d", &resp.StatusCode)
|
||||
break
|
||||
}
|
||||
|
||||
m, err := tp.ReadMIMEHeader()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range m {
|
||||
//fmt.Printf("%s: %s\n", k, v)
|
||||
|
||||
if strings.ToLower(k) == "content-length" {
|
||||
resp.ContentLength, err = strconv.ParseInt(v[0], 10, 64)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
} else {
|
||||
ofs += n
|
||||
remain -= int64(n)
|
||||
if remain <= 0 {
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:ofs]))
|
||||
cont = false
|
||||
break
|
||||
}
|
||||
if time.Now().Sub(lastRequestTime).Milliseconds() >= 1000 {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("time out")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Header.Get(k) == "" {
|
||||
resp.Header.Set(k, v[0])
|
||||
v = v[1:]
|
||||
}
|
||||
for _, vv := range v {
|
||||
resp.Header.Add(k, vv)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if c.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
c.Jar.SetCookies(req.URL, rc)
|
||||
if resp.Header.Get("Transfer-Encoding") == "chunked" {
|
||||
// chunked
|
||||
cur := 0
|
||||
end := 0
|
||||
for {
|
||||
length := 0
|
||||
if len(buf) < cur+6 {
|
||||
// This is not a very accurate check, but in many cases it should be fine.
|
||||
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", cur+6)
|
||||
}
|
||||
for i := 0; ; i++ {
|
||||
buf[cur+i], err = br.ReadByte()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
length = i + 1
|
||||
if i > 1 && buf[cur+i-1] == '\r' && buf[cur+i] == '\n' {
|
||||
break
|
||||
}
|
||||
}
|
||||
//fmt.Printf("cur:%d length:%d\n", cur, length)
|
||||
|
||||
size, err := strconv.ParseInt(string(buf[cur:cur+length-2]), 16, 64)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
//cur += length
|
||||
//fmt.Printf("cur:%d length:%d size:%d\n", cur, length, size)
|
||||
|
||||
end = cur + int(size) + 2 // size + 2 (\r\n)
|
||||
if len(buf) < end {
|
||||
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", end)
|
||||
}
|
||||
for i := 0; i < int(size)+2; i++ {
|
||||
buf[cur+i], err = br.ReadByte()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
cur += int(size)
|
||||
|
||||
if size == 0 {
|
||||
end = end - 2
|
||||
break
|
||||
}
|
||||
}
|
||||
//fmt.Printf("%q\n", buf[:end])
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:end]))
|
||||
} else {
|
||||
end := int(resp.ContentLength)
|
||||
if len(buf) < end {
|
||||
return nil, fmt.Errorf("slice out of range : use http.SetBuf() to change the allocation to %d bytes or more", end)
|
||||
}
|
||||
for i := 0; i < end; i++ {
|
||||
buf[i], err = br.ReadByte()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
resp.Body = io.NopCloser(bytes.NewReader(buf[:end]))
|
||||
}
|
||||
|
||||
return resp, conn.Close()
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// Package qmi8658c provides a driver for the QMI8658C accelerometer and gyroscope
|
||||
// made by QST Solutions.
|
||||
//
|
||||
// Datasheet:
|
||||
// https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%89QMI8658C%20datasheet%20rev%200.9.pdf
|
||||
package qmi8656c
|
||||
|
||||
import "tinygo.org/x/drivers"
|
||||
|
||||
// Device wraps the I2C connection to the QMIC8658 sensor
|
||||
type Device struct {
|
||||
bus drivers.I2C
|
||||
Address uint16
|
||||
AccLsbDiv uint16
|
||||
GyroLsbDiv uint16
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// SPI Config
|
||||
SPIMode byte // One of SPI_X_WIRE
|
||||
SPIEndian byte // One of SPI_XXX_ENDIAN
|
||||
SPIAutoInc byte // One of SPI_NOT_AUTO_INC or SPI_AUTO_INC
|
||||
// Accelerometer
|
||||
AccEnable byte // One of ACC_ENABLE or ACC_DISABLE
|
||||
AccScale byte // One of ACC_XG
|
||||
AccRate byte // One of ACC_XX_YYHZ
|
||||
AccLowPass byte // One of ACC_LOW_PASS_X
|
||||
// Gyro
|
||||
GyroEnable byte // One of GYRO_X_ENABLE or GYRO_DISABLE
|
||||
GyroScale byte // One of GYRO_XDPS
|
||||
GyroRate byte // One of GYRO_X_YHZ
|
||||
GyroLowPass byte // One of GYRO_LOW_PASS_X
|
||||
}
|
||||
|
||||
// Create a new device with the I2C passed, correct address and nil values for
|
||||
// AccLsbDiv and GyroLsbDiv, which will be corrected based on the config.
|
||||
func New(bus drivers.I2C) Device {
|
||||
return Device{
|
||||
bus,
|
||||
Address,
|
||||
1,
|
||||
1,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the device is connected by calling WHO_AM_I and checking the
|
||||
// default identifier.
|
||||
func (d *Device) Connected() bool {
|
||||
data := []byte{0}
|
||||
d.ReadRegister(WHO_AM_I, data)
|
||||
return data[0] == IDENTIFIER
|
||||
}
|
||||
|
||||
// Create a basic default configuration that works with the "WaveShare RP2040
|
||||
// Round LCD 1.28in".
|
||||
func DefaultConfig() (cfg Config) {
|
||||
return Config{
|
||||
SPIMode: SPI_4_WIRE,
|
||||
SPIEndian: SPI_BIG_ENDIAN,
|
||||
SPIAutoInc: SPI_AUTO_INC,
|
||||
AccEnable: ACC_ENABLE,
|
||||
AccScale: ACC_8G,
|
||||
AccRate: ACC_NORMAL_1000HZ,
|
||||
AccLowPass: ACC_LOW_PASS_2_62,
|
||||
GyroEnable: GYRO_FULL_ENABLE,
|
||||
GyroScale: GYRO_512DPS,
|
||||
GyroRate: GYRO_1000HZ,
|
||||
GyroLowPass: GYRO_LOW_PASS_2_62,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user has defined a desired configuration, if not uses the
|
||||
// DefaultConfig, then defines the AccLsbDiv and GyroLsbDiv based on the
|
||||
// configurations and, finally, send the commands and configure the IMU.
|
||||
func (d *Device) Configure(cfg Config) {
|
||||
if cfg == (Config{}) {
|
||||
cfg = DefaultConfig()
|
||||
}
|
||||
var val uint16
|
||||
// Setting accelerometer LSB
|
||||
switch cfg.AccScale {
|
||||
case ACC_2G:
|
||||
d.AccLsbDiv = 1 << 14
|
||||
case ACC_4G:
|
||||
d.AccLsbDiv = 1 << 13
|
||||
case ACC_8G:
|
||||
d.AccLsbDiv = 1 << 12
|
||||
case ACC_16G:
|
||||
d.AccLsbDiv = 1 << 11
|
||||
default:
|
||||
d.AccLsbDiv = 1 << 12
|
||||
}
|
||||
// Setting gyro LSB
|
||||
switch cfg.GyroScale {
|
||||
case GYRO_16DPS:
|
||||
d.GyroLsbDiv = 2048
|
||||
case GYRO_32DPS:
|
||||
d.GyroLsbDiv = 1024
|
||||
case GYRO_64DPS:
|
||||
d.GyroLsbDiv = 512
|
||||
case GYRO_128DPS:
|
||||
d.GyroLsbDiv = 256
|
||||
case GYRO_256DPS:
|
||||
d.GyroLsbDiv = 128
|
||||
case GYRO_512DPS:
|
||||
d.GyroLsbDiv = 64
|
||||
case GYRO_1024DPS:
|
||||
d.GyroLsbDiv = 32
|
||||
case GYRO_2048DPS:
|
||||
d.GyroLsbDiv = 16
|
||||
default:
|
||||
d.GyroLsbDiv = 64
|
||||
}
|
||||
// SPI Modes
|
||||
val = uint16((cfg.SPIMode | cfg.SPIEndian | cfg.SPIAutoInc))
|
||||
d.WriteRegister(CTRL1, val)
|
||||
// Accelerometer config
|
||||
val = uint16(cfg.AccScale | cfg.AccRate)
|
||||
d.WriteRegister(CTRL2, val)
|
||||
// Gyro config
|
||||
val = uint16(cfg.GyroScale | cfg.GyroRate)
|
||||
d.WriteRegister(CTRL3, val)
|
||||
// Sensor DSP config
|
||||
val = uint16(cfg.GyroLowPass | cfg.AccLowPass)
|
||||
d.WriteRegister(CTRL5, val)
|
||||
// Sensors config
|
||||
val = uint16(cfg.GyroEnable | cfg.AccEnable)
|
||||
d.WriteRegister(CTRL7, val)
|
||||
}
|
||||
|
||||
// Read the acceleration from the sensor, the values returned are in mg
|
||||
// (milli gravity), which means that 1000 = 1g.
|
||||
func (d *Device) ReadAcceleration() (x int32, y int32, z int32) {
|
||||
data := make([]byte, 6)
|
||||
raw := make([]int32, 3)
|
||||
d.ReadRegister(ACC_XOUT_L, data)
|
||||
for i := range raw {
|
||||
raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
|
||||
if raw[i] >= 32767 {
|
||||
raw[i] = raw[i] - 65535
|
||||
}
|
||||
}
|
||||
x = -raw[0] * 1000 / int32(d.AccLsbDiv)
|
||||
y = -raw[1] * 1000 / int32(d.AccLsbDiv)
|
||||
z = -raw[2] * 1000 / int32(d.AccLsbDiv)
|
||||
return x, y, z
|
||||
}
|
||||
|
||||
// Read the rotation from the sensor, the values returned are in mdeg/sec
|
||||
// (milli degress/second), which means that a full rotation is 360000.
|
||||
func (d *Device) ReadRotation() (x int32, y int32, z int32) {
|
||||
data := make([]byte, 6)
|
||||
raw := make([]int32, 3)
|
||||
d.ReadRegister(GYRO_XOUT_L, data)
|
||||
for i := range raw {
|
||||
raw[i] = int32(uint16(data[(2*i+1)])<<8 | uint16(data[i]))
|
||||
if raw[i] >= 32767 {
|
||||
raw[i] = raw[i] - 65535
|
||||
}
|
||||
}
|
||||
x = raw[0] * 1000 / int32(d.GyroLsbDiv)
|
||||
y = raw[1] * 1000 / int32(d.GyroLsbDiv)
|
||||
z = raw[2] * 1000 / int32(d.GyroLsbDiv)
|
||||
return x, y, z
|
||||
}
|
||||
|
||||
// Read the temperature from the sensor, the values returned are in
|
||||
// millidegrees Celsius.
|
||||
func (d *Device) ReadTemperature() (int32, error) {
|
||||
data := make([]byte, 2)
|
||||
err := d.ReadRegister(TEMP_OUT_L, data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
raw := uint16(data[1])<<8 | uint16(data[0])
|
||||
t := int32(raw) * 1000 / 256
|
||||
return t, err
|
||||
}
|
||||
|
||||
// Convenience method to read the register and avoid repetition.
|
||||
func (d *Device) ReadRegister(reg uint8, buf []byte) error {
|
||||
return d.bus.ReadRegister(uint8(d.Address), reg, buf)
|
||||
}
|
||||
|
||||
// Convenience method to write the register and avoid repetition.
|
||||
func (d *Device) WriteRegister(reg uint8, v uint16) error {
|
||||
data := []byte{byte(v)}
|
||||
err := d.bus.WriteRegister(uint8(d.Address), reg, data)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package qmi8656c
|
||||
|
||||
// The I2C address that the sensor listens to.
|
||||
const Address = 0x6B
|
||||
|
||||
const (
|
||||
// Who am I
|
||||
WHO_AM_I = 0x00
|
||||
IDENTIFIER = 0x05
|
||||
|
||||
// Configuration registers
|
||||
CTRL1 = 0x02 // SPI Modes
|
||||
CTRL2 = 0x03 // Accelerometer config
|
||||
CTRL3 = 0x04 // Gyro config
|
||||
CTRL4 = 0x05 // Magnetometer config (ignored)
|
||||
CTRL5 = 0x06 // Sensor DSP config
|
||||
CTRL6 = 0x07 // Motion on Demand (ignored)
|
||||
CTRL7 = 0x08 // Sensors config
|
||||
|
||||
// Interface config (CTRL1)
|
||||
SPI_4_WIRE = 0x00
|
||||
SPI_3_WIRE = 0x80
|
||||
SPI_NOT_AUTO_INC = 0x00
|
||||
SPI_AUTO_INC = 0x40
|
||||
SPI_LITTLE_ENDIAN = 0x00
|
||||
SPI_BIG_ENDIAN = 0x20
|
||||
|
||||
// Accelerometer scale config (CTRL2-H)
|
||||
ACC_SELF_TEST = 0x80
|
||||
|
||||
// Accelerometer scale config (CTRL2-H)
|
||||
ACC_2G = 0x00
|
||||
ACC_4G = 0x10
|
||||
ACC_8G = 0x20
|
||||
ACC_16G = 0x30
|
||||
|
||||
// Accelerometer output data rate (ODR) config (CTRL2-L)
|
||||
ACC_NORMAL_8000HZ = 0x00
|
||||
ACC_NORMAL_4000HZ = 0x01
|
||||
ACC_NORMAL_2000HZ = 0x02
|
||||
ACC_NORMAL_1000HZ = 0x03
|
||||
ACC_NORMAL_500HZ = 0x04
|
||||
ACC_NORMAL_250HZ = 0x05
|
||||
ACC_NORMAL_125HZ = 0x06
|
||||
ACC_NORMAL_62HZ = 0x07
|
||||
ACC_NORMAL_31HZ = 0x08
|
||||
ACC_LOW_POWER_128HZ = 0x0C
|
||||
ACC_LOW_POWER_21HZ = 0x0D
|
||||
ACC_LOW_POWER_11HZ = 0x0E
|
||||
ACC_LOW_POWER_3HZ = 0x0F
|
||||
|
||||
// Gyro scale config (CTRL3-H)
|
||||
GYRO_SELF_TEST = 0x80
|
||||
|
||||
// Gyro scale config (CTRL3-H)
|
||||
GYRO_16DPS = 0x00
|
||||
GYRO_32DPS = 0x10
|
||||
GYRO_64DPS = 0x20
|
||||
GYRO_128DPS = 0x30
|
||||
GYRO_256DPS = 0x40
|
||||
GYRO_512DPS = 0x50
|
||||
GYRO_1024DPS = 0x60
|
||||
GYRO_2048DPS = 0x70
|
||||
|
||||
// Gyro output data rate (ODR) config (CTRL3-L)
|
||||
GYRO_8000HZ = 0x00
|
||||
GYRO_4000HZ = 0x01
|
||||
GYRO_2000HZ = 0x02
|
||||
GYRO_1000HZ = 0x03
|
||||
GYRO_500HZ = 0x04
|
||||
GYRO_250HZ = 0x05
|
||||
GYRO_125HZ = 0x06
|
||||
GYRO_62HZ = 0x07
|
||||
GYRO_31HZ = 0x08
|
||||
|
||||
// Gyro DSP config (CTRL4-H)
|
||||
GYRO_LOW_PASS_OFF = 0x00 // Disabled
|
||||
GYRO_LOW_PASS_2_62 = 0x10 // 2.62% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_3_59 = 0x30 // 3.59% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_5_32 = 0x50 // 5.32% of output data rate (ODR)
|
||||
GYRO_LOW_PASS_14 = 0x70 // 14% of output data rate (ODR)
|
||||
|
||||
// Accelerometer DSP config (CTRL4-L)
|
||||
ACC_LOW_PASS_OFF = 0x00 // Disabled
|
||||
ACC_LOW_PASS_2_62 = 0x01 // 2.62% of output data rate (ODR)
|
||||
ACC_LOW_PASS_3_59 = 0x03 // 3.59% of output data rate (ODR)
|
||||
ACC_LOW_PASS_5_32 = 0x05 // 5.32% of output data rate (ODR)
|
||||
ACC_LOW_PASS_14 = 0x07 // 14% of output data rate (ODR)
|
||||
|
||||
// Motion on demand (MOD) (CTRL6)
|
||||
MOD_DISABLE = 0x00
|
||||
MOD_ENABLE = 0x80
|
||||
|
||||
// Enable sensors (CTRL7)
|
||||
GYRO_DISABLE = 0x00
|
||||
GYRO_FULL_ENABLE = 0x02
|
||||
GYRO_SNOOZE_ENABLE = 0x12
|
||||
ACC_DISABLE = 0x00
|
||||
ACC_ENABLE = 0x01
|
||||
|
||||
// Timestamp Outputs Register Adresses
|
||||
TIMESTAMP_OUT_L = 0x30
|
||||
TIMESTAMP_OUT_M = 0x31
|
||||
TIMESTAMP_OUT_H = 0x32
|
||||
|
||||
// Temperature Outputs Register Adresses
|
||||
TEMP_OUT_L = 0x33
|
||||
TEMP_OUT_H = 0x34
|
||||
|
||||
// Acceleration Outputs Register Adresses
|
||||
ACC_XOUT_L = 0x35
|
||||
ACC_XOUT_H = 0x36
|
||||
ACC_YOUT_L = 0x37
|
||||
ACC_YOUT_H = 0x38
|
||||
ACC_ZOUT_L = 0x39
|
||||
ACC_ZOUT_H = 0x3A
|
||||
|
||||
// Angular Rate Outputs Register Adresses
|
||||
GYRO_XOUT_L = 0x3B
|
||||
GYRO_XOUT_H = 0x3C
|
||||
GYRO_YOUT_L = 0x3D
|
||||
GYRO_YOUT_H = 0x3E
|
||||
GYRO_ZOUT_L = 0x3F
|
||||
GYRO_ZOUT_H = 0x40
|
||||
|
||||
// Quaternion Outputs Register Adresses
|
||||
DELTA_QUAT_WOUT_L = 0x49
|
||||
DELTA_QUAT_WOUT_H = 0x4A
|
||||
DELTA_QUAT_XOUT_L = 0x4B
|
||||
DELTA_QUAT_XOUT_H = 0x4C
|
||||
DELTA_QUAT_YOUT_L = 0x4D
|
||||
DELTA_QUAT_YOUT_H = 0x4E
|
||||
DELTA_QUAT_ZOUT_L = 0x4F
|
||||
DELTA_QUAT_ZOUT_H = 0x50
|
||||
|
||||
// Delta Velocity Outputs Register Adresses
|
||||
DELTA_VEL_XOUT_L = 0x51
|
||||
DELTA_VEL_XOUT_H = 0x52
|
||||
DELTA_VEL_YOUT_L = 0x53
|
||||
DELTA_VEL_YOUT_H = 0x54
|
||||
DELTA_VEL_ZOUT_L = 0x55
|
||||
DELTA_VEL_ZOUT_H = 0x56
|
||||
)
|
||||
@@ -71,10 +71,13 @@ func (d *Driver) ConnectTCPSocket(addr, port string) error {
|
||||
name[6] = byte(ipaddr[2])
|
||||
name[7] = byte(ipaddr[3])
|
||||
|
||||
_, err = d.Rpc_lwip_connect(socket, name, uint32(len(name)))
|
||||
result, err := d.Rpc_lwip_connect(socket, name, uint32(len(name)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result == -1 {
|
||||
return fmt.Errorf("failed to connect to %d.%d.%d.%d port %s", addr[0], addr[1], addr[2], addr[3], port)
|
||||
}
|
||||
|
||||
readset := []byte{}
|
||||
writeset := []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
@@ -341,8 +344,11 @@ func (d *Driver) ReadSocket(b []byte) (n int, err error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if nn < 0 {
|
||||
return 0, fmt.Errorf("error %d", n)
|
||||
if nn == -76 {
|
||||
// no data
|
||||
return 0, nil
|
||||
} else if nn < 0 {
|
||||
return 0, fmt.Errorf("error %d", nn)
|
||||
} else if nn == 0 || nn == -30848 {
|
||||
return 0, d.DisconnectSocket()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build pybadge
|
||||
// +build pybadge
|
||||
|
||||
package shifter
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
package ssd1289
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build stm32wlx
|
||||
// +build stm32wlx
|
||||
|
||||
package sx126x
|
||||
|
||||
|
||||
+11
-4
@@ -19,10 +19,11 @@ type DistanceMode uint8
|
||||
type RangeStatus uint8
|
||||
|
||||
type rangingData struct {
|
||||
mm uint16
|
||||
status RangeStatus
|
||||
signalRateMCPS int32 //MCPS : Mega Count Per Second
|
||||
ambientRateMCPS int32
|
||||
mm uint16
|
||||
status RangeStatus
|
||||
signalRateMCPS int32 //MCPS : Mega Count Per Second
|
||||
ambientRateMCPS int32
|
||||
effectiveSPADCount uint16
|
||||
}
|
||||
|
||||
type resultBuffer struct {
|
||||
@@ -337,6 +338,11 @@ func (d *Device) AmbientRate() int32 {
|
||||
return d.rangingData.ambientRateMCPS
|
||||
}
|
||||
|
||||
// EffectiveSPADCount returns the effective number of SPADs
|
||||
func (d *Device) EffectiveSPADCount() uint16 {
|
||||
return d.rangingData.effectiveSPADCount
|
||||
}
|
||||
|
||||
// getRangingData stores in the buffer the ranging data
|
||||
func (d *Device) getRangingData() {
|
||||
d.rangingData.mm = uint16((uint32(d.results.mmCrosstalkSD0)*2011 + 0x0400) / 0x0800)
|
||||
@@ -384,6 +390,7 @@ func (d *Device) getRangingData() {
|
||||
|
||||
d.rangingData.signalRateMCPS = 1000000 * int32(d.results.signalRateCrosstalkMCPSSD0) / (1 << 7)
|
||||
d.rangingData.ambientRateMCPS = 1000000 * int32(d.results.ambientRateMCPSSD0) / (1 << 7)
|
||||
d.rangingData.effectiveSPADCount = d.results.effectiveSPADCount
|
||||
}
|
||||
|
||||
// setupManualCalibration configures the manual calibration
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
package wifinina
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/net/http"
|
||||
)
|
||||
|
||||
func (d *Device) ListenAndServe(addr string, handler http.Handler) error {
|
||||
|
||||
if handler == nil {
|
||||
handler = http.DefaultServeMux
|
||||
}
|
||||
|
||||
server := newServer(d, handler)
|
||||
|
||||
if err := server.listen(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
client, err := server.accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := client.handleHTTP(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = client.stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Server stuff
|
||||
|
||||
type server struct {
|
||||
device *Device
|
||||
handler http.Handler
|
||||
sock uint8
|
||||
clients map[uint8]*client // keyed by client sock
|
||||
}
|
||||
|
||||
func newServer(device *Device, handler http.Handler) *server {
|
||||
return &server{
|
||||
device: device,
|
||||
handler: handler,
|
||||
sock: NoSocketAvail,
|
||||
clients: make(map[uint8]*client),
|
||||
}
|
||||
}
|
||||
|
||||
func portFromAddr(addr string) (uint16, error) {
|
||||
// ignore anything before ':' in address
|
||||
i := strings.LastIndex(addr, ":")
|
||||
if i < 0 {
|
||||
return 0, fmt.Errorf("Missing ':' in address")
|
||||
}
|
||||
v, err := strconv.ParseUint(addr[i+1:], 10, 16)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("Parsing address err: %s", err)
|
||||
}
|
||||
return uint16(v), nil
|
||||
}
|
||||
|
||||
func (s *server) listen(addr string) error {
|
||||
port, err := portFromAddr(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting port err: %s", err)
|
||||
}
|
||||
|
||||
s.sock, err = s.device.GetSocket()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting socket err: %s", err)
|
||||
}
|
||||
if s.sock == NoSocketAvail {
|
||||
return fmt.Errorf("No socket available")
|
||||
}
|
||||
|
||||
return s.device.StartServer(port, s.sock, ProtoModeTCP)
|
||||
}
|
||||
|
||||
func (s *server) availServer(sock uint8) (uint8, error) {
|
||||
d := s.device
|
||||
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if err := d.waitForChipSelect(); err != nil {
|
||||
d.spiChipDeselect()
|
||||
return NoSocketAvail, fmt.Errorf("Wait for CS: %s", err)
|
||||
}
|
||||
|
||||
l := d.sendCmd(CmdAvailDataTCP, 1)
|
||||
l += d.sendParam8(sock, true)
|
||||
d.addPadding(l)
|
||||
d.spiChipDeselect()
|
||||
_, err := d.waitRspCmd1(CmdAvailDataTCP)
|
||||
if err != nil {
|
||||
return NoSocketAvail, fmt.Errorf("Wait for Rsp: %s", err)
|
||||
}
|
||||
newsock, err := d.getUint16(2, err)
|
||||
if err != nil {
|
||||
return NoSocketAvail, fmt.Errorf("getUint16: %s", err)
|
||||
}
|
||||
return uint8(newsock >> 8), nil
|
||||
}
|
||||
|
||||
func (s *server) accept() (*client, error) {
|
||||
|
||||
for {
|
||||
sock, err := s.availServer(s.sock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("accept: %w", err)
|
||||
}
|
||||
|
||||
if sock == NoSocketAvail {
|
||||
continue
|
||||
}
|
||||
|
||||
if client, ok := s.clients[sock]; ok {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
client := newClient(s, sock)
|
||||
s.clients[sock] = client
|
||||
|
||||
return client, nil
|
||||
}
|
||||
}
|
||||
|
||||
// client stuff
|
||||
|
||||
type client struct {
|
||||
server *server
|
||||
device *Device
|
||||
sock uint8
|
||||
|
||||
// HTTP request
|
||||
req *http.Request
|
||||
reqBuf bytes.Buffer
|
||||
readBuf [256]byte
|
||||
|
||||
// HTTP response
|
||||
res bytes.Buffer
|
||||
resHdr http.Header
|
||||
resBuf bytes.Buffer
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func newClient(server *server, sock uint8) *client {
|
||||
return &client{
|
||||
server: server,
|
||||
device: server.device,
|
||||
sock: sock,
|
||||
}
|
||||
}
|
||||
|
||||
// client implements http.ResponseWriter interface
|
||||
|
||||
func (c *client) Header() http.Header {
|
||||
return c.resHdr
|
||||
}
|
||||
|
||||
func (c *client) Write(b []byte) (int, error) {
|
||||
return c.resBuf.Write(b)
|
||||
}
|
||||
|
||||
func (c *client) WriteHeader(statusCode int) {
|
||||
c.statusCode = statusCode
|
||||
}
|
||||
|
||||
func (c *client) status() uint8 {
|
||||
d := c.device
|
||||
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if err := d.waitForChipSelect(); err != nil {
|
||||
d.spiChipDeselect()
|
||||
return 0
|
||||
}
|
||||
|
||||
l := d.sendCmd(CmdGetClientStateTCP, 1)
|
||||
l += d.sendParam8(c.sock, true)
|
||||
d.addPadding(l)
|
||||
d.spiChipDeselect()
|
||||
_, err := d.waitRspCmd1(CmdGetClientStateTCP)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
status, err := d.getUint8(1, err)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func (c *client) stop() error {
|
||||
if err := c.device.StopClient(c.sock); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait max 5 secs for the connection to close
|
||||
for i := 0; i < 50 && c.status() != TCPStateClosed; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
if c.status() != TCPStateClosed {
|
||||
return fmt.Errorf("stop failed, client status %x", c.status())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) handleHTTP() error {
|
||||
|
||||
c.reqBuf.Reset()
|
||||
end := -1
|
||||
|
||||
// read the request
|
||||
|
||||
start := time.Now()
|
||||
for {
|
||||
|
||||
// TODO use Server.ReadTimeout
|
||||
if time.Since(start) > 1*time.Second {
|
||||
return fmt.Errorf("ReadTimeout")
|
||||
}
|
||||
|
||||
n, err := c.device.GetDataBuf(c.sock, c.readBuf[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetDataBuf: %s", err)
|
||||
}
|
||||
if n == 0 {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
c.reqBuf.Write(c.readBuf[:n])
|
||||
bytesSoFar := c.reqBuf.Bytes()
|
||||
|
||||
if end == -1 {
|
||||
|
||||
// search for blank line marking end-of-header
|
||||
end = bytes.Index(bytesSoFar, []byte("\r\n\r\n"))
|
||||
if end == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// found end-of-header; parse header
|
||||
end += len([]byte("\r\n\r\n"))
|
||||
bufio := bufio.NewReader(bytes.NewReader(bytesSoFar[:end]))
|
||||
c.req, err = http.ReadRequest(bufio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
v := c.req.Header.Get("Content-Length")
|
||||
if v == "" {
|
||||
// no body; we're done reading request
|
||||
break
|
||||
}
|
||||
|
||||
length, _ := strconv.Atoi(v)
|
||||
if end+length == len(bytesSoFar) {
|
||||
// got the whole body
|
||||
body := bytes.NewReader(bytesSoFar[end:])
|
||||
c.req.Body = io.NopCloser(body)
|
||||
break
|
||||
}
|
||||
|
||||
// continue reading request...
|
||||
}
|
||||
|
||||
// build the response
|
||||
|
||||
c.statusCode = 200
|
||||
|
||||
c.resHdr = http.Header{}
|
||||
c.resHdr.Add(`Content-Type`, `text/html; charset=UTF-8`)
|
||||
c.resHdr.Add(`Connection`, `close`)
|
||||
|
||||
c.resBuf.Reset()
|
||||
c.server.handler.ServeHTTP(c, c.req)
|
||||
|
||||
c.resHdr.Add(`Content-Length`, fmt.Sprintf("%d", c.resBuf.Len()))
|
||||
|
||||
c.res.Reset()
|
||||
fmt.Fprintf(&c.res, "HTTP/1.1 %d %s\r\n", c.statusCode,
|
||||
http.StatusText(c.statusCode))
|
||||
if err := c.resHdr.Write(&c.res); err != nil {
|
||||
return err
|
||||
}
|
||||
c.res.WriteByte(byte('\n'))
|
||||
c.res.Write(c.resBuf.Bytes())
|
||||
|
||||
// send the response
|
||||
|
||||
written, err := c.device.SendData(c.res.Bytes(), c.sock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if written == 0 {
|
||||
return ErrDataNotWritten
|
||||
}
|
||||
if sent, _ := c.device.CheckDataSent(c.sock); !sent {
|
||||
return ErrCheckDataError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build none
|
||||
// +build none
|
||||
|
||||
package main
|
||||
|
||||
@@ -285,7 +284,6 @@ func main() {
|
||||
}
|
||||
defer f.Close()
|
||||
fmt.Fprintln(f, "//go:build", architectures[*arch].buildTag)
|
||||
fmt.Fprintln(f, "// +build", architectures[*arch].buildTag)
|
||||
f.WriteString(`
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build cortexm
|
||||
// +build cortexm
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo.riscv32
|
||||
// +build tinygo.riscv32
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build avr
|
||||
// +build avr
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build cortexm
|
||||
// +build cortexm
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !baremetal
|
||||
// +build !baremetal
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build tinygo.riscv32
|
||||
// +build tinygo.riscv32
|
||||
|
||||
package ws2812
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user