mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-06 16:03:41 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 592f66e1ca |
@@ -11,13 +11,10 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: ghcr.io/tinygo-org/tinygo-dev:latest
|
container: tinygo/tinygo-dev
|
||||||
steps:
|
steps:
|
||||||
- name: Work around CVE-2022-24765
|
|
||||||
# We're not on a multi-user machine, so this is safe.
|
|
||||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
- name: TinyGo version check
|
- name: TinyGo version check
|
||||||
run: tinygo version
|
run: tinygo version
|
||||||
- name: Enforce Go Formatted Code
|
- name: Enforce Go Formatted Code
|
||||||
|
|||||||
-221
@@ -1,224 +1,3 @@
|
|||||||
0.25.0
|
|
||||||
---
|
|
||||||
|
|
||||||
- **core**
|
|
||||||
- add Sensor interface and Measurement type
|
|
||||||
- **delay**
|
|
||||||
- add new package for cycle-accurate delays
|
|
||||||
|
|
||||||
- **new devices**
|
|
||||||
- **AS560x**
|
|
||||||
- Add support for ams AS560x on-axis magnetic rotary position sensors
|
|
||||||
- **onewire**
|
|
||||||
- first implementation of 1-wire protocol (#505)
|
|
||||||
- **mpu6886**
|
|
||||||
- initial implementation
|
|
||||||
- **ttp229**
|
|
||||||
- initial support for ttp229 (BSF)
|
|
||||||
|
|
||||||
- **enhancements**
|
|
||||||
- **gps**
|
|
||||||
- make the date available in addition to the time (#532)
|
|
||||||
- **i2csoft**
|
|
||||||
- use cycle counting for delays
|
|
||||||
- **ili9341**
|
|
||||||
- add EnableTEOutput to be able to sync drawing with VSYNC
|
|
||||||
- add sleep mode
|
|
||||||
- unify rotation support
|
|
||||||
- **st7735**
|
|
||||||
- add DrawRGBBitmap8 method to draw raw RGB565 buffers
|
|
||||||
- add sleep mode
|
|
||||||
- unify rotation support
|
|
||||||
- **st7789**
|
|
||||||
- added DrawRGBBitmap8 (same as ili9341 & st7735)
|
|
||||||
- allow changing the color format using COLMOD
|
|
||||||
- make it possible to configure gamma
|
|
||||||
- support the chip select pin
|
|
||||||
- update saved rotation in SetRotation
|
|
||||||
- add sleep mode
|
|
||||||
- unify rotation support
|
|
||||||
- **sx126x/sx127x**
|
|
||||||
- Reduce spi buffer size, add missing select when using channels
|
|
||||||
- Remove heap alloc in interrupt, add non blocking channel send/receive, and other cleanups
|
|
||||||
- **wifinina**
|
|
||||||
- add generated strings, improved debugging system and messages
|
|
||||||
- add ResetIsHigh to control the behavior of the RESET pin for boards like the Arduino MKR 1010
|
|
||||||
- only add generated strings when using wifidebug tag
|
|
||||||
|
|
||||||
- **bugfixes**
|
|
||||||
- **ds3231**
|
|
||||||
- Document incorrect leap year 2100
|
|
||||||
- Fix negative temperature conversion
|
|
||||||
- **ili9341**
|
|
||||||
- fix Size() for mirrored rotation
|
|
||||||
- **st7789**
|
|
||||||
- avoid heap allocations after the driver is created
|
|
||||||
- **net**
|
|
||||||
- Revert "(#501) make IP.String() method return something sensible"
|
|
||||||
- **wifinina**
|
|
||||||
- small timing adjustments in Configure() to better ensure device reset
|
|
||||||
|
|
||||||
- **examples**
|
|
||||||
- **sdcard**
|
|
||||||
- remove tinyfs example and replace with link to tinyfs repo in docs
|
|
||||||
- **wifinina**
|
|
||||||
- improve connectToAP() and other needed minor corrections
|
|
||||||
|
|
||||||
- **build**
|
|
||||||
- switch to ghcr.io for docker container
|
|
||||||
- run smoke tests in parallel
|
|
||||||
- **Makefile**
|
|
||||||
- add XTENSA=0 flag to skip Xtensa tests
|
|
||||||
- remove AVR=0 flag
|
|
||||||
|
|
||||||
- **docs**
|
|
||||||
- remove full list of devices from README, better to keep it on the tinygo.org site
|
|
||||||
- update LICENSE year
|
|
||||||
|
|
||||||
|
|
||||||
0.24.0
|
|
||||||
---
|
|
||||||
- **new devices**
|
|
||||||
- **lora**
|
|
||||||
- created shared RadioEvent
|
|
||||||
- move shared config for sx126x/sx127x to single package
|
|
||||||
- **lorawan**
|
|
||||||
- add initial LoRaWAN stack support
|
|
||||||
- Basic implementation of Lorawan Regional Settings and EU868/AU915 regions
|
|
||||||
- **qmi8658c**
|
|
||||||
- Add support for the QMI8658C sensor (#467)
|
|
||||||
- **sh1106**
|
|
||||||
- add support for SH1106 display driver
|
|
||||||
- **sx127x**
|
|
||||||
- Driver for Semtech sx127x radio modules
|
|
||||||
|
|
||||||
- **enhancements**
|
|
||||||
- **bme280**
|
|
||||||
- improve config support
|
|
||||||
- add ReadAltitude() function copied from BMP280 driver
|
|
||||||
- **buzzer**
|
|
||||||
- make all note durations float64
|
|
||||||
- no tone during rest
|
|
||||||
- **dht22**
|
|
||||||
- update DHT22 receive to use runtime/interrupt
|
|
||||||
- **gps**
|
|
||||||
- add support for GLL sentence type, add original sentence to gps errors
|
|
||||||
- improve error handling
|
|
||||||
- improve parsing and add tests to verify
|
|
||||||
- **microbitmatrix**
|
|
||||||
- add link to schema for microbit V2
|
|
||||||
- add smoke test for microbitmatrix with microbit-v2
|
|
||||||
- add support for brightness of led pixels
|
|
||||||
- harmonize v1 and v2 implementation
|
|
||||||
- move Size() to version agnostic part
|
|
||||||
- **mpu6050**
|
|
||||||
- add functions to configure clock, and scaling for accelerometer and gyroscope
|
|
||||||
- **net/http**
|
|
||||||
- add PostForm()
|
|
||||||
- **sx126x**
|
|
||||||
- add Reset() and needed pin
|
|
||||||
- move RadioController into separate file for clarity
|
|
||||||
- pre-define all errors to avoid heap allocations
|
|
||||||
- refactor to RadioController interface to more easily handle non-STM32WL boards and remove duplicated code
|
|
||||||
|
|
||||||
- **vl53l1x**
|
|
||||||
- Add getter for the effective SPAD count
|
|
||||||
- **wifinina**
|
|
||||||
- add support for http server (#480)
|
|
||||||
|
|
||||||
- **bugfixes**
|
|
||||||
- **lsm303agr**
|
|
||||||
- fix I2C address auto increment for multi data read
|
|
||||||
- **net**
|
|
||||||
- (#501) make IP.String() method return something sensible
|
|
||||||
- **mpu6050**
|
|
||||||
- return I2C error when configuring fails
|
|
||||||
- **sx126x**
|
|
||||||
- fix in SetBandwidth function
|
|
||||||
- actually set the frequency when calling SetFrequency()
|
|
||||||
- correct RX/TX pin mapping for TheThingsIndustries GNSE board
|
|
||||||
|
|
||||||
- **examples**
|
|
||||||
- **LoRaWAN**
|
|
||||||
- example with LoRaWAN AT command set implementation
|
|
||||||
- basic example
|
|
||||||
- update all remaining examples for refactored API
|
|
||||||
- **sx126x**
|
|
||||||
- fix bandwidth,tx power in lora//lora_continuous example
|
|
||||||
- **sx127x**
|
|
||||||
- rx/tx example
|
|
||||||
|
|
||||||
- **build**
|
|
||||||
- remove older format build tags
|
|
||||||
- update to actions/checkout@v3
|
|
||||||
- work around for CVE-2022-24765
|
|
||||||
|
|
||||||
|
|
||||||
0.23.0
|
|
||||||
---
|
|
||||||
- **new devices**
|
|
||||||
- Add GC9A01 Driver (#452)
|
|
||||||
- Initial support for VL6180x sensor
|
|
||||||
|
|
||||||
- **enhancements**
|
|
||||||
- **rtl8720dn**
|
|
||||||
- refactor by bringing this driver more in line with wifinina and espat
|
|
||||||
- **ssd1306**
|
|
||||||
- add getter method to the current buffer
|
|
||||||
- **makeybutton**
|
|
||||||
- revise to better match the algorithm defined by the original
|
|
||||||
- **espat,wifinina,rtl8720dn**
|
|
||||||
- change ssid/pass from const to var
|
|
||||||
|
|
||||||
- **bugfixes**
|
|
||||||
- **microbitmatrix**
|
|
||||||
- fix inverted axis
|
|
||||||
- **espat**
|
|
||||||
- Trim quotes from IP returned by espat's GetDNS()
|
|
||||||
- **all**
|
|
||||||
- correct go fmt
|
|
||||||
|
|
||||||
- **examples**
|
|
||||||
- **rtl8720dn**
|
|
||||||
- remove wifi setting
|
|
||||||
- add call to optional debug setting
|
|
||||||
- update all remaining examples for refactored API
|
|
||||||
|
|
||||||
|
|
||||||
0.22.0
|
|
||||||
---
|
|
||||||
- **new devices**
|
|
||||||
- epd: add waveshare 2.9in (v1)
|
|
||||||
- makeybutton: add driver for MakeyMakey-like button
|
|
||||||
|
|
||||||
- **enhancements**
|
|
||||||
- **rtl8720dn**
|
|
||||||
- add UDP close function
|
|
||||||
- improve error handling
|
|
||||||
- **net/http**
|
|
||||||
- improve header parsing
|
|
||||||
- add last-will-and-testament to MQTT
|
|
||||||
- **net/mqtt**
|
|
||||||
- adds keepalive pinging, disconnect, and graceful goroutine cleanup
|
|
||||||
- support for cookies when https
|
|
||||||
- add support for retained messsages
|
|
||||||
|
|
||||||
- **bugfixes**
|
|
||||||
- irremote: Fix irremote reporting incorrect NEC addresses and command codes (#422)
|
|
||||||
- net/http: Fix http.Get() with port specification
|
|
||||||
|
|
||||||
- **build**
|
|
||||||
- Makefile recursively finds unit-tests
|
|
||||||
- switching to GHA
|
|
||||||
|
|
||||||
- **updates**
|
|
||||||
- update tinyfont to v0.3.0
|
|
||||||
- update tinyfs to v0.2.0
|
|
||||||
|
|
||||||
- **examples**
|
|
||||||
- rtl8720dn: add ./examples/rtl8720dn/version
|
|
||||||
|
|
||||||
|
|
||||||
0.21.0
|
0.21.0
|
||||||
---
|
---
|
||||||
- **new devices**
|
- **new devices**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
Copyright (c) 2018-2022 The TinyGo Authors. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
|||||||
@@ -7,11 +7,240 @@ FMT_PATHS = ./
|
|||||||
fmt-check:
|
fmt-check:
|
||||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||||
|
|
||||||
XTENSA ?= 1
|
|
||||||
smoke-test:
|
smoke-test:
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
@go run ./smoketest.go -xtensa=$(XTENSA) smoketest.sh
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adt7410/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adxl345/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/amg88xx
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bh1750/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/blinkm/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmi160/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp180/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp280/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bmp388/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/sram/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/time/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/ds3231/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/easystepper/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/espconsole/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/esphub/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/espat/espstation/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/flash/console/spi
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/flash/console/qspi
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/i2c/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/uart/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/hcsr04/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/customchar/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/text/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/hd44780i2c/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/hts221/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hub75/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/basic
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/pyportal_boing
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/scroll
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/scroll
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/slideshow
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017-multiple/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp2515/main.go
|
||||||
|
@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=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
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/thermistor/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-bluefruit ./examples/tone
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/tm1637/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/fourwire/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/pyportal_touchpaint/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/vl53l1x/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd4in2/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/ntpclient/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/udpstation/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/tcpclient/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/wifinina/webclient/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.bin -target=m5stamp-c3 ./examples/ws2812
|
||||||
|
@md5sum ./build/test.bin
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/is31fl3731/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
ifneq ($(AVR), 0)
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino ./examples/ws2812
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=digispark ./examples/ws2812
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
endif
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bme280/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/microphone/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/buzzer/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/veml6070/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/simple/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/speed/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/simple/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/speed/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nucleo-f103rb ./examples/shiftregister/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=hifive1b ./examples/ssd1351/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/max72xx/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
# tinygo build -size short -o ./build/test.hex -target=arduino ./examples/keypad4x4/main.go
|
||||||
|
# @md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/time/
|
||||||
|
@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=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
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/tinyfs/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webclient/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/webserver/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=wioterminal ./examples/rtl8720dn/mqttsub/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
|
||||||
|
@md5sum ./build/test.uf2
|
||||||
|
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/basic/
|
||||||
|
@md5sum ./build/test.elf
|
||||||
|
tinygo build -size short -o ./build/test.elf -target=m5stack-core2 ./examples/ft6336/touchpaint/
|
||||||
|
@md5sum ./build/test.elf
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/sx126x/lora_rxtx/
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/ssd1289/main.go
|
||||||
|
@md5sum ./build/test.uf2
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=pico ./examples/irremote/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=badger2040 ./examples/uc8151/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/scd4x/main.go
|
||||||
|
@md5sum ./build/test.uf2
|
||||||
|
tinygo build -size short -o ./build/test.uf2 -target=circuitplay-express ./examples/makeybutton/main.go
|
||||||
|
@md5sum ./build/test.uf2
|
||||||
|
|
||||||
# rwildcard is a recursive version of $(wildcard)
|
# rwildcard is a recursive version of $(wildcard)
|
||||||
# https://blog.jgc.org/2011/07/gnu-make-recursive-wildcard-function.html
|
# https://blog.jgc.org/2011/07/gnu-make-recursive-wildcard-function.html
|
||||||
|
|||||||
@@ -50,10 +50,98 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Supported devices
|
## Currently supported devices
|
||||||
|
|
||||||
There are currently 96 devices supported. For the complete list, please see:
|
The following 81 devices are supported.
|
||||||
https://tinygo.org/docs/reference/devices/
|
|
||||||
|
| Device Name | Interface Type |
|
||||||
|
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
|
||||||
|
| [ADT7410 I2C Temperature Sensor](https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf) | I2C |
|
||||||
|
| [ADXL345 accelerometer](http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf) | I2C |
|
||||||
|
| [AHT20 I2C Temperature and Humidity Sensor](http://www.aosong.com/userfiles/files/media/AHT20%20%E8%8B%B1%E6%96%87%E7%89%88%E8%AF%B4%E6%98%8E%E4%B9%A6%20A0%2020201222.pdf) | I2C |
|
||||||
|
| [AMG88xx 8x8 Thermal camera sensor](https://cdn-learn.adafruit.com/assets/assets/000/043/261/original/Grid-EYE_SPECIFICATIONS%28Reference%29.pdf) | I2C |
|
||||||
|
| [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI |
|
||||||
|
| [APDS9960 Digital proximity, ambient light, RGB and gesture sensor](https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf) | I2C |
|
||||||
|
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
|
||||||
|
| [AXP192 single Cell Li-Battery and Power System Management](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf) | I2C |
|
||||||
|
| [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO |
|
||||||
|
| [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C |
|
||||||
|
| [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C |
|
||||||
|
| [BME280 humidity/pressure sensor](https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf) | I2C |
|
||||||
|
| [BMI160 accelerometer/gyroscope](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi160-ds000.pdf) | SPI |
|
||||||
|
| [BMP180 barometer](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) | I2C |
|
||||||
|
| [BMP280 temperature/barometer](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf) | I2C |
|
||||||
|
| [BMP388 pressure sensor](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf) | I2C |
|
||||||
|
| [Buzzer](https://en.wikipedia.org/wiki/Buzzer#Piezoelectric) | GPIO |
|
||||||
|
| [DHTXX thermometer and humidity sensor](https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf) | GPIO |
|
||||||
|
| [DS1307 real time clock](https://datasheets.maximintegrated.com/en/ds/DS1307.pdf) | I2C |
|
||||||
|
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
|
||||||
|
| [ESP32 as WiFi Coprocessor with Arduino nina-fw](https://github.com/arduino/nina-fw) | SPI |
|
||||||
|
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
|
||||||
|
| [FT6336 touch controller](https://focuslcds.com/content/FT6236.pdf) | I2C |
|
||||||
|
| [GPS module](https://www.u-blox.com/en/product/neo-6-series) | I2C/UART |
|
||||||
|
| [HC-SR04 Ultrasonic distance sensor](https://cdn.sparkfun.com/datasheets/Sensors/Proximity/HCSR04.pdf) | GPIO |
|
||||||
|
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
|
||||||
|
| [HTS221 digital humidity and temperature sensor](https://www.st.com/resource/en/datasheet/hts221.pdf) | I2C |
|
||||||
|
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
|
||||||
|
| [software I2C driver](https://www.ti.com/lit/an/slva704/slva704.pdf) | GPIO |
|
||||||
|
| [ILI9341 TFT color display](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf) | SPI |
|
||||||
|
| [INA260 Volt/Amp/Power meter](https://www.ti.com/lit/ds/symlink/ina260.pdf) | I2C |
|
||||||
|
| [Infrared remote control](https://en.wikipedia.org/wiki/Consumer_IR) | GPIO |
|
||||||
|
| [IS31FL3731 matrix LED driver](https://www.lumissil.com/assets/pdf/core/IS31FL3731_DS.pdf) | I2C |
|
||||||
|
| [4x4 Membrane Keypad](https://cdn.sparkfun.com/assets/f/f/a/5/0/DS-16038.pdf) | GPIO |
|
||||||
|
| [L293x motor driver](https://www.ti.com/lit/ds/symlink/l293d.pdf) | GPIO/PWM |
|
||||||
|
| [L9110x motor driver](https://www.elecrow.com/download/datasheet-l9110.pdf) | GPIO/PWM |
|
||||||
|
| [LIS2MDL magnetometer](https://www.st.com/resource/en/datasheet/lis2mdl.pdf) | I2C |
|
||||||
|
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
|
||||||
|
| [LPS22HB MEMS nano pressure sensor](https://www.st.com/resource/en/datasheet/dm00140895.pdf) | I2C |
|
||||||
|
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C |
|
||||||
|
| [LSM6DSOX accelerometer](https://www.st.com/resource/en/datasheet/lsm6dsox.pdf) | I2C |
|
||||||
|
| [LSM6DS3TR accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3tr.pdf) | I2C |
|
||||||
|
| [LSM303AGR accelerometer](https://www.st.com/resource/en/datasheet/lsm303agr.pdf) | I2C |
|
||||||
|
| [LSM9DS1 accelerometer](https://www.st.com/resource/en/datasheet/lsm9ds1.pdf) | I2C |
|
||||||
|
| [Makey Button](https://makeymakey.com/) | GPIO |
|
||||||
|
| [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C |
|
||||||
|
| [MAX7219 & MAX7221 display driver](https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) | SPI |
|
||||||
|
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
|
||||||
|
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
|
||||||
|
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
|
||||||
|
| [Microphone - PDM](https://cdn-learn.adafruit.com/assets/assets/000/049/977/original/MP34DT01-M.pdf) | I2S/PDM |
|
||||||
|
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
|
||||||
|
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
|
||||||
|
| [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 |
|
||||||
|
| [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 |
|
||||||
|
| [Semihosting](https://wiki.segger.com/Semihosting) | Debug |
|
||||||
|
| [Servo](https://learn.sparkfun.com/tutorials/hobby-servo-tutorial/all) | PWM |
|
||||||
|
| [Shift register (PISO)](https://en.wikipedia.org/wiki/Shift_register#Parallel-in_serial-out_\(PISO\)) | GPIO |
|
||||||
|
| [Shift registers (SIPO)](https://en.wikipedia.org/wiki/Shift_register#Serial-in_parallel-out_(SIPO)) | GPIO |
|
||||||
|
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||||
|
| [SHTC3 Digital Humidity Sensor (RH/T)](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHTC3_Datasheet.pdf) | I2C |
|
||||||
|
| [SPI NOR Flash Memory](https://en.wikipedia.org/wiki/Flash_memory#NOR_flash) | SPI/QSPI |
|
||||||
|
| [SPI SDCARD/MMC](https://en.wikipedia.org/wiki/SD_card) | SPI |
|
||||||
|
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||||
|
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
|
||||||
|
| [SSD1351 OLED display](https://download.mikroe.com/documents/datasheets/ssd1351-revision-1.3.pdf) | SPI |
|
||||||
|
| [ST7735 TFT color display](https://www.crystalfontz.com/controllers/Sitronix/ST7735R/319/) | SPI |
|
||||||
|
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
|
||||||
|
| [Stepper motor "Easystepper" controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
|
||||||
|
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
|
||||||
|
| [TM1637 7-segment LED display](https://www.mcielectronics.cl/website_MCI/static/documents/Datasheet_TM1637.pdf) | I2C |
|
||||||
|
| [TMP102 I2C Temperature Sensor](https://download.mikroe.com/documents/datasheets/tmp102-data-sheet.pdf) | I2C |
|
||||||
|
| [UC8151 All-in-one driver IC for ESL](https://www.buydisplay.com/download/ic/UC8151C.pdf) | I2C |
|
||||||
|
| [VEML6070 UV light sensor](https://www.vishay.com/docs/84277/veml6070.pdf) | I2C |
|
||||||
|
| [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C |
|
||||||
|
| [Waveshare 2.13" (B & C) e-paper display](https://www.waveshare.com/w/upload/d/d3/2.13inch-e-paper-b-Specification.pdf) | SPI |
|
||||||
|
| [Waveshare 2.13" e-paper display](https://www.waveshare.com/w/upload/e/e6/2.13inch_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 |
|
||||||
|
| [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 |
|
||||||
|
| [SSD1289 TFT color display](http://aitendo3.sakura.ne.jp/aitendo_data/product_img/lcd/tft2/M032C1289TP/3.2-SSD1289.pdf) | GPIO |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,13 +1,13 @@
|
|||||||
// Package adt7410 provides a driver for the adt7410 I2C Temperature Sensor.
|
// Package adt7410 provides a driver for the adt7410 I2C Temperature Sensor.
|
||||||
//
|
//
|
||||||
// Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf
|
// Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf
|
||||||
|
//
|
||||||
package adt7410 // import "tinygo.org/x/drivers/adt7410"
|
package adt7410 // import "tinygo.org/x/drivers/adt7410"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error uint8
|
type Error uint8
|
||||||
@@ -55,7 +55,7 @@ func (d *Device) Configure() (err error) {
|
|||||||
// Connected returns whether sensor has been found.
|
// Connected returns whether sensor has been found.
|
||||||
func (d *Device) Connected() bool {
|
func (d *Device) Connected() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), RegID, data)
|
d.bus.ReadRegister(uint8(d.Address), RegID, data)
|
||||||
return data[0]&0xF8 == 0xC8
|
return data[0]&0xF8 == 0xC8
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,11 +82,11 @@ func (d *Device) writeByte(reg uint8, data byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) readByte(reg uint8) byte {
|
func (d *Device) readByte(reg uint8) byte {
|
||||||
legacy.ReadRegister(d.bus, d.Address, reg, d.buf)
|
d.bus.ReadRegister(d.Address, reg, d.buf)
|
||||||
return d.buf[0]
|
return d.buf[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) readUint16(reg uint8) uint16 {
|
func (d *Device) readUint16(reg uint8) uint16 {
|
||||||
legacy.ReadRegister(d.bus, d.Address, reg, d.buf)
|
d.bus.ReadRegister(d.Address, reg, d.buf)
|
||||||
return uint16(d.buf[0])<<8 | uint16(d.buf[1])
|
return uint16(d.buf[0])<<8 | uint16(d.buf[1])
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-13
@@ -3,12 +3,10 @@
|
|||||||
// Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
|
// Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
|
||||||
//
|
//
|
||||||
// Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
|
// Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
|
||||||
|
//
|
||||||
package adxl345 // import "tinygo.org/x/drivers/adxl345"
|
package adxl345 // import "tinygo.org/x/drivers/adxl345"
|
||||||
|
|
||||||
import (
|
import "tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Range uint8
|
type Range uint8
|
||||||
type Rate uint8
|
type Rate uint8
|
||||||
@@ -71,21 +69,21 @@ func New(bus drivers.I2C) Device {
|
|||||||
|
|
||||||
// Configure sets up the device for communication
|
// Configure sets up the device for communication
|
||||||
func (d *Device) Configure() {
|
func (d *Device) Configure() {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Halt stops the sensor, values will not updated
|
// Halt stops the sensor, values will not updated
|
||||||
func (d *Device) Halt() {
|
func (d *Device) Halt() {
|
||||||
d.powerCtl.measure = 0
|
d.powerCtl.measure = 0
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart makes reading the sensor working again after a halt
|
// Restart makes reading the sensor working again after a halt
|
||||||
func (d *Device) Restart() {
|
func (d *Device) Restart() {
|
||||||
d.powerCtl.measure = 1
|
d.powerCtl.measure = 1
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_POWER_CTL, []byte{d.powerCtl.toByte()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAcceleration reads the current acceleration from the device and returns
|
// ReadAcceleration reads the current acceleration from the device and returns
|
||||||
@@ -106,7 +104,7 @@ func (d *Device) ReadAcceleration() (x int32, y int32, z int32, err error) {
|
|||||||
// from the adxl345.
|
// from the adxl345.
|
||||||
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
|
func (d *Device) ReadRawAcceleration() (x int32, y int32, z int32) {
|
||||||
data := []byte{0, 0, 0, 0, 0, 0}
|
data := []byte{0, 0, 0, 0, 0, 0}
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), REG_DATAX0, data)
|
d.bus.ReadRegister(uint8(d.Address), REG_DATAX0, data)
|
||||||
|
|
||||||
x = readIntLE(data[0], data[1])
|
x = readIntLE(data[0], data[1])
|
||||||
y = readIntLE(data[2], data[3])
|
y = readIntLE(data[2], data[3])
|
||||||
@@ -122,20 +120,20 @@ func (d *Device) UseLowPower(power bool) {
|
|||||||
} else {
|
} else {
|
||||||
d.bwRate.lowPower = 0
|
d.bwRate.lowPower = 0
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRate change the current rate of the sensor
|
// SetRate change the current rate of the sensor
|
||||||
func (d *Device) SetRate(rate Rate) bool {
|
func (d *Device) SetRate(rate Rate) bool {
|
||||||
d.bwRate.rate = rate & 0x0F
|
d.bwRate.rate = rate & 0x0F
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_BW_RATE, []byte{d.bwRate.toByte()})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRange change the current range of the sensor
|
// SetRange change the current range of the sensor
|
||||||
func (d *Device) SetRange(sensorRange Range) bool {
|
func (d *Device) SetRange(sensorRange Range) bool {
|
||||||
d.dataFormat.sensorRange = sensorRange & 0x03
|
d.dataFormat.sensorRange = sensorRange & 0x03
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
|
d.bus.WriteRegister(uint8(d.Address), REG_DATA_FORMAT, []byte{d.dataFormat.toByte()})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-17
@@ -8,7 +8,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps an I2C connection to a AMG88xx device.
|
// Device wraps an I2C connection to a AMG88xx device.
|
||||||
@@ -49,7 +48,7 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
|
|
||||||
// ReadPixels returns the 64 values (8x8 grid) of the sensor converted to millicelsius
|
// ReadPixels returns the 64 values (8x8 grid) of the sensor converted to millicelsius
|
||||||
func (d *Device) ReadPixels(buffer *[64]int16) {
|
func (d *Device) ReadPixels(buffer *[64]int16) {
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), PIXEL_OFFSET, d.data)
|
d.bus.ReadRegister(uint8(d.Address), PIXEL_OFFSET, d.data)
|
||||||
for i := 0; i < 64; i++ {
|
for i := 0; i < 64; i++ {
|
||||||
buffer[i] = int16((uint16(d.data[2*i+1]) << 8) | uint16(d.data[2*i]))
|
buffer[i] = int16((uint16(d.data[2*i+1]) << 8) | uint16(d.data[2*i]))
|
||||||
if (buffer[i] & (1 << 11)) > 0 { // temperature negative
|
if (buffer[i] & (1 << 11)) > 0 { // temperature negative
|
||||||
@@ -62,17 +61,17 @@ func (d *Device) ReadPixels(buffer *[64]int16) {
|
|||||||
|
|
||||||
// SetPCTL sets the PCTL
|
// SetPCTL sets the PCTL
|
||||||
func (d *Device) SetPCTL(pctl uint8) {
|
func (d *Device) SetPCTL(pctl uint8) {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), PCTL, []byte{pctl})
|
d.bus.WriteRegister(uint8(d.Address), PCTL, []byte{pctl})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReset sets the reset value
|
// SetReset sets the reset value
|
||||||
func (d *Device) SetReset(rst uint8) {
|
func (d *Device) SetReset(rst uint8) {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), RST, []byte{rst})
|
d.bus.WriteRegister(uint8(d.Address), RST, []byte{rst})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFrameRate configures the frame rate
|
// SetFrameRate configures the frame rate
|
||||||
func (d *Device) SetFrameRate(framerate uint8) {
|
func (d *Device) SetFrameRate(framerate uint8) {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), FPSC, []byte{framerate & 0x01})
|
d.bus.WriteRegister(uint8(d.Address), FPSC, []byte{framerate & 0x01})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMovingAverageMode sets the moving average mode
|
// SetMovingAverageMode sets the moving average mode
|
||||||
@@ -81,7 +80,7 @@ func (d *Device) SetMovingAverageMode(mode bool) {
|
|||||||
if mode {
|
if mode {
|
||||||
value = 1
|
value = 1
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), AVE, []byte{value << 5})
|
d.bus.WriteRegister(uint8(d.Address), AVE, []byte{value << 5})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInterruptLevels sets the interrupt levels
|
// SetInterruptLevels sets the interrupt levels
|
||||||
@@ -98,8 +97,8 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
|
|||||||
if high > 4095 {
|
if high > 4095 {
|
||||||
high = 4095
|
high = 4095
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(high & 0xFF)})
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((high & 0xFF) >> 4)})
|
||||||
|
|
||||||
low = low / PIXEL_TEMP_CONVERSION
|
low = low / PIXEL_TEMP_CONVERSION
|
||||||
if low < -4095 {
|
if low < -4095 {
|
||||||
@@ -108,8 +107,8 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
|
|||||||
if low > 4095 {
|
if low > 4095 {
|
||||||
low = 4095
|
low = 4095
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(low & 0xFF)})
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((low & 0xFF) >> 4)})
|
||||||
|
|
||||||
hysteresis = hysteresis / PIXEL_TEMP_CONVERSION
|
hysteresis = hysteresis / PIXEL_TEMP_CONVERSION
|
||||||
if hysteresis < -4095 {
|
if hysteresis < -4095 {
|
||||||
@@ -118,32 +117,32 @@ func (d *Device) SetInterruptLevelsHysteresis(high int16, low int16, hysteresis
|
|||||||
if hysteresis > 4095 {
|
if hysteresis > 4095 {
|
||||||
hysteresis = 4095
|
hysteresis = 4095
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8(hysteresis & 0xFF)})
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
|
d.bus.WriteRegister(uint8(d.Address), INTHL, []byte{uint8((hysteresis & 0xFF) >> 4)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableInterrupt enables the interrupt pin on the device
|
// EnableInterrupt enables the interrupt pin on the device
|
||||||
func (d *Device) EnableInterrupt() {
|
func (d *Device) EnableInterrupt() {
|
||||||
d.interruptEnable = 1
|
d.interruptEnable = 1
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisableInterrupt disables the interrupt pin on the device
|
// DisableInterrupt disables the interrupt pin on the device
|
||||||
func (d *Device) DisableInterrupt() {
|
func (d *Device) DisableInterrupt() {
|
||||||
d.interruptEnable = 0
|
d.interruptEnable = 0
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInterruptMode sets the interrupt mode
|
// SetInterruptMode sets the interrupt mode
|
||||||
func (d *Device) SetInterruptMode(mode InterruptMode) {
|
func (d *Device) SetInterruptMode(mode InterruptMode) {
|
||||||
d.interruptMode = mode
|
d.interruptMode = mode
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
d.bus.WriteRegister(uint8(d.Address), INTC, []byte{((uint8(d.interruptMode) << 1) | d.interruptEnable) & 0x03})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInterrupt reads the state of the triggered interrupts
|
// GetInterrupt reads the state of the triggered interrupts
|
||||||
func (d *Device) GetInterrupt() []uint8 {
|
func (d *Device) GetInterrupt() []uint8 {
|
||||||
data := make([]uint8, 8)
|
data := make([]uint8, 8)
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), INT_OFFSET, data)
|
d.bus.ReadRegister(uint8(d.Address), INT_OFFSET, data)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +154,6 @@ func (d *Device) ClearInterrupt() {
|
|||||||
// ReadThermistor reads the onboard thermistor
|
// ReadThermistor reads the onboard thermistor
|
||||||
func (d *Device) ReadThermistor() int16 {
|
func (d *Device) ReadThermistor() int16 {
|
||||||
data := make([]uint8, 2)
|
data := make([]uint8, 2)
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), TTHL, data)
|
d.bus.ReadRegister(uint8(d.Address), TTHL, data)
|
||||||
return (int16((uint16(data[1])<<8)|uint16(data[0])) * THERMISTOR_CONVERSION) / 10
|
return (int16((uint16(data[1])<<8)|uint16(data[0])) * THERMISTOR_CONVERSION) / 10
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-26
@@ -2,13 +2,13 @@
|
|||||||
// a digital proximity, ambient light, RGB and gesture sensor.
|
// a digital proximity, ambient light, RGB and gesture sensor.
|
||||||
//
|
//
|
||||||
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
|
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
|
||||||
|
//
|
||||||
package apds9960
|
package apds9960
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps an I2C connection to a APDS-9960 device.
|
// Device wraps an I2C connection to a APDS-9960 device.
|
||||||
@@ -69,7 +69,7 @@ func New(bus drivers.I2C) Device {
|
|||||||
// It does a "who am I" request and checks the response.
|
// It does a "who am I" request and checks the response.
|
||||||
func (d *Device) Connected() bool {
|
func (d *Device) Connected() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_ID_REG, data)
|
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
|
||||||
return data[0] == 0xAB
|
return data[0] == 0xAB
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ func (d *Device) GetMode() uint8 {
|
|||||||
// DisableAll turns off the device and all functions
|
// DisableAll turns off the device and all functions
|
||||||
func (d *Device) DisableAll() {
|
func (d *Device) DisableAll() {
|
||||||
d.enable(enableConfig{})
|
d.enable(enableConfig{})
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_GCONF4_REG, []byte{0x00})
|
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
|
||||||
d.mode = MODE_NONE
|
d.mode = MODE_NONE
|
||||||
d.gesture.detected = GESTURE_NONE
|
d.gesture.detected = GESTURE_NONE
|
||||||
}
|
}
|
||||||
@@ -89,13 +89,13 @@ func (d *Device) DisableAll() {
|
|||||||
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
|
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
|
||||||
// default: 16, 64
|
// default: 16, 64
|
||||||
func (d *Device) SetProximityPulse(length, count uint8) {
|
func (d *Device) SetProximityPulse(length, count uint8) {
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
|
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
|
||||||
// default: 16, 64
|
// default: 16, 64
|
||||||
func (d *Device) SetGesturePulse(length, count uint8) {
|
func (d *Device) SetGesturePulse(length, count uint8) {
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
|
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
|
||||||
@@ -104,14 +104,14 @@ func (d *Device) SetADCIntegrationCycles(cycles uint16) {
|
|||||||
if cycles > 256 {
|
if cycles > 256 {
|
||||||
cycles = 256
|
cycles = 256
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
|
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
|
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
|
||||||
// default: 1, 1, 4
|
// default: 1, 1, 4
|
||||||
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
|
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
|
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
|
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
|
||||||
}
|
}
|
||||||
|
|
||||||
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
|
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
|
||||||
@@ -128,7 +128,7 @@ func (d *Device) LEDBoost(percent uint16) {
|
|||||||
case 300:
|
case 300:
|
||||||
v = 3
|
v = 3
|
||||||
}
|
}
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
|
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setthreshold sets threshold (0~255) for detecting gestures
|
// Setthreshold sets threshold (0~255) for detecting gestures
|
||||||
@@ -169,7 +169,7 @@ func (d *Device) ReadProximity() (proximity int32) {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_PDATA_REG, data)
|
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
|
||||||
return 255 - int32(data[0])
|
return 255 - int32(data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,14 +196,14 @@ func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_CDATAL_REG, data[:1])
|
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_CDATAH_REG, data[1:2])
|
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_RDATAL_REG, data[2:3])
|
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_RDATAH_REG, data[3:4])
|
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GDATAL_REG, data[4:5])
|
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GDATAH_REG, data[5:6])
|
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_BDATAL_REG, data[6:7])
|
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_BDATAH_REG, data[7:])
|
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
|
||||||
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
|
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
|
||||||
r = int32(uint16(data[3])<<8 | uint16(data[2]))
|
r = int32(uint16(data[3])<<8 | uint16(data[2]))
|
||||||
g = int32(uint16(data[5])<<8 | uint16(data[4]))
|
g = int32(uint16(data[5])<<8 | uint16(data[4]))
|
||||||
@@ -235,13 +235,13 @@ func (d *Device) GestureAvailable() bool {
|
|||||||
data := []byte{0, 0, 0, 0}
|
data := []byte{0, 0, 0, 0}
|
||||||
|
|
||||||
// check GVALID
|
// check GVALID
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GSTATUS_REG, data[:1])
|
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
|
||||||
if data[0]&0x01 == 0 {
|
if data[0]&0x01 == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// get number of data sets available in FIFO
|
// get number of data sets available in FIFO
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFLVL_REG, data[:1])
|
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
|
||||||
availableDataSets := data[0]
|
availableDataSets := data[0]
|
||||||
if availableDataSets == 0 {
|
if availableDataSets == 0 {
|
||||||
return false
|
return false
|
||||||
@@ -250,10 +250,10 @@ func (d *Device) GestureAvailable() bool {
|
|||||||
// read up, down, left and right proximity data from FIFO
|
// read up, down, left and right proximity data from FIFO
|
||||||
var dataSets [32][4]uint8
|
var dataSets [32][4]uint8
|
||||||
for i := uint8(0); i < availableDataSets; i++ {
|
for i := uint8(0); i < availableDataSets; i++ {
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_U_REG, data[:1])
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_D_REG, data[1:2])
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_L_REG, data[2:3])
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_GFIFO_R_REG, data[3:4])
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
|
||||||
for j := uint8(0); j < 4; j++ {
|
for j := uint8(0); j < 4; j++ {
|
||||||
dataSets[i][j] = data[j]
|
dataSets[i][j] = data[j]
|
||||||
}
|
}
|
||||||
@@ -386,7 +386,7 @@ func (d *Device) enable(cfg enableConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
|
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
|
||||||
legacy.WriteRegister(d.bus, d.Address, APDS9960_ENABLE_REG, data)
|
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
|
||||||
|
|
||||||
if cfg.PON {
|
if cfg.PON {
|
||||||
time.Sleep(time.Millisecond * 10)
|
time.Sleep(time.Millisecond * 10)
|
||||||
@@ -395,7 +395,7 @@ func (d *Device) enable(cfg enableConfig) {
|
|||||||
|
|
||||||
func (d *Device) readStatus(param string) bool {
|
func (d *Device) readStatus(param string) bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, d.Address, APDS9960_STATUS_REG, data)
|
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
|
||||||
|
|
||||||
switch param {
|
switch param {
|
||||||
case "CPSAT":
|
case "CPSAT":
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
//go:build !nano_33_ble
|
//go:build !nano_33_ble
|
||||||
|
// +build !nano_33_ble
|
||||||
|
|
||||||
package apds9960
|
package apds9960
|
||||||
|
|
||||||
|
import "tinygo.org/x/drivers"
|
||||||
|
|
||||||
// Configure sets up the APDS-9960 device.
|
// Configure sets up the APDS-9960 device.
|
||||||
func (d *Device) Configure(cfg Configuration) {
|
func (d *Device) Configure(cfg Configuration) {
|
||||||
// configure device
|
// configure device
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build nano_33_ble
|
//go:build nano_33_ble
|
||||||
|
// +build nano_33_ble
|
||||||
|
|
||||||
package apds9960
|
package apds9960
|
||||||
|
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
// Product: https://ams.com/as5600
|
|
||||||
// Datasheet: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
|
|
||||||
|
|
||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AS5600 includes MPOS & MANG in addition to ZPOS to set a 'narrower angle range'
|
|
||||||
// ZPOS enables setting the 'zero position' of the device to any RAW_ANGLE value.
|
|
||||||
// MPOS ('max position') & MANG 'max angle' enable a 'partial range' on the AS5600.
|
|
||||||
// The value in ANGLE is scaled & adjusted by the device according to ZPOS and MPOS/MANG.
|
|
||||||
// The entire 12-bit range is 'compressed' into the RAW_ANGLE range of ZPOS->MPOS
|
|
||||||
// (or ZPOS->ZPOS+MANG) thus enabling a higher resolution for a partial range.
|
|
||||||
// if ZPOS > MPOS (or ZPOS + MANG > 4095) i.e. the incremental range 'crosses zero'
|
|
||||||
// then the device will automatically compensate for the correct range.
|
|
||||||
// For RAW_ANGLE values outside of the partial range, ANGLE will be 'capped' at either
|
|
||||||
// 0 or 4095, depending on 'which end of the partial range is closer.'
|
|
||||||
|
|
||||||
// AS5600Device represents an ams AS5600 device driver accessed over I2C
|
|
||||||
type AS5600Device struct {
|
|
||||||
// promote BaseDevice
|
|
||||||
BaseDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAS5600 creates a new AS5600Device given an I2C bus
|
|
||||||
func NewAS5600(bus drivers.I2C) AS5600Device {
|
|
||||||
// Create base device
|
|
||||||
baseDev := newBaseDevice(bus)
|
|
||||||
// Add AS5600 specific registers
|
|
||||||
baseDev.registers[MPOS] = newI2CRegister(MPOS, 0, 0xfff, 2, reg_read|reg_write|reg_program)
|
|
||||||
baseDev.registers[MANG] = newI2CRegister(MANG, 0, 0xfff, 2, reg_read|reg_write|reg_program)
|
|
||||||
// Add AS5600 specific 'virtual registers'
|
|
||||||
conf, ok := baseDev.registers[CONF]
|
|
||||||
if ok {
|
|
||||||
baseDev.registers[PWMF] = newVirtualRegister(conf, 6, 0b11)
|
|
||||||
baseDev.registers[OUTS] = newVirtualRegister(conf, 4, 0b11)
|
|
||||||
}
|
|
||||||
// Return the device
|
|
||||||
return AS5600Device{baseDev}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure sets up the AMS AS5600 sensor device with the given configuration.
|
|
||||||
func (d *AS5600Device) Configure(cfg Config) error {
|
|
||||||
// Call the BaseDevice method to do the actual Configure
|
|
||||||
d.BaseDevice.Configure(cfg)
|
|
||||||
// For AS5600 devices we need to calculate the maxAngle on startup from ZPOS/MPOS/MANG
|
|
||||||
// These could have been permanently BURN'ed (by writing BURN register with BURN_ANGLE/BURN_SETTING)
|
|
||||||
// or may have already been written in previous runs without a power cycle since.
|
|
||||||
mpos, err := d.ReadRegister(MPOS)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mang, err := d.ReadRegister(MANG)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Read ZPOS for side effect of caching only so that next calculateEffectiveMaxAngle() can't fail
|
|
||||||
if _, err = d.ReadRegister(ZPOS); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if mpos != 0 {
|
|
||||||
// If MPOS is set, use MPOS regardless of MANG
|
|
||||||
err = d.calculateEffectiveMaxAngle(MPOS, mpos)
|
|
||||||
} else if mang != 0 {
|
|
||||||
// If MANG is set and MPOS == 0, use MANG
|
|
||||||
err = d.calculateEffectiveMaxAngle(MANG, mang)
|
|
||||||
} else {
|
|
||||||
// if neither is set, we have no narrow range
|
|
||||||
d.maxAngle = NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateEffectiveMaxAngle calculates d.maxAngle after one of ZPOS/MPOS/MANG have been written
|
|
||||||
func (d *AS5600Device) calculateEffectiveMaxAngle(register uint8, value uint16) error {
|
|
||||||
|
|
||||||
var zpos, mpos uint16 = 0, 0
|
|
||||||
var err error = nil
|
|
||||||
|
|
||||||
switch register {
|
|
||||||
case MANG:
|
|
||||||
d.maxAngle = value // The easy case
|
|
||||||
return nil
|
|
||||||
case ZPOS:
|
|
||||||
zpos = value
|
|
||||||
mpos, err = d.ReadRegister(MPOS)
|
|
||||||
case MPOS:
|
|
||||||
mpos = value
|
|
||||||
zpos, err = d.ReadRegister(ZPOS)
|
|
||||||
default:
|
|
||||||
panic("calculateEffectiveMaxAngle() can only work from ZPOS, MPOS or MANG")
|
|
||||||
}
|
|
||||||
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// MANG is effectively MPOS-ZPOS
|
|
||||||
mang := int(mpos) - int(zpos)
|
|
||||||
// correct for mpos < zpos
|
|
||||||
if mang < 0 {
|
|
||||||
mang += NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
d.maxAngle = uint16(mang)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteRegister writes the given value for the given register to the AS560x device via I2C
|
|
||||||
func (d *AS5600Device) WriteRegister(address uint8, value uint16) error {
|
|
||||||
// Call the BaseDevice method to do the actual write
|
|
||||||
if err := d.BaseDevice.WriteRegister(address, value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// When either ZPOS/MANG/MPOS are set we need to recalculate maxAngle
|
|
||||||
// We also may need to invalidate some cached values for the other two registers
|
|
||||||
recalc := false
|
|
||||||
switch address {
|
|
||||||
case ZPOS:
|
|
||||||
// Setting a new ZPOS invalidates MPOS but not MANG
|
|
||||||
d.registers[MPOS].invalidate()
|
|
||||||
recalc = true
|
|
||||||
case MPOS:
|
|
||||||
// Setting a new MPOS invalidates MANG but not ZPOS
|
|
||||||
d.registers[MANG].invalidate()
|
|
||||||
recalc = true
|
|
||||||
case MANG:
|
|
||||||
// Setting a new MANG invalidates MPOS but not ZPOS
|
|
||||||
d.registers[MPOS].invalidate()
|
|
||||||
recalc = true
|
|
||||||
}
|
|
||||||
if recalc {
|
|
||||||
// Datasheet tells us to wait at least 1ms before reading back
|
|
||||||
time.Sleep(time.Millisecond * 10) // conservative wait
|
|
||||||
return d.calculateEffectiveMaxAngle(address, value)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMaxPosition returns the 'max position' (MPOS) in different units
|
|
||||||
func (d *AS5600Device) GetMaxPosition(units AngleUnit) (uint16, float32, error) {
|
|
||||||
mpos, err := d.ReadRegister(MPOS)
|
|
||||||
if nil != err {
|
|
||||||
return 0, 0.0, err
|
|
||||||
}
|
|
||||||
// Convert to requested units
|
|
||||||
i, f := convertFromNativeAngle(mpos, NATIVE_ANGLE_RANGE, units)
|
|
||||||
return i, f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMaxPosition sets the 'max position' (MPOS) in different units
|
|
||||||
func (d *AS5600Device) SetMaxPosition(mpos float32, units AngleUnit) error {
|
|
||||||
return d.WriteRegister(MPOS, convertToNativeAngle(mpos, units))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMaxAngle returns the 'max position' (MANG) in different units
|
|
||||||
func (d *AS5600Device) GetMaxAngle(units AngleUnit) (uint16, float32, error) {
|
|
||||||
mang, err := d.ReadRegister(MANG)
|
|
||||||
if nil != err {
|
|
||||||
return 0, 0.0, err
|
|
||||||
}
|
|
||||||
// Convert to requested units
|
|
||||||
i, f := convertFromNativeAngle(mang, NATIVE_ANGLE_RANGE, units)
|
|
||||||
return i, f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMaxAngle sets the 'max angle' (MANG) in different units
|
|
||||||
func (d *AS5600Device) SetMaxAngle(mang float32, units AngleUnit) error {
|
|
||||||
return d.WriteRegister(MANG, convertToNativeAngle(mang, units))
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Product: https://ams.com/as5601
|
|
||||||
// Datasheet: https://ams.com/documents/20143/36005/AS5601_DS000395_3-00.pdf
|
|
||||||
|
|
||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
import "tinygo.org/x/drivers"
|
|
||||||
|
|
||||||
// AS5601Device represents an ams AS5601 device driver accessed over I2C
|
|
||||||
type AS5601Device struct {
|
|
||||||
BaseDevice // promote base device
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAS5601 creates a new AS5601Device given an I2C bus
|
|
||||||
func NewAS5601(bus drivers.I2C) AS5601Device {
|
|
||||||
// Create base device
|
|
||||||
baseDev := newBaseDevice(bus)
|
|
||||||
// Add AS5601 specific registers
|
|
||||||
baseDev.registers[ABN] = newI2CRegister(ABN, 0, 0b1111, 1, reg_read|reg_write|reg_program)
|
|
||||||
baseDev.registers[PUSHTHR] = newI2CRegister(PUSHTHR, 0, 0xff, 1, reg_read|reg_write|reg_program)
|
|
||||||
// Return the device
|
|
||||||
return AS5601Device{baseDev}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
// Package as560x implements drivers for the ams AS5600/AS5601 on-axis magnetic rotary position sensors
|
|
||||||
//
|
|
||||||
// Product Pages:
|
|
||||||
// AS5600: https://ams.com/as5600
|
|
||||||
// AS5601: https://ams.com/as5601
|
|
||||||
//
|
|
||||||
// Datasheets:
|
|
||||||
// AS5600: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
|
|
||||||
// AS5601: https://ams.com/documents/20143/36005/AS5601_DS000395_3-00.pdf
|
|
||||||
//
|
|
||||||
|
|
||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config holds the configuration for the AMS AS560x sensor devices.
|
|
||||||
type Config struct {
|
|
||||||
// Address is the I2C address of the AS560x device. If left zero this will default to 0x36
|
|
||||||
Address uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// MagnetStrength is an enum to indicate the magnetic field strength detected by the AS560x sensors.
|
|
||||||
type MagnetStrength int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// MagnetTooWeak indicates that the magnet strength is too weak (AGC maximum gain overflow) - move it closer
|
|
||||||
MagnetTooWeak MagnetStrength = iota - 1
|
|
||||||
// MagnetOk indicates that the magnet strength is about right.
|
|
||||||
MagnetOk
|
|
||||||
// MagnetTooStrong indicates that the magnet strength is too strong (AGC minimum gain overflow) - move it further away
|
|
||||||
MagnetTooStrong
|
|
||||||
)
|
|
||||||
|
|
||||||
// AngleUnit is an enum to allow the use of different units when reading/writing angles from the AS560x sensors.
|
|
||||||
type AngleUnit int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ANGLE_NATIVE uses the device's native angle measurement. i.e. 12-bit integer, 0 <= angle <= 0xfff (4095)
|
|
||||||
ANGLE_NATIVE AngleUnit = iota
|
|
||||||
// ANGLE_DEGREES_INT measures angles in degrees using integer arithmetic for speed. i.e. 0 <= angle < 360
|
|
||||||
ANGLE_DEGREES_INT
|
|
||||||
// ANGLE_DEGREES_FLOAT measures angles in degrees using floating point (slower). i.e. 0.0 <= angle < 360.0
|
|
||||||
ANGLE_DEGREES_FLOAT
|
|
||||||
// ANGLE_RADIANS measures angles in radians using floating point (slower). i.e. 0.0 <= angle < 2 * PI
|
|
||||||
ANGLE_RADIANS
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// NATIVE_ANGLE_MAX is the maximum valid value for a native angle for a AS560x device
|
|
||||||
NATIVE_ANGLE_MAX = (1 << 12) - 1 + iota
|
|
||||||
// NATIVE_ANGLE_RANGE is the number of unique values for native angles for a AS560x device
|
|
||||||
NATIVE_ANGLE_RANGE
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errRegisterNotFound = errors.New("Register not found")
|
|
||||||
errMaxBurnAngle = errors.New("Max BURN_ANGLE limit reached")
|
|
||||||
)
|
|
||||||
|
|
||||||
// BaseDevice handles the common behaviour between AS5600 & AS5601 devices
|
|
||||||
type BaseDevice struct {
|
|
||||||
bus drivers.I2C
|
|
||||||
address uint8
|
|
||||||
registers map[uint8]*i2cRegister
|
|
||||||
maxAngle uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// newBaseDevice creates a new base device given an I2C bus.
|
|
||||||
func newBaseDevice(bus drivers.I2C) BaseDevice {
|
|
||||||
// Add all 'base' registers, common to both AS5600 & AS5601
|
|
||||||
conf := newI2CRegister(CONF, 0, 0x3fff, 2, reg_read|reg_write|reg_program)
|
|
||||||
status := newI2CRegister(STATUS, 0, 0xff, 1, reg_read)
|
|
||||||
regs := map[uint8]*i2cRegister{
|
|
||||||
ZPOS: newI2CRegister(ZPOS, 0, 0xfff, 2, reg_read|reg_write|reg_program),
|
|
||||||
CONF: conf,
|
|
||||||
RAW_ANGLE: newI2CRegister(RAW_ANGLE, 0, 0xfff, 2, reg_read),
|
|
||||||
ANGLE: newI2CRegister(ANGLE, 0, 0xfff, 2, reg_read),
|
|
||||||
STATUS: status,
|
|
||||||
AGC: newI2CRegister(AGC, 0, 0xff, 1, reg_read),
|
|
||||||
MAGNITUDE: newI2CRegister(MAGNITUDE, 0, 0xfff, 2, reg_read),
|
|
||||||
BURN: newI2CRegister(BURN, 0, 0xff, 1, reg_write),
|
|
||||||
// Add common 'virtual registers' These are bitfields within the common registers above
|
|
||||||
// A virtual register provides a convenient way to access the fields of a registers
|
|
||||||
// by handling all of the necessary bitfield shifting and masking operations
|
|
||||||
WD: newVirtualRegister(conf, 13, 0b1),
|
|
||||||
FTH: newVirtualRegister(conf, 10, 0b111),
|
|
||||||
SF: newVirtualRegister(conf, 8, 0b11),
|
|
||||||
HYST: newVirtualRegister(conf, 2, 0b11),
|
|
||||||
PM: newVirtualRegister(conf, 0, 0b11),
|
|
||||||
MD: newVirtualRegister(status, 5, 0b1),
|
|
||||||
ML: newVirtualRegister(status, 4, 0b1),
|
|
||||||
MH: newVirtualRegister(status, 3, 0b1),
|
|
||||||
}
|
|
||||||
return BaseDevice{bus, DefaultAddress, regs, NATIVE_ANGLE_RANGE}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure sets up the AMS AS560x sensor device with the given configuration.
|
|
||||||
func (d *BaseDevice) Configure(cfg Config) {
|
|
||||||
if cfg.Address == 0 {
|
|
||||||
cfg.Address = DefaultAddress
|
|
||||||
}
|
|
||||||
d.address = cfg.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadRegister reads the value for the given register from the AS560x device via I2C
|
|
||||||
func (d *BaseDevice) ReadRegister(address uint8) (uint16, error) {
|
|
||||||
reg, ok := d.registers[address]
|
|
||||||
if !ok {
|
|
||||||
return 0, errRegisterNotFound
|
|
||||||
}
|
|
||||||
return reg.read(d.bus, d.address)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteRegister writes the given value for the given register to the AS560x device via I2C
|
|
||||||
func (d *BaseDevice) WriteRegister(address uint8, value uint16) error {
|
|
||||||
reg, ok := d.registers[address]
|
|
||||||
if !ok {
|
|
||||||
return errRegisterNotFound
|
|
||||||
}
|
|
||||||
return reg.write(d.bus, d.address, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetZeroPosition returns the 'zero position' (ZPOS) in various units
|
|
||||||
func (d *BaseDevice) GetZeroPosition(units AngleUnit) (uint16, float32, error) {
|
|
||||||
zpos, err := d.ReadRegister(ZPOS)
|
|
||||||
if nil != err {
|
|
||||||
return 0, 0.0, err
|
|
||||||
}
|
|
||||||
// Convert to requested units
|
|
||||||
i, f := convertFromNativeAngle(zpos, NATIVE_ANGLE_RANGE, units)
|
|
||||||
return i, f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetZeroPosition sets the 'zero position' (ZPOS) in various units
|
|
||||||
func (d *BaseDevice) SetZeroPosition(zpos float32, units AngleUnit) error {
|
|
||||||
return d.WriteRegister(ZPOS, convertToNativeAngle(zpos, units))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RawAngle reads the (unscaled & unadjusted) RAW_ANGLE register in various units
|
|
||||||
func (d *BaseDevice) RawAngle(units AngleUnit) (uint16, float32, error) {
|
|
||||||
angle, err := d.ReadRegister(RAW_ANGLE)
|
|
||||||
if nil != err {
|
|
||||||
return 0, 0.0, err
|
|
||||||
}
|
|
||||||
// Convert to requested units
|
|
||||||
i, f := convertFromNativeAngle(angle, NATIVE_ANGLE_RANGE, units)
|
|
||||||
return i, f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle reads the (scaled & adjusted) ANGLE register in various units
|
|
||||||
func (d *BaseDevice) Angle(units AngleUnit) (uint16, float32, error) {
|
|
||||||
// ZPOS enables setting the 'zero position' of the device to any RAW_ANGLE value
|
|
||||||
// ANGLE is RAW_ANGLE adjusted relative to ZPOS.
|
|
||||||
angle, err := d.ReadRegister(ANGLE)
|
|
||||||
if nil != err {
|
|
||||||
return 0, 0.0, err
|
|
||||||
}
|
|
||||||
// Convert to requested units
|
|
||||||
i, f := convertFromNativeAngle(angle, d.maxAngle, units)
|
|
||||||
return i, f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MagnetStatus reads the STATUS register and reports magnet position characteristics
|
|
||||||
func (d *BaseDevice) MagnetStatus() (detected bool, strength MagnetStrength, err error) {
|
|
||||||
status, err := d.ReadRegister(STATUS)
|
|
||||||
if nil != err {
|
|
||||||
return false, MagnetOk, err
|
|
||||||
}
|
|
||||||
detected = (status & STATUS_MD) != 0
|
|
||||||
strength = MagnetOk
|
|
||||||
if (status & STATUS_ML) != 0 {
|
|
||||||
strength = MagnetTooWeak
|
|
||||||
} else if (status & STATUS_MH) != 0 {
|
|
||||||
strength = MagnetTooStrong
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Burn is a convenience method to program the device permanently by writing to the BURN register (limited number of times use!)
|
|
||||||
func (d *BaseDevice) Burn(burnCmd BURN_CMD) error {
|
|
||||||
if BURN_ANGLE == burnCmd {
|
|
||||||
// BURN_ANGLE can only be executed up to 3 times.
|
|
||||||
// We can check this in advance by reading ZMCO before writing to the BURN register.
|
|
||||||
numBurns, err := d.ReadRegister(ZMCO)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if numBurns >= BURN_ANGLE_COUNT_MAX {
|
|
||||||
// We're outta BURNs :(
|
|
||||||
return errMaxBurnAngle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d.WriteRegister(BURN, uint16(burnCmd))
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
import "math"
|
|
||||||
|
|
||||||
// convertFromNativeAngle converts and scales an angle from the device's native 12-bit range to the requested units
|
|
||||||
func convertFromNativeAngle(angle uint16, maxAngle uint16, units AngleUnit) (uint16, float32) {
|
|
||||||
// MANG == 0 & MANG == NATIVE_ANGLE_RANGE (1 << 12) mean the same thing: use full circle range
|
|
||||||
// but the latter makes the maths/code simpler
|
|
||||||
if 0 == maxAngle {
|
|
||||||
maxAngle = NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
switch units {
|
|
||||||
case ANGLE_NATIVE:
|
|
||||||
// For native angles, scaling has already been done by the device
|
|
||||||
return angle, float32(angle)
|
|
||||||
case ANGLE_DEGREES_INT:
|
|
||||||
// Convert to degrees using integer arithmetic. Less accuracy but faster
|
|
||||||
var deg int = 0
|
|
||||||
if NATIVE_ANGLE_RANGE == maxAngle {
|
|
||||||
// Simplify the conversion when using the full range
|
|
||||||
deg = int(angle) * 360 >> 12
|
|
||||||
} else {
|
|
||||||
// Using an integer degrees scale with a narrower native range is pointless since we don't
|
|
||||||
// benefit at all from the increase in native resolution, in fact we LOSE precision.
|
|
||||||
// Alas, we have to return something
|
|
||||||
// First get maxAngle on the degrees scale
|
|
||||||
degMang, _ := convertFromNativeAngle(maxAngle, NATIVE_ANGLE_RANGE, units)
|
|
||||||
// Now scale angle
|
|
||||||
deg = int(angle) * int(degMang) / NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
return uint16(deg), float32(deg)
|
|
||||||
case ANGLE_DEGREES_FLOAT:
|
|
||||||
// Convert to degrees using floating point. More accuracy at expense of speed
|
|
||||||
var degF float32 = 0.0
|
|
||||||
if NATIVE_ANGLE_RANGE == maxAngle {
|
|
||||||
// Simplify the conversion when using the full range
|
|
||||||
degF = float32(angle) * 360.0 / NATIVE_ANGLE_RANGE
|
|
||||||
} else {
|
|
||||||
// Scale to degrees using a narrower native range
|
|
||||||
// First get maxAngle on the degrees scale
|
|
||||||
_, degMangF := convertFromNativeAngle(maxAngle, NATIVE_ANGLE_RANGE, units)
|
|
||||||
// Now scale angle
|
|
||||||
degF = float32(angle) * degMangF / NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
return uint16(degF), degF
|
|
||||||
case ANGLE_RADIANS:
|
|
||||||
// Convert to radians. Can only be done using floating point.
|
|
||||||
var rad float32 = 0.0
|
|
||||||
if NATIVE_ANGLE_RANGE == maxAngle {
|
|
||||||
// Simplify the conversion when using the full range
|
|
||||||
rad = float32(angle) * 2 * math.Pi / NATIVE_ANGLE_RANGE
|
|
||||||
} else {
|
|
||||||
// Scale to radians using a narrower native range
|
|
||||||
// First get maxAngle on the radians scale
|
|
||||||
_, radMang := convertFromNativeAngle(maxAngle, NATIVE_ANGLE_RANGE, units)
|
|
||||||
// Now scale angle
|
|
||||||
rad = float32(angle) * radMang / NATIVE_ANGLE_RANGE
|
|
||||||
}
|
|
||||||
return uint16(rad), rad
|
|
||||||
default:
|
|
||||||
panic("Unknown angle measurement unit")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertToNativeAngle converts an angle from the requested units to the device's native 12-bit range.
|
|
||||||
func convertToNativeAngle(angle float32, units AngleUnit) uint16 {
|
|
||||||
var pos uint16 = 0
|
|
||||||
switch units {
|
|
||||||
case ANGLE_NATIVE:
|
|
||||||
pos = uint16(angle)
|
|
||||||
case ANGLE_DEGREES_INT:
|
|
||||||
fallthrough
|
|
||||||
case ANGLE_DEGREES_FLOAT:
|
|
||||||
// Convert from degrees
|
|
||||||
angle = float32(math.Mod(float64(angle), 360.0))
|
|
||||||
if angle < 0.0 {
|
|
||||||
angle += 360.0
|
|
||||||
}
|
|
||||||
pos = uint16(math.Round(float64(angle) * NATIVE_ANGLE_RANGE / 360.0))
|
|
||||||
case ANGLE_RADIANS:
|
|
||||||
// Convert from radians
|
|
||||||
const circRad = 2.0 * math.Pi
|
|
||||||
angle = float32(math.Mod(float64(angle), circRad))
|
|
||||||
if angle < 0.0 {
|
|
||||||
angle += circRad
|
|
||||||
}
|
|
||||||
pos = uint16(math.Round(float64(angle) * NATIVE_ANGLE_RANGE / circRad))
|
|
||||||
default:
|
|
||||||
panic("Unknown angle measurement unit")
|
|
||||||
}
|
|
||||||
if pos > NATIVE_ANGLE_MAX {
|
|
||||||
pos = NATIVE_ANGLE_MAX
|
|
||||||
}
|
|
||||||
return pos
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
|
||||||
|
|
||||||
// registerAttributes is a bitfield of attributes for a register
|
|
||||||
type registerAttributes uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// reg_read indicates that the register is readable
|
|
||||||
reg_read registerAttributes = 1 << iota
|
|
||||||
// reg_write indicates that the register is writeable
|
|
||||||
reg_write
|
|
||||||
// reg_program indicates that the register can be permanently programmed ('BURNed')
|
|
||||||
reg_program
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errRegisterNotReadable = errors.New("Register is not readable")
|
|
||||||
errRegisterNotWriteable = errors.New("Register is not writeable")
|
|
||||||
)
|
|
||||||
|
|
||||||
// i2cRegister encapsulates the address, structure and read/write logic for a register on a AS560x device
|
|
||||||
type i2cRegister struct {
|
|
||||||
// host is the 'host register' for virtual registers. Physical/root registers have this set to self
|
|
||||||
host *i2cRegister
|
|
||||||
// address is the i2c address of the register. For 2-byte (word) addresses it's the low byte which holds the MSBs
|
|
||||||
address uint8
|
|
||||||
// shift is the number of bits the value is 'left shifted' into the register byte/word (0-15)
|
|
||||||
shift uint16
|
|
||||||
// mask is a bitwise mask applied to the register AFTER 'right shifting' to mask the register value
|
|
||||||
mask uint16
|
|
||||||
// num_bytes is the width of the register in bytes, 1 or 2.
|
|
||||||
num_bytes uint8
|
|
||||||
// attributes holds the register attributes. A bitfield of REG_xyz constants
|
|
||||||
attributes registerAttributes
|
|
||||||
// cached indicates whether we are holding a cached value of the register in value
|
|
||||||
cached bool
|
|
||||||
// value can be used as a 'cache' of the register's value for writeable registers.
|
|
||||||
value uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// newI2CRegister returns a pointer to a new i2cRegister with no cached value
|
|
||||||
func newI2CRegister(address uint8, shift uint16, mask uint16, num_bytes uint8, attributes registerAttributes) *i2cRegister {
|
|
||||||
reg := &i2cRegister{
|
|
||||||
address: address,
|
|
||||||
shift: shift,
|
|
||||||
mask: mask,
|
|
||||||
num_bytes: num_bytes,
|
|
||||||
attributes: attributes,
|
|
||||||
}
|
|
||||||
// root registers host themselves
|
|
||||||
reg.host = reg
|
|
||||||
return reg
|
|
||||||
}
|
|
||||||
|
|
||||||
// newVirtualRegister returns a pointer to a new i2cRegister with the given host register and shift/mask.
|
|
||||||
func newVirtualRegister(host *i2cRegister, shift uint16, mask uint16) *i2cRegister {
|
|
||||||
return &i2cRegister{
|
|
||||||
host: host,
|
|
||||||
address: host.address,
|
|
||||||
shift: shift,
|
|
||||||
mask: mask,
|
|
||||||
num_bytes: host.num_bytes,
|
|
||||||
attributes: host.attributes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// invalidate invalidates any cached value for the register and forces an I2C read on the next read()
|
|
||||||
func (r *i2cRegister) invalidate() {
|
|
||||||
r.host.cached = false
|
|
||||||
r.host.value = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// readShiftAndMask is an internal method to read a value for the register over the given I2C bus from the device with the given address applying the given shift and mask
|
|
||||||
func (r *i2cRegister) readShiftAndMask(bus drivers.I2C, deviceAddress uint8, shift uint16, mask uint16) (uint16, error) {
|
|
||||||
if r.host.attributes®_read == 0 {
|
|
||||||
return 0, errRegisterNotReadable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only read over I2C if we don't have the host register value cached
|
|
||||||
var val uint16 = r.host.value
|
|
||||||
if !r.host.cached {
|
|
||||||
// To avoid an alloc we always use an array of 2 bytes
|
|
||||||
var buffer [2]byte
|
|
||||||
var buf []byte
|
|
||||||
if r.host.num_bytes < 2 {
|
|
||||||
buf = buffer[:1]
|
|
||||||
} else {
|
|
||||||
buf = buffer[:]
|
|
||||||
}
|
|
||||||
// Read the host register over I2C
|
|
||||||
err := legacy.ReadRegister(bus, deviceAddress, r.host.address, buf)
|
|
||||||
if nil != err {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Unpack data from I2C
|
|
||||||
if r.host.num_bytes > 1 {
|
|
||||||
val = binary.BigEndian.Uint16(buf)
|
|
||||||
} else {
|
|
||||||
val = uint16(buf[0])
|
|
||||||
}
|
|
||||||
// cache this value if the host register is writeable. Note we cache the entire buffer without applying shift/mask
|
|
||||||
if r.host.attributes®_write != 0 {
|
|
||||||
r.host.value = val
|
|
||||||
r.host.cached = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Shift and mask the value before returning
|
|
||||||
val >>= shift
|
|
||||||
val &= mask
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// read reads a value for the register over the given I2C bus from the device with the given address.
|
|
||||||
func (r *i2cRegister) read(bus drivers.I2C, deviceAddress uint8) (uint16, error) {
|
|
||||||
return r.readShiftAndMask(bus, deviceAddress, r.shift, r.mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
// write writes a value for the register over the given I2C bus to the device with the given address.
|
|
||||||
func (r *i2cRegister) write(bus drivers.I2C, deviceAddress uint8, value uint16) error {
|
|
||||||
if r.host.attributes®_write == 0 {
|
|
||||||
return errRegisterNotWriteable
|
|
||||||
}
|
|
||||||
var newValue uint16 = 0
|
|
||||||
// Data sheet tells us to do a read first, modify only the desired bits and then write back
|
|
||||||
// since (quote:) 'Blank fields may contain factory settings'
|
|
||||||
// We will also need to do this anyway to support virtualRegister mappings on some registers
|
|
||||||
// (e.g. CONF/STATUS)
|
|
||||||
if (r.host.attributes & reg_read) > 0 { // not all registers are readable, e.g. BURN
|
|
||||||
// read the host register's entire host byte/word, regardless of shift & mask
|
|
||||||
readValue, error := r.readShiftAndMask(bus, deviceAddress, 0, 0xffff)
|
|
||||||
if error != nil {
|
|
||||||
return error
|
|
||||||
}
|
|
||||||
// Zero-out ONLY the relevant bits in newValue we just read
|
|
||||||
readValue &= (0xffff ^ (r.mask << r.shift))
|
|
||||||
newValue = readValue
|
|
||||||
}
|
|
||||||
// Mask the new value and shift it into place
|
|
||||||
value &= r.mask
|
|
||||||
value <<= r.shift
|
|
||||||
// OR the masked & shifted value back into newValue to be written
|
|
||||||
newValue |= value
|
|
||||||
// Pack newValue into a byte buffer to write. To avoid an alloc we always use an array of 2 bytes
|
|
||||||
var buffer [2]byte
|
|
||||||
var buf []byte
|
|
||||||
if r.host.num_bytes < 2 {
|
|
||||||
buf = buffer[:1]
|
|
||||||
buf[0] = uint8(newValue & 0xff)
|
|
||||||
} else {
|
|
||||||
buf = buffer[:]
|
|
||||||
binary.BigEndian.PutUint16(buf, newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the register from the buffer over I2C
|
|
||||||
err := legacy.WriteRegister(bus, deviceAddress, r.host.address, buf)
|
|
||||||
// after successful I2C write, cache this value if the host register (if also readable)
|
|
||||||
// Note we cache the entire buffer without applying shift/mask
|
|
||||||
if nil == err && r.host.attributes®_read != 0 {
|
|
||||||
r.host.value = newValue
|
|
||||||
r.host.cached = true
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
package as560x // import tinygo.org/x/drivers/ams560x
|
|
||||||
|
|
||||||
// DefaultAddress is the default I2C address of the AMS AS560x sensors (0x36).
|
|
||||||
const DefaultAddress uint8 = 0x36
|
|
||||||
|
|
||||||
// AS560x common device registers
|
|
||||||
const (
|
|
||||||
// ZMCO contains the number of times a BURN_ANGLE command has been executed (max 3 burns)
|
|
||||||
ZMCO = 0x00
|
|
||||||
// ZPOS is the zero (start) position in RAW_ANGLE terms.
|
|
||||||
ZPOS = 0x01
|
|
||||||
// CONF supports custom config. Raw 14-bit register. See datasheet for mapping or use 'virtual registers' below.
|
|
||||||
CONF = 0x07
|
|
||||||
// STATUS indicates magnet position. Encapsulates MD, ML & MH. See also 'virtual registers' below.
|
|
||||||
STATUS = 0x0b
|
|
||||||
// RAW_ANGLE is the raw unscaled & unadjusted angle (12 bit: 0-4095/0xfff)
|
|
||||||
RAW_ANGLE = 0x0c
|
|
||||||
// ANGLE is RAW_ANGLE scaled & adjusted according to ZPOS (and MPOS/MANG on AS5600). (12 bit: 0-4095/0xfff)
|
|
||||||
ANGLE = 0x0e
|
|
||||||
// AGC is the Automatic Gain Control based on temp, airgap etc. 0-255 @ 5V, 0-128 @ 3.3V.
|
|
||||||
AGC = 0x1a
|
|
||||||
// MAGNITUDE indicates the magnitude value of the internal CORDIC output. See datasheet for more info.
|
|
||||||
MAGNITUDE = 0x1b
|
|
||||||
// BURN performs permanent programming of some registers. See BURN_XYZ cmd constants below for commands.
|
|
||||||
BURN = 0xff
|
|
||||||
)
|
|
||||||
|
|
||||||
// AS5600 specific registers
|
|
||||||
const (
|
|
||||||
// MPOS is the maximum position in RAW_ANGLE terms. With ZPOS, defines a 'narrower angle' for higher resolution.
|
|
||||||
MPOS = 0x03
|
|
||||||
// MANG is the maximum angle. With ZPOS, defines a 'narrower angle' for higher resolution.
|
|
||||||
MANG = 0x05
|
|
||||||
)
|
|
||||||
|
|
||||||
// AS5601 specific registers
|
|
||||||
const (
|
|
||||||
// ABN. See datasheet for mapping
|
|
||||||
ABN = 0x09
|
|
||||||
// PUSHTHR. Configures push-button function. See datasheet and AGC
|
|
||||||
PUSHTHR = 0x0a
|
|
||||||
)
|
|
||||||
|
|
||||||
// 'Virtual Registers' (VRs) are bitfields within the registers above.
|
|
||||||
// These are not real register addresses recognized by the chip,
|
|
||||||
// but they are recognized by the driver for convenience.
|
|
||||||
|
|
||||||
// virtualRegisterStartAddress defines the start of the virtual register address range.
|
|
||||||
const virtualRegisterStartAddress = 0xa0
|
|
||||||
|
|
||||||
const (
|
|
||||||
// VRs for CONF
|
|
||||||
|
|
||||||
// WD is a Virtual Register for the Watchdog timer. See WATCHDOG_TIMER consts.
|
|
||||||
WD = iota + virtualRegisterStartAddress
|
|
||||||
// FTH is a Virtual Register for the Fast Filter Threshold. See FAST_FILTER_THRESHOLD consts.
|
|
||||||
FTH
|
|
||||||
// SF is a Virtual Register for the Slow Filter. See SLOW_FILTER_RESPONSE consts.
|
|
||||||
SF
|
|
||||||
// PWMF is a Virtual Register for PWM Frequency (AS5600 ONLY). See PWM_FREQUENCY consts.
|
|
||||||
PWMF
|
|
||||||
// OUTS is a Virtual Register for the Output Stage (AS5600 ONLY). See OUTPUT_STAGE consts.
|
|
||||||
OUTS
|
|
||||||
// HYST is a Virtual Register for Hysteresis. See HYSTERESIS consts.
|
|
||||||
HYST
|
|
||||||
// PM is a Virtual Register for the Power Mode. See POWER_MODE consts.
|
|
||||||
PM
|
|
||||||
|
|
||||||
// VRs for STATUS (0 = unset, 1 = set)
|
|
||||||
|
|
||||||
// MD is a Virtual Register for the 'Magnet was detected' flag.
|
|
||||||
MD
|
|
||||||
// ML is a Virtual Register for the 'AGC maximum gain overflow' a.k.a 'magnet too weak' flag.
|
|
||||||
ML
|
|
||||||
// MH is a Virtual Register for the 'AGC minimum gain overflow' a.k.a 'magnet too strong' flag.
|
|
||||||
MH
|
|
||||||
)
|
|
||||||
|
|
||||||
// POWER_MODE values for the PM component of CONF (and the PM VR)
|
|
||||||
const (
|
|
||||||
// PM_NOM is the normal 'always on' power mode. No polling, max 6.5mA current
|
|
||||||
PM_NOM = iota
|
|
||||||
// PM_LPM1 is Low Power Mode 1. 5ms polling, max 3.4mA current
|
|
||||||
PM_LPM1
|
|
||||||
// PM_LPM2 is Low Power Mode 2. 20ms polling, max 1.8mA current
|
|
||||||
PM_LPM2
|
|
||||||
// PM_LPM3 is Low Power Mode 3. 100ms polling, max 1.5mA current
|
|
||||||
PM_LPM3
|
|
||||||
)
|
|
||||||
|
|
||||||
// HYSTERESIS values for the HYST component of CONF (and the HYST VR)
|
|
||||||
const (
|
|
||||||
// HYST_OFF disables any hysteresis of the output
|
|
||||||
HYST_OFF = iota
|
|
||||||
// HYST_1LSB enables output hysteresis using 1 LSB
|
|
||||||
HYST_1LSB
|
|
||||||
// HYST_2LSB enables output hysteresis using 2 LSBs
|
|
||||||
HYST_2LSB
|
|
||||||
// HYST_3LSB enables output hysteresis using 3 LSBs
|
|
||||||
HYST_3LSB
|
|
||||||
)
|
|
||||||
|
|
||||||
// OUTPUT_STAGE values for the OUTS component of CONF (and the OUTS VR - AS5600 ONLY)
|
|
||||||
const (
|
|
||||||
// OS_ANALOG_FULL_RANGE enables analog output with full range (0%-100% VDD)
|
|
||||||
OS_ANALOG_FULL_RANGE = iota
|
|
||||||
// OS_ANALOG_REDUCED_RANGE enables analog output with reduced range (10%-90% VDD)
|
|
||||||
OS_ANALOG_REDUCED_RANGE
|
|
||||||
// OS_DIGITAL_PWM enables digital PWM output. Frequency determined by PWMF
|
|
||||||
OS_DIGITAL_PWM
|
|
||||||
)
|
|
||||||
|
|
||||||
// PWM_FREQUENCY values for the PWMF component of CONF (and the PWMF VR - ASS5600 ONLY)
|
|
||||||
const (
|
|
||||||
// PWMF_115_HZ enables PWM at 115 Hz
|
|
||||||
PWMF_115_HZ = iota
|
|
||||||
// PWMF_230_HZ enables PWM at 230 Hz
|
|
||||||
PWMF_230_HZ
|
|
||||||
// PWMF_460_HZ enables PWM at 460 Hz
|
|
||||||
PWMF_460_HZ
|
|
||||||
// PWMF_920_HZ enables PWM at 920 Hz
|
|
||||||
PWMF_920_HZ
|
|
||||||
)
|
|
||||||
|
|
||||||
// SLOW_FILTER_RESPONSE values for the SF (slow filter) component of CONF (and the SF VR)
|
|
||||||
const (
|
|
||||||
// SF_16X enables a 16x Slow Filter step response
|
|
||||||
SF_16X = iota
|
|
||||||
// SF_8X enables a 8x Slow Filter step response
|
|
||||||
SF_8X
|
|
||||||
// SF_4X enables a 4x Slow Filter step response
|
|
||||||
SF_4X
|
|
||||||
// SF_2X enables a 2x Slow Filter step response
|
|
||||||
SF_2X
|
|
||||||
)
|
|
||||||
|
|
||||||
// FAST_FILTER_THRESHOLD values for the FTH (fast filter threshold) component of CONF (and the FTH VR)
|
|
||||||
const (
|
|
||||||
// FTH_NONE disables the fast filter (slow filter only)
|
|
||||||
FTH_NONE = iota
|
|
||||||
// FTH_6LSB enables a fast filter threshold with 6 LSBs
|
|
||||||
FTH_6LSB
|
|
||||||
// FTH_7LSB enables a fast filter threshold with 7 LSBs
|
|
||||||
FTH_7LSB
|
|
||||||
// FTH_9LSB enables a fast filter threshold with 9 LSBs
|
|
||||||
FTH_9LSB
|
|
||||||
// FTH_18LSB enables a fast filter threshold with 18 LSBs
|
|
||||||
FTH_18LSB
|
|
||||||
// FTH_21LSB enables a fast filter threshold with 21 LSBs
|
|
||||||
FTH_21LSB
|
|
||||||
// FTH_24LSB enables a fast filter threshold with 24 LSBs
|
|
||||||
FTH_24SB
|
|
||||||
// FTH_10LSB enables a fast filter threshold with 10 LSBs
|
|
||||||
FTH_10LSB
|
|
||||||
)
|
|
||||||
|
|
||||||
// WATCHDOG_TIMER values for the WD component of CONF (and the WD VR)
|
|
||||||
const (
|
|
||||||
// WD_OFF disables the Watchdog Timer
|
|
||||||
WD_OFF = iota
|
|
||||||
// WD_ON enables the Watchdog Timer (automatic entry into LPM3 low-power mode enabled)
|
|
||||||
WD_ON
|
|
||||||
)
|
|
||||||
|
|
||||||
// constants for the raw STATUS register bitfield value.
|
|
||||||
const (
|
|
||||||
// STATUS_MH is set in STATUS when the magnet field is too strong (AGC minimum gain overflow)
|
|
||||||
STATUS_MH = 1 << (iota + 3)
|
|
||||||
// STATUS_ML is set in STATUS when the magnet field is too weak (AGC maximum gain overflow)
|
|
||||||
STATUS_ML
|
|
||||||
// STATUS_MD is set n STATUS when the magnet is detected. Doesn't seem to work with some units.
|
|
||||||
STATUS_MD
|
|
||||||
)
|
|
||||||
|
|
||||||
// ABN_MAPPING values for the ABN register (AS5601 ONLY)
|
|
||||||
const (
|
|
||||||
// ABN_8 configures 8 output positions (61 Hz)
|
|
||||||
ABN_8 = iota
|
|
||||||
// ABN_16 configures 16 output positions (122 Hz)
|
|
||||||
ABN_16
|
|
||||||
// ABN_32 configures 32 output positions (244 Hz)
|
|
||||||
ABN_32
|
|
||||||
// ABN_64 configures 64 output positions (488 Hz)
|
|
||||||
ABN_64
|
|
||||||
// ABN_128 configures 128 output positions (976 Hz)
|
|
||||||
ABN_128
|
|
||||||
// ABN_256 configures 256 output positions (1.95 KHz)
|
|
||||||
ABN_256
|
|
||||||
// ABN_512 configures 512 output positions (3.9 KHz)
|
|
||||||
ABN_512
|
|
||||||
// ABN_1024 configures 1024 output positions (7.8 KHz)
|
|
||||||
ABN_1024
|
|
||||||
// ABN_2048 configures 2048 output positions (15.6 KHz)
|
|
||||||
ABN_2048
|
|
||||||
)
|
|
||||||
|
|
||||||
// BURN_CMD is a command to write to the BURN register.
|
|
||||||
type BURN_CMD uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
// BURN_ANGLE is the value to write to BURN to permanently program ZPOS & MPOS (Max 3 times!)
|
|
||||||
BURN_ANGLE BURN_CMD = 0x80
|
|
||||||
// BURN_SETTING is the value to write to BURN to permanently program MANG & CONF (ONCE ONLY!)
|
|
||||||
BURN_SETTING BURN_CMD = 0x40
|
|
||||||
)
|
|
||||||
|
|
||||||
// BURN_ANGLE_COUNT_MAX is a constant for the maximum number of times a BURN_ANGLE command can be executed. Compare this with ZMCO
|
|
||||||
const BURN_ANGLE_COUNT_MAX uint16 = 3
|
|
||||||
+3
-3
@@ -3,11 +3,11 @@
|
|||||||
//
|
//
|
||||||
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
|
// http://www.x-powers.com/en.php/Info/product_detail/article_id/29
|
||||||
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
|
// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf
|
||||||
|
//
|
||||||
package axp192 // import "tinygo.org/x/drivers/axp192"
|
package axp192 // import "tinygo.org/x/drivers/axp192"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error uint8
|
type Error uint8
|
||||||
@@ -249,10 +249,10 @@ func (d *Device) SetLDOEnable(number uint8, state bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) write1Byte(reg, data uint8) {
|
func (d *Device) write1Byte(reg, data uint8) {
|
||||||
legacy.WriteRegister(d.bus, d.Address, reg, []byte{data})
|
d.bus.WriteRegister(d.Address, reg, []byte{data})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) read8bit(reg uint8) uint8 {
|
func (d *Device) read8bit(reg uint8) uint8 {
|
||||||
legacy.ReadRegister(d.bus, d.Address, reg, d.buf[:1])
|
d.bus.ReadRegister(d.Address, reg, d.buf[:1])
|
||||||
return d.buf[0]
|
return d.buf[0]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// Datasheet:
|
// Datasheet:
|
||||||
// https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf
|
// https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf
|
||||||
|
//
|
||||||
package bh1750 // import "tinygo.org/x/drivers/bh1750"
|
package bh1750 // import "tinygo.org/x/drivers/bh1750"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Package blinkm implements a driver for the BlinkM I2C RGB LED.
|
// Package blinkm implements a driver for the BlinkM I2C RGB LED.
|
||||||
//
|
//
|
||||||
// Datasheet: http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf
|
// Datasheet: http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf
|
||||||
|
//
|
||||||
package blinkm // import "tinygo.org/x/drivers/blinkm"
|
package blinkm // import "tinygo.org/x/drivers/blinkm"
|
||||||
|
|
||||||
import "tinygo.org/x/drivers"
|
import "tinygo.org/x/drivers"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,352 +0,0 @@
|
|||||||
// Package bma42x provides a driver for the BMA421 and BMA425 accelerometer
|
|
||||||
// chips.
|
|
||||||
//
|
|
||||||
// Here is a reasonably good datasheet:
|
|
||||||
// https://datasheet.lcsc.com/lcsc/1912111437_Bosch-Sensortec-BMA425_C437656.pdf
|
|
||||||
//
|
|
||||||
// This driver was originally written for the PineTime, using the datasheet as a
|
|
||||||
// guide. There is an open source C driver provided by Bosch, but unfortunately
|
|
||||||
// it needs some small modifications to work with other chips (most importantly,
|
|
||||||
// the "config file").
|
|
||||||
// The InfiniTime and Wasp-OS drivers for this accelerometer have also been used
|
|
||||||
// to figure out some driver details (especially step counting).
|
|
||||||
package bma42x
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Driver for BMA421 and BMA425:
|
|
||||||
// BMA421: https://files.pine64.org/doc/datasheet/pinetime/BST-BMA421-FL000.pdf
|
|
||||||
// BMA425: https://datasheet.lcsc.com/lcsc/1912111437_Bosch-Sensortec-BMA425_C437656.pdf
|
|
||||||
|
|
||||||
// This is the BMA421 firmware from the Wasp-OS project.
|
|
||||||
// It is identical to the so-called BMA423 firmware in InfiniTime, which I
|
|
||||||
// suspect to be actually a BMA421 firmware. I don't know where this firmware
|
|
||||||
// comes from or what the licensing status is.
|
|
||||||
// It has the FEATURES_IN command prepended, so that it can be written directly
|
|
||||||
// using I2C.Tx.
|
|
||||||
// Source: https://github.com/wasp-os/bma42x-upy/blob/master/BMA42X-Sensor-API/bma421.h
|
|
||||||
//
|
|
||||||
//go:embed bma421-config-waspos.bin
|
|
||||||
var bma421Firmware string
|
|
||||||
|
|
||||||
// Same as the BMA421 firmware, but for the BMA425.
|
|
||||||
// Source: https://github.com/wasp-os/bma42x-upy/blob/master/BMA42X-Sensor-API/bma425.h
|
|
||||||
//
|
|
||||||
//go:embed bma425-config-waspos.bin
|
|
||||||
var bma425Firmware string
|
|
||||||
|
|
||||||
var (
|
|
||||||
errUnknownDevice = errors.New("bma42x: unknown device")
|
|
||||||
errUnsupportedDevice = errors.New("bma42x: device not part of config")
|
|
||||||
errConfigMismatch = errors.New("bma42x: config mismatch")
|
|
||||||
errTimeout = errors.New("bma42x: timeout")
|
|
||||||
errInitFailed = errors.New("bma42x: failed to initialize")
|
|
||||||
)
|
|
||||||
|
|
||||||
const Address = 0x18 // BMA421/BMA425 address
|
|
||||||
|
|
||||||
type DeviceType uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
DeviceBMA421 DeviceType = 1 << iota
|
|
||||||
DeviceBMA425
|
|
||||||
|
|
||||||
AnyDevice = DeviceBMA421 | DeviceBMA425
|
|
||||||
noDevice DeviceType = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// Features to enable while configuring the accelerometer.
|
|
||||||
type Features uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
FeatureStepCounting = 1 << iota
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
// Which devices to support (OR the device types together as needed).
|
|
||||||
Device DeviceType
|
|
||||||
|
|
||||||
// Which features to enable. With Features == 0, only the accelerometer will
|
|
||||||
// be enabled.
|
|
||||||
Features Features
|
|
||||||
}
|
|
||||||
|
|
||||||
type Device struct {
|
|
||||||
bus drivers.I2C
|
|
||||||
address uint8
|
|
||||||
accelData [6]byte
|
|
||||||
combinedTempSteps [5]uint8 // [0:3] steps, [4] temperature
|
|
||||||
dataBuf [2]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewI2C(i2c drivers.I2C, address uint8) *Device {
|
|
||||||
return &Device{
|
|
||||||
bus: i2c,
|
|
||||||
address: address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) Connected() bool {
|
|
||||||
val, err := d.read1(_CHIP_ID)
|
|
||||||
return err == nil && identifyChip(val) != noDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) Configure(config Config) error {
|
|
||||||
if config.Device == 0 {
|
|
||||||
config.Device = AnyDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check chip ID, to check the connection and to determine which BMA42x
|
|
||||||
// device we're dealing with.
|
|
||||||
chipID, err := d.read1(_CHIP_ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine which firmware (config file?) we'll be using.
|
|
||||||
// There is an extra check for the device before using the given firmware.
|
|
||||||
// This check will typically be optimized away if the given device is not
|
|
||||||
// configured, so that the firmware (which is 6kB in size!) won't be linked
|
|
||||||
// into the binary.
|
|
||||||
var firmware string
|
|
||||||
switch identifyChip(chipID) {
|
|
||||||
case DeviceBMA421:
|
|
||||||
if config.Device&DeviceBMA421 == 0 {
|
|
||||||
return errUnsupportedDevice
|
|
||||||
}
|
|
||||||
firmware = bma421Firmware
|
|
||||||
case DeviceBMA425:
|
|
||||||
if config.Device&DeviceBMA425 == 0 {
|
|
||||||
return errUnsupportedDevice
|
|
||||||
}
|
|
||||||
firmware = bma425Firmware
|
|
||||||
default:
|
|
||||||
return errUnknownDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the chip, to be able to initialize it properly.
|
|
||||||
// The datasheet says a delay is needed after a SoftReset, but it doesn't
|
|
||||||
// say how long this delay should be. The bma423 driver however uses a 200ms
|
|
||||||
// delay, so that's what we'll be using.
|
|
||||||
err = d.write1(_CMD, cmdSoftReset)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
|
|
||||||
// Disable power saving.
|
|
||||||
err = d.write1(_PWR_CONF, 0x00)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
time.Sleep(450 * time.Microsecond)
|
|
||||||
|
|
||||||
// Start initialization (because the datasheet says so).
|
|
||||||
err = d.write1(_INIT_CTRL, 0x00)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write "config file" (actually a firmware, I think) to the chip.
|
|
||||||
// To do this, unsafely cast the string to a byte slice to avoid putting it
|
|
||||||
// in RAM. This is safe in this case because Tx won't write to the 'w'
|
|
||||||
// slice.
|
|
||||||
err = d.bus.Tx(uint16(d.address), unsafeStringToSlice(firmware), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the config data back.
|
|
||||||
// We don't do that, as it slows down configuration and it probably isn't
|
|
||||||
// _really_ necessary with a reasonably stable I2C bus.
|
|
||||||
if false {
|
|
||||||
data := make([]byte, len(firmware)-1)
|
|
||||||
err = d.readn(_FEATURES_IN, data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for i, c := range data {
|
|
||||||
if firmware[i+1] != c {
|
|
||||||
return errConfigMismatch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable sensors.
|
|
||||||
err = d.write1(_INIT_CTRL, 0x01)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the device is initialized.
|
|
||||||
start := time.Now()
|
|
||||||
status := uint8(0) // busy
|
|
||||||
for status == 0 {
|
|
||||||
status, err = d.read1(_INTERNAL_STATUS)
|
|
||||||
if err != nil {
|
|
||||||
return err // I2C bus error.
|
|
||||||
}
|
|
||||||
if status > 1 {
|
|
||||||
// Expected either 0 ("not_init") or 1 ("init_ok").
|
|
||||||
return errInitFailed
|
|
||||||
}
|
|
||||||
if time.Since(start) >= 150*time.Millisecond {
|
|
||||||
// The datasheet says initialization should not take longer than
|
|
||||||
return errTimeout
|
|
||||||
}
|
|
||||||
// Don't bother the chip all the time while it's initializing.
|
|
||||||
time.Sleep(50 * time.Microsecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Features&FeatureStepCounting != 0 {
|
|
||||||
// Enable step counter.
|
|
||||||
// TODO: support step counter parameters.
|
|
||||||
var buf [71]byte
|
|
||||||
buf[0] = _FEATURES_IN // prefix buf with the command
|
|
||||||
data := buf[1:]
|
|
||||||
err = d.readn(_FEATURES_IN, data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data[0x3A+1] |= 0x10 // enable step counting by setting a magical bit
|
|
||||||
err = d.bus.Tx(uint16(d.address), buf[:], nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the accelerometer.
|
|
||||||
err = d.write1(_PWR_CTRL, 0x04)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure accelerometer for low power usage:
|
|
||||||
// acc_perf_mode=0 (power saving enabled)
|
|
||||||
// acc_bwp=osr4_avg1 (no averaging)
|
|
||||||
// acc_odr=50Hz (50Hz sampling interval, enough for the step counter)
|
|
||||||
const accelConf = 0x00<<7 | 0x00<<4 | 0x07<<0
|
|
||||||
err = d.write1(_ACC_CONF, accelConf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce current consumption.
|
|
||||||
// With power saving enabled (and the above ACC_CONF) the chip consumes only
|
|
||||||
// 14µA.
|
|
||||||
err = d.write1(_PWR_CONF, 0x03)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) Update(which drivers.Measurement) error {
|
|
||||||
// TODO: combine temperature and step counter into a single read.
|
|
||||||
if which&drivers.Temperature != 0 {
|
|
||||||
val, err := d.read1(_TEMPERATURE)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.combinedTempSteps[4] = val
|
|
||||||
}
|
|
||||||
if which&drivers.Acceleration != 0 {
|
|
||||||
// The acceleration data is stored in DATA8 through DATA13 as 3 12-bit
|
|
||||||
// values.
|
|
||||||
err := d.readn(_DATA_8, d.accelData[:]) // ACC_X(LSB)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = d.readn(_STEP_COUNTER_0, d.combinedTempSteps[:4])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature returns the last read temperature in celsius milli degrees (1°C
|
|
||||||
// is 1000).
|
|
||||||
func (d *Device) Temperature() int32 {
|
|
||||||
// The temperature value is a two's complement number (meaning: signed) in
|
|
||||||
// units of 1 kelvin, with 0 being 23°C.
|
|
||||||
return (int32(int8(d.combinedTempSteps[4])) + 23) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// Acceleration returns the last read acceleration in µg (micro-gravity).
|
|
||||||
// When one of the axes is pointing straight to Earth and the sensor is not
|
|
||||||
// moving the returned value will be around 1000000 or -1000000.
|
|
||||||
func (d *Device) Acceleration() (x, y, z int32) {
|
|
||||||
// Combine raw data from d.accelData (stored as 12-bit signed values) into a
|
|
||||||
// number (0..4095):
|
|
||||||
x = int32(d.accelData[0])>>4 | int32(d.accelData[1])<<4
|
|
||||||
y = int32(d.accelData[2])>>4 | int32(d.accelData[3])<<4
|
|
||||||
z = int32(d.accelData[4])>>4 | int32(d.accelData[5])<<4
|
|
||||||
// Sign extend this number to -2048..2047:
|
|
||||||
x = (x << 20) >> 20
|
|
||||||
y = (y << 20) >> 20
|
|
||||||
z = (z << 20) >> 20
|
|
||||||
// Scale from -512..511 to -1000_000..998_046.
|
|
||||||
// Or, at the maximum range (4g), from -2048..2047 to -2000_000..3998_046.
|
|
||||||
// The formula derived as follows (where 512 is the expected value at 1g):
|
|
||||||
// x = x * 1000_000 / 512
|
|
||||||
// x = x * (1000_000/64) / (512/64)
|
|
||||||
// x = x * 15625 / 8
|
|
||||||
x = x * 15625 / 8
|
|
||||||
y = y * 15625 / 8
|
|
||||||
z = z * 15625 / 8
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps returns the number of steps counted since the BMA42x sensor was
|
|
||||||
// initialized.
|
|
||||||
func (d *Device) Steps() (steps uint32) {
|
|
||||||
steps |= uint32(d.combinedTempSteps[0]) << 0
|
|
||||||
steps |= uint32(d.combinedTempSteps[1]) << 8
|
|
||||||
steps |= uint32(d.combinedTempSteps[2]) << 16
|
|
||||||
steps |= uint32(d.combinedTempSteps[3]) << 24
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) read1(register uint8) (uint8, error) {
|
|
||||||
d.dataBuf[0] = register
|
|
||||||
err := d.bus.Tx(uint16(d.address), d.dataBuf[:1], d.dataBuf[1:2])
|
|
||||||
return d.dataBuf[1], err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) readn(register uint8, data []byte) error {
|
|
||||||
d.dataBuf[0] = register
|
|
||||||
return d.bus.Tx(uint16(d.address), d.dataBuf[:1], data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) write1(register uint8, data uint8) error {
|
|
||||||
d.dataBuf[0] = register
|
|
||||||
d.dataBuf[1] = data
|
|
||||||
return d.bus.Tx(uint16(d.address), d.dataBuf[:2], nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsafeStringToSlice(s string) []byte {
|
|
||||||
// TODO: use unsafe.Slice(unsafe.StringData(...)) once we require Go 1.20.
|
|
||||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
|
||||||
return unsafe.Slice((*byte)(unsafe.Pointer(sh.Data)), len(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func identifyChip(chipID uint8) DeviceType {
|
|
||||||
switch chipID {
|
|
||||||
case 0x11:
|
|
||||||
return DeviceBMA421
|
|
||||||
case 0x13:
|
|
||||||
return DeviceBMA425
|
|
||||||
default:
|
|
||||||
return noDevice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package bma42x
|
|
||||||
|
|
||||||
const (
|
|
||||||
// I2C registers
|
|
||||||
_CHIP_ID = 0x00
|
|
||||||
_ERR_REG = 0x02
|
|
||||||
_STATUS = 0x03
|
|
||||||
_DATA_0 = 0x0A
|
|
||||||
_DATA_1 = 0x0B
|
|
||||||
_DATA_2 = 0x0C
|
|
||||||
_DATA_3 = 0x0D
|
|
||||||
_DATA_4 = 0x0E
|
|
||||||
_DATA_5 = 0x0F
|
|
||||||
_DATA_6 = 0x10
|
|
||||||
_DATA_7 = 0x11
|
|
||||||
_DATA_8 = 0x12
|
|
||||||
_DATA_9 = 0x13
|
|
||||||
_DATA_10 = 0x14
|
|
||||||
_DATA_11 = 0x15
|
|
||||||
_DATA_12 = 0x16
|
|
||||||
_DATA_13 = 0x17
|
|
||||||
_SENSORTIME_0 = 0x18
|
|
||||||
_SENSORTIME_1 = 0x19
|
|
||||||
_SENSORTIME_2 = 0x1A
|
|
||||||
_EVENT = 0x1B
|
|
||||||
_INT_STATUS_0 = 0x1C
|
|
||||||
_INT_STATUS_1 = 0x1D
|
|
||||||
_STEP_COUNTER_0 = 0x1E
|
|
||||||
_STEP_COUNTER_1 = 0x1F
|
|
||||||
_STEP_COUNTER_2 = 0x20
|
|
||||||
_STEP_COUNTER_3 = 0x21
|
|
||||||
_TEMPERATURE = 0x22
|
|
||||||
_FIFO_LENGTH_0 = 0x24
|
|
||||||
_FIFO_LENGTH_1 = 0x25
|
|
||||||
_FIFO_DATA = 0x26
|
|
||||||
_ACTIVITY_TYPE = 0x27
|
|
||||||
_INTERNAL_STATUS = 0x2A
|
|
||||||
_ACC_CONF = 0x40
|
|
||||||
_ACC_RANGE = 0x41
|
|
||||||
_AUX_CONF = 0x44
|
|
||||||
_FIFO_DOWNS = 0x45
|
|
||||||
_FIFO_WTM_0 = 0x46
|
|
||||||
_FIFO_WTM_1 = 0x47
|
|
||||||
_FIFO_CONFIG_0 = 0x48
|
|
||||||
_FIFO_CONFIG_1 = 0x49
|
|
||||||
_AUX_DEV_ID = 0x4B
|
|
||||||
_AUX_IF_CONF = 0x4C
|
|
||||||
_AUX_RD_ADDR = 0x4D
|
|
||||||
_AUX_WR_ADDR = 0x4E
|
|
||||||
_AUX_WR_DATA = 0x4F
|
|
||||||
_INT1_IO_CTRL = 0x53
|
|
||||||
_INT2_IO_CTRL = 0x54
|
|
||||||
_INT_LATCH = 0x55
|
|
||||||
_INT1_MAP = 0x56
|
|
||||||
_INT2_MAP = 0x57
|
|
||||||
_INT_MAP_DATA = 0x58
|
|
||||||
_INIT_CTRL = 0x59
|
|
||||||
_FEATURES_IN = 0x5E
|
|
||||||
_INTERNAL_ERROR = 0x5F
|
|
||||||
_NVM_CONF = 0x6A
|
|
||||||
_IF_CONF = 0x6B
|
|
||||||
_ACC_SELF_TEST = 0x6D
|
|
||||||
_NV_CONF = 0x70
|
|
||||||
_OFFSET_0 = 0x71
|
|
||||||
_OFFSET_1 = 0x72
|
|
||||||
_OFFSET_2 = 0x73
|
|
||||||
_PWR_CONF = 0x7C
|
|
||||||
_PWR_CTRL = 0x7D
|
|
||||||
_CMD = 0x7E
|
|
||||||
|
|
||||||
// Commands send to regCommand.
|
|
||||||
cmdSoftReset = 0xB6
|
|
||||||
)
|
|
||||||
+13
-124
@@ -3,14 +3,13 @@
|
|||||||
//
|
//
|
||||||
// Datasheet:
|
// Datasheet:
|
||||||
// https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
|
// https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
|
||||||
|
//
|
||||||
package bme280
|
package bme280
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// calibrationCoefficients reads at startup and stores the calibration coefficients
|
// calibrationCoefficients reads at startup and stores the calibration coefficients
|
||||||
@@ -35,27 +34,11 @@ type calibrationCoefficients struct {
|
|||||||
h6 int8
|
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.
|
// Device wraps an I2C connection to a BME280 device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.I2C
|
bus drivers.I2C
|
||||||
Address uint16
|
Address uint16
|
||||||
calibrationCoefficients calibrationCoefficients
|
calibrationCoefficients calibrationCoefficients
|
||||||
Config Config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new BME280 connection. The I2C bus must already be
|
// New creates a new BME280 connection. The I2C bus must already be
|
||||||
@@ -69,49 +52,24 @@ func New(bus drivers.I2C) Device {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureWithSettings sets up the device for communication and
|
// Configure sets up the device for communication and
|
||||||
// read the calibration coefficients.
|
// read the calibration coefficientes.
|
||||||
//
|
|
||||||
// The default configuration is the Indoor Navigation settings
|
|
||||||
// from the BME280 datasheet.
|
|
||||||
func (d *Device) Configure() {
|
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
|
var data [24]byte
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION, data[:])
|
err := d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION, data[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var h1 [1]byte
|
var h1 [1]byte
|
||||||
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION_H1, h1[:])
|
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H1, h1[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var h2lsb [7]byte
|
var h2lsb [7]byte
|
||||||
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
|
err = d.bus.ReadRegister(uint8(d.Address), REG_CALIBRATION_H2LSB, h2lsb[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,45 +94,23 @@ func (d *Device) ConfigureWithSettings(config Config) {
|
|||||||
d.calibrationCoefficients.h4 = 0 + (int16(h2lsb[3]) << 4) | (int16(h2lsb[4] & 0x0F))
|
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.calibrationCoefficients.h5 = 0 + (int16(h2lsb[5]) << 4) | (int16(h2lsb[4]) >> 4)
|
||||||
|
|
||||||
d.Reset()
|
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})
|
||||||
|
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_CONFIG, []byte{byte(d.Config.Period<<5) | byte(d.Config.IIR<<2)})
|
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), CTRL_HUMIDITY_ADDR, []byte{byte(d.Config.Humidity)})
|
|
||||||
|
|
||||||
// Normal mode, start measuring now
|
|
||||||
if d.Config.Mode == ModeNormal {
|
|
||||||
legacy.WriteRegister(d.bus, 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.
|
// Connected returns whether a BME280 has been found.
|
||||||
// It does a "who am I" request and checks the response.
|
// It does a "who am I" request and checks the response.
|
||||||
func (d *Device) Connected() bool {
|
func (d *Device) Connected() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
|
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
|
||||||
return data[0] == CHIP_ID
|
return data[0] == CHIP_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the device
|
// Reset the device
|
||||||
func (d *Device) Reset() {
|
func (d *Device) Reset() {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), CMD_RESET, []byte{0xB6})
|
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
|
|
||||||
|
|
||||||
legacy.WriteRegister(d.bus, 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)
|
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
||||||
@@ -213,8 +149,7 @@ func (d *Device) ReadHumidity() (int32, error) {
|
|||||||
// ReadAltitude returns the current altitude in meters based on the
|
// ReadAltitude returns the current altitude in meters based on the
|
||||||
// current barometric pressure and estimated pressure at sea level.
|
// current barometric pressure and estimated pressure at sea level.
|
||||||
// Calculation is based on code from Adafruit BME280 library
|
// Calculation is based on code from Adafruit BME280 library
|
||||||
//
|
// https://github.com/adafruit/Adafruit_BME280_Library
|
||||||
// https://github.com/adafruit/Adafruit_BME280_Library
|
|
||||||
func (d *Device) ReadAltitude() (alt int32, err error) {
|
func (d *Device) ReadAltitude() (alt int32, err error) {
|
||||||
mPa, _ := d.ReadPressure()
|
mPa, _ := d.ReadPressure()
|
||||||
atmP := float32(mPa) / 100000
|
atmP := float32(mPa) / 100000
|
||||||
@@ -251,17 +186,7 @@ func readIntLE(msb byte, lsb byte) int16 {
|
|||||||
// readData does a burst read from 0xF7 to 0xF0 according to the datasheet
|
// 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
|
// 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) {
|
func (d *Device) readData() (data [8]byte, err error) {
|
||||||
if d.Config.Mode == ModeForced {
|
err = d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE, data[:])
|
||||||
// Write the CTRL_MEAS register to trigger a measurement
|
|
||||||
legacy.WriteRegister(d.bus, 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 = legacy.ReadRegister(d.bus, uint8(d.Address), REG_PRESSURE, data[:])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err)
|
println(err)
|
||||||
return
|
return
|
||||||
@@ -331,39 +256,3 @@ func (d *Device) calculateHumidity(data [8]byte, tFine int32) int32 {
|
|||||||
return int32(100 * h)
|
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,50 +20,6 @@ const (
|
|||||||
CHIP_ID = 0x60
|
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 (
|
const (
|
||||||
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
||||||
)
|
)
|
||||||
|
|||||||
+7
-23
@@ -3,14 +3,13 @@
|
|||||||
//
|
//
|
||||||
// Datasheet:
|
// Datasheet:
|
||||||
// https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
// https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
|
||||||
|
//
|
||||||
package bmp180 // import "tinygo.org/x/drivers/bmp180"
|
package bmp180 // import "tinygo.org/x/drivers/bmp180"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OversamplingMode is the oversampling ratio of the pressure measurement.
|
// OversamplingMode is the oversampling ratio of the pressure measurement.
|
||||||
@@ -56,7 +55,7 @@ func New(bus drivers.I2C) Device {
|
|||||||
// It does a "who am I" request and checks the response.
|
// It does a "who am I" request and checks the response.
|
||||||
func (d *Device) Connected() bool {
|
func (d *Device) Connected() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
|
d.bus.ReadRegister(uint8(d.Address), WHO_AM_I, data)
|
||||||
return data[0] == CHIP_ID
|
return data[0] == CHIP_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ func (d *Device) Connected() bool {
|
|||||||
// read the calibration coefficients.
|
// read the calibration coefficients.
|
||||||
func (d *Device) Configure() {
|
func (d *Device) Configure() {
|
||||||
data := make([]byte, 22)
|
data := make([]byte, 22)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), AC1_MSB, data)
|
err := d.bus.ReadRegister(uint8(d.Address), AC1_MSB, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -125,27 +124,12 @@ func (d *Device) ReadPressure() (pressure int32, err error) {
|
|||||||
return 1000 * (p + ((x1 + x2 + 3791) >> 4)), nil
|
return 1000 * (p + ((x1 + x2 + 3791) >> 4)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAltitude returns the current altitude in meters based on the
|
|
||||||
// current barometric pressure and estimated pressure at sea level.
|
|
||||||
// Calculation is based on code from Adafruit BME280 library
|
|
||||||
//
|
|
||||||
// https://github.com/adafruit/Adafruit_BME280_Library
|
|
||||||
func (d *Device) ReadAltitude() (int32, error) {
|
|
||||||
mPa, err := d.ReadPressure()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
atmP := float32(mPa) / 100000
|
|
||||||
|
|
||||||
return int32(44330.0 * (1.0 - math.Pow(float64(atmP/SEALEVEL_PRESSURE), 0.1903))), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// rawTemp returns the sensor's raw values of the temperature
|
// rawTemp returns the sensor's raw values of the temperature
|
||||||
func (d *Device) rawTemp() (int32, error) {
|
func (d *Device) rawTemp() (int32, error) {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_TEMP})
|
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_TEMP})
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
data := make([]byte, 2)
|
data := make([]byte, 2)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_TEMP_MSB, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP_MSB, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -161,10 +145,10 @@ func (d *Device) calculateB5(rawTemp int32) int32 {
|
|||||||
|
|
||||||
// rawPressure returns the sensor's raw values of the pressure
|
// rawPressure returns the sensor's raw values of the pressure
|
||||||
func (d *Device) rawPressure(mode OversamplingMode) (int32, error) {
|
func (d *Device) rawPressure(mode OversamplingMode) (int32, error) {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)})
|
d.bus.WriteRegister(uint8(d.Address), REG_CTRL, []byte{CMD_PRESSURE + byte(mode<<6)})
|
||||||
time.Sleep(pauseForReading(mode))
|
time.Sleep(pauseForReading(mode))
|
||||||
data := make([]byte, 3)
|
data := make([]byte, 3)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_PRESSURE_MSB, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_PRESSURE_MSB, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,3 @@ const (
|
|||||||
// ULTRAHIGHRESOLUTION is the highest oversampling mode of the pressure measurement.
|
// ULTRAHIGHRESOLUTION is the highest oversampling mode of the pressure measurement.
|
||||||
ULTRAHIGHRESOLUTION
|
ULTRAHIGHRESOLUTION
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
SEALEVEL_PRESSURE float32 = 1013.25 // in hPa
|
|
||||||
)
|
|
||||||
|
|||||||
+8
-9
@@ -4,7 +4,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OversamplingMode is the oversampling ratio of the temperature or pressure measurement.
|
// OversamplingMode is the oversampling ratio of the temperature or pressure measurement.
|
||||||
@@ -65,14 +64,14 @@ func New(bus drivers.I2C) Device {
|
|||||||
// It does a "who am I" request and checks the response.
|
// It does a "who am I" request and checks the response.
|
||||||
func (d *Device) Connected() bool {
|
func (d *Device) Connected() bool {
|
||||||
data := make([]byte, 1)
|
data := make([]byte, 1)
|
||||||
legacy.ReadRegister(d.bus, uint8(d.Address), REG_ID, data)
|
d.bus.ReadRegister(uint8(d.Address), REG_ID, data)
|
||||||
return data[0] == CHIP_ID
|
return data[0] == CHIP_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset preforms complete power-on-reset procedure.
|
// Reset preforms complete power-on-reset procedure.
|
||||||
// It is required to call Configure afterwards.
|
// It is required to call Configure afterwards.
|
||||||
func (d *Device) Reset() {
|
func (d *Device) Reset() {
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_RESET, []byte{CMD_RESET})
|
d.bus.WriteRegister(uint8(d.Address), REG_RESET, []byte{CMD_RESET})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure sets up the device for communication and
|
// Configure sets up the device for communication and
|
||||||
@@ -86,15 +85,15 @@ func (d *Device) Configure(standby Standby, filter Filter, temp Oversampling, pr
|
|||||||
|
|
||||||
// Write the configuration (standby, filter, spi 3 wire)
|
// Write the configuration (standby, filter, spi 3 wire)
|
||||||
config := uint(d.Standby<<5) | uint(d.Filter<<2) | 0x00
|
config := uint(d.Standby<<5) | uint(d.Filter<<2) | 0x00
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONFIG, []byte{byte(config)})
|
d.bus.WriteRegister(uint8(d.Address), REG_CONFIG, []byte{byte(config)})
|
||||||
|
|
||||||
// Write the control (temperature oversampling, pressure oversampling,
|
// Write the control (temperature oversampling, pressure oversampling,
|
||||||
config = uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(d.Mode)
|
config = uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(d.Mode)
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
||||||
|
|
||||||
// Read Calibration data
|
// Read Calibration data
|
||||||
data := make([]byte, 24)
|
data := make([]byte, 24)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CALI, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_CALI, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -208,18 +207,18 @@ func (d *Device) readData(register int, n int) ([]byte, error) {
|
|||||||
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
|
// After the measurement in FORCED mode, the sensor will return to SLEEP mode
|
||||||
if d.Mode != MODE_NORMAL {
|
if d.Mode != MODE_NORMAL {
|
||||||
config := uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(MODE_FORCED)
|
config := uint(d.Temperature<<5) | uint(d.Pressure<<2) | uint(MODE_FORCED)
|
||||||
legacy.WriteRegister(d.bus, uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
d.bus.WriteRegister(uint8(d.Address), REG_CTRL_MEAS, []byte{byte(config)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check STATUS register, wait if data is not available yet
|
// Check STATUS register, wait if data is not available yet
|
||||||
status := make([]byte, 1)
|
status := make([]byte, 1)
|
||||||
for legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; legacy.ReadRegister(d.bus, uint8(d.Address), uint8(REG_STATUS), status[0:]) {
|
for d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]); status[0] != 4 && status[0] != 0; d.bus.ReadRegister(uint8(d.Address), uint8(REG_STATUS), status[0:]) {
|
||||||
time.Sleep(time.Millisecond)
|
time.Sleep(time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the requested register
|
// Read the requested register
|
||||||
data := make([]byte, n)
|
data := make([]byte, n)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), uint8(register), data[:])
|
err := d.bus.ReadRegister(uint8(d.Address), uint8(register), data[:])
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -241,10 +240,10 @@ func (d *Device) configurationError() bool {
|
|||||||
|
|
||||||
func (d *Device) readRegister(register byte, len int) (data []byte, err error) {
|
func (d *Device) readRegister(register byte, len int) (data []byte, err error) {
|
||||||
data = make([]byte, len)
|
data = make([]byte, len)
|
||||||
err = legacy.ReadRegister(d.bus, d.Address, register, data)
|
err = d.bus.ReadRegister(d.Address, register, data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) writeRegister(register byte, data byte) error {
|
func (d *Device) writeRegister(register byte, data byte) error {
|
||||||
return legacy.WriteRegister(d.bus, d.Address, register, []byte{data})
|
return d.bus.WriteRegister(d.Address, register, []byte{data})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -1,4 +1,5 @@
|
|||||||
// Package buzzer provides a very simplistic driver for a connected buzzer or low-fidelity speaker.
|
// Package buzzer provides a very simplistic driver for a connected buzzer or low-fidelity speaker.
|
||||||
|
//
|
||||||
package buzzer // import "tinygo.org/x/drivers/buzzer"
|
package buzzer // import "tinygo.org/x/drivers/buzzer"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -54,12 +55,6 @@ func (l *Device) Tone(hz, duration float64) (err error) {
|
|||||||
|
|
||||||
tempo := ((60 / l.BPM) * (duration * 1000))
|
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 {
|
for i := 0.0; i < tempo*1000; i += tone * 2.0 {
|
||||||
if err = l.On(); err != nil {
|
if err = l.On(); err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
package buzzer
|
package buzzer
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Whole = 4.0
|
Whole = 4
|
||||||
Half = 2.0
|
Half = 2
|
||||||
Quarter = 1.0
|
Quarter = 1
|
||||||
Eighth = 0.500
|
Eighth = 0.500
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// Loop the given times, where one loop takes four CPU cycles.
|
|
||||||
bool tinygo_drivers_sleep(uint32_t cycles) {
|
|
||||||
// In this function, a [n] comment indicates the number of cycles an
|
|
||||||
// instruction or a set of instructions take. This is typically 1 for most
|
|
||||||
// arithmetic instructions, and a bit more for branches.
|
|
||||||
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
|
|
||||||
// Inline assembly for Cortex-M0/M0+/M3/M4/M7.
|
|
||||||
// The Cortex-M0 (but not M0+) takes one more cycle, so is off by 12.5%.
|
|
||||||
// Others should be basically cycle-accurate (with a slight overhead to
|
|
||||||
// calculate the number of cycles). Unfortunately, there doesn't appear to
|
|
||||||
// be a preprocessor macro to detect the Cortex-M0 specifically (although we
|
|
||||||
// could rely on macros like NRF51).
|
|
||||||
|
|
||||||
// Each loop takes 8 cycles (5 nops, 1 sub, and 2 for the branch).
|
|
||||||
uint32_t loops = (cycles + 7) / 8;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1:\n\t"
|
|
||||||
"nop\n\t" // [5] nops
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"subs %[loops], #1\n\t" // [1]
|
|
||||||
"bne 1b" // [1-4], at least 2 cycles if taken
|
|
||||||
: [loops]"+r"(loops)
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
#elif __XTENSA__
|
|
||||||
// Inline assembly for Xtensa.
|
|
||||||
// I don't know exactly how many cycles a branch takes, so I've taken a
|
|
||||||
// conservative guess and assume it takes only one cycle. In practice, it's
|
|
||||||
// probably more than that.
|
|
||||||
uint32_t loops = (cycles + 7) / 8;
|
|
||||||
__asm__ __volatile__(
|
|
||||||
"1:\n\t"
|
|
||||||
"nop\n\t" // [6] nops
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"nop\n\t"
|
|
||||||
"addi %[loops], %[loops], -1\n\t" // [1]
|
|
||||||
"bnez %[loops], 1b" // [1?]
|
|
||||||
: [loops]"+r"(loops)
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
// Unknown architecture, so fall back to time.Sleep.
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package delay
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
bool tinygo_drivers_sleep(uint32_t ticks);
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
// Sleep for a very precise short duration by busy-waiting for the given time.
|
|
||||||
// This is not an efficient way to sleep: it will needlessly burn cycles while
|
|
||||||
// sleeping. But it is useful for sleeping for a very short duration, for
|
|
||||||
// example for bit-banged protocols.
|
|
||||||
//
|
|
||||||
// Longer durations (longer than a few milliseconds) will be handled by calling
|
|
||||||
// time.Sleep instead.
|
|
||||||
//
|
|
||||||
// This function should be called with a constant duration value, in which case
|
|
||||||
// the call will typically be fully inlined and only take up around nine
|
|
||||||
// instructions for the entire loop.
|
|
||||||
//
|
|
||||||
//go:inline
|
|
||||||
func Sleep(duration time.Duration) {
|
|
||||||
if time.Duration(uint32(duration)&0xff_ffff) != duration {
|
|
||||||
// This is a long duration (more than 16ms) which shouldn't be done by
|
|
||||||
// busy-waiting.
|
|
||||||
time.Sleep(duration)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the number of cycles we should sleep:
|
|
||||||
// cycles = duration * freq / 1e9
|
|
||||||
// Avoiding a 64-bit division:
|
|
||||||
// cycles = duration * (freq/1000_000) / 1000
|
|
||||||
//
|
|
||||||
// This assumes:
|
|
||||||
// * The CPU frequency is a constant and can trivially be
|
|
||||||
// const-propagated, therefore the divide by 1000_000 is done at compile
|
|
||||||
// time.
|
|
||||||
// * The CPU frequency is a multiple of 1000_000, which is true for most
|
|
||||||
// chips (examples: 16MHz, 48MHz, 120MHz, etc).
|
|
||||||
// * The division by 1000 can be done efficiently (Cortex-M3 and up), or
|
|
||||||
// can be fully const-propagated.
|
|
||||||
// * The CPU frequency is lower than 256MHz. If it is higher, long sleep
|
|
||||||
// times (1-16ms) may not work correctly.
|
|
||||||
cycles := uint32(duration) * (machine.CPUFrequency() / 1000_000) / 1000
|
|
||||||
slept := C.tinygo_drivers_sleep(cycles)
|
|
||||||
if !slept {
|
|
||||||
// Fallback for platforms without inline assembly support.
|
|
||||||
time.Sleep(duration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build tinygo
|
//go:build tinygo
|
||||||
|
// +build tinygo
|
||||||
|
|
||||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build mimxrt1062 || stm32f405 || atsamd51 || stm32f103xx || k210 || stm32f407
|
//go:build mimxrt1062 || stm32f405 || atsamd51 || stm32f103xx || k210 || stm32f407
|
||||||
|
// +build mimxrt1062 stm32f405 atsamd51 stm32f103xx k210 stm32f407
|
||||||
|
|
||||||
package dht // import "tinygo.org/x/drivers/dht"
|
package dht // import "tinygo.org/x/drivers/dht"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build !mimxrt1062 && !stm32f405 && !atsamd51 && !stm32f103xx && !k210 && !stm32f407
|
//go:build !mimxrt1062 && !stm32f405 && !atsamd51 && !stm32f103xx && !k210 && !stm32f407
|
||||||
|
// +build !mimxrt1062,!stm32f405,!atsamd51,!stm32f103xx,!k210,!stm32f407
|
||||||
|
|
||||||
package dht // import "tinygo.org/x/drivers/dht"
|
package dht // import "tinygo.org/x/drivers/dht"
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,5 @@
|
|||||||
//go:build tinygo
|
//go:build tinygo
|
||||||
|
// +build tinygo
|
||||||
|
|
||||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||||
//
|
//
|
||||||
@@ -10,7 +11,6 @@ package dht // import "tinygo.org/x/drivers/dht"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -160,8 +160,8 @@ func (t *device) read() error {
|
|||||||
// interrupts
|
// interrupts
|
||||||
func receiveSignals(pin machine.Pin, result []counter) {
|
func receiveSignals(pin machine.Pin, result []counter) {
|
||||||
i := uint8(0)
|
i := uint8(0)
|
||||||
mask := interrupt.Disable()
|
machine.UART1.Interrupt.Disable()
|
||||||
defer interrupt.Restore(mask)
|
defer machine.UART1.Interrupt.Enable()
|
||||||
for ; i < 40; i++ {
|
for ; i < 40; i++ {
|
||||||
result[i*2] = expectChange(pin, false)
|
result[i*2] = expectChange(pin, false)
|
||||||
result[i*2+1] = expectChange(pin, true)
|
result[i*2+1] = expectChange(pin, true)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build tinygo
|
//go:build tinygo
|
||||||
|
// +build tinygo
|
||||||
|
|
||||||
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build tinygo
|
//go:build tinygo
|
||||||
|
// +build tinygo
|
||||||
|
|
||||||
package dht // import "tinygo.org/x/drivers/dht"
|
package dht // import "tinygo.org/x/drivers/dht"
|
||||||
|
|
||||||
|
|||||||
@@ -12,19 +12,3 @@ type Displayer interface {
|
|||||||
// Display sends the buffer (if any) to the screen.
|
// Display sends the buffer (if any) to the screen.
|
||||||
Display() error
|
Display() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotation is how much a display has been rotated. Displays can be rotated, and
|
|
||||||
// sometimes also mirrored.
|
|
||||||
type Rotation uint8
|
|
||||||
|
|
||||||
// Clockwise rotation of the screen.
|
|
||||||
const (
|
|
||||||
Rotation0 = iota
|
|
||||||
Rotation90
|
|
||||||
Rotation180
|
|
||||||
Rotation270
|
|
||||||
Rotation0Mirror
|
|
||||||
Rotation90Mirror
|
|
||||||
Rotation180Mirror
|
|
||||||
Rotation270Mirror
|
|
||||||
)
|
|
||||||
|
|||||||
+8
-7
@@ -3,22 +3,22 @@
|
|||||||
//
|
//
|
||||||
// Here is an example in TinyGo that uses the BMP180 digital barometer:
|
// Here is an example in TinyGo that uses the BMP180 digital barometer:
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
// import (
|
// import (
|
||||||
// "time"
|
// "time"
|
||||||
// "machine"
|
// "machine"
|
||||||
//
|
//
|
||||||
// "tinygo.org/x/drivers/bmp180"
|
// "tinygo.org/x/drivers/bmp180"
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// func main() {
|
// func main() {
|
||||||
// machine.I2C0.Configure(machine.I2CConfig{})
|
// machine.I2C0.Configure(machine.I2CConfig{})
|
||||||
// sensor := bmp180.New(machine.I2C0)
|
// sensor := bmp180.New(machine.I2C0)
|
||||||
// sensor.Configure()
|
// sensor.Configure()
|
||||||
//
|
//
|
||||||
// connected := sensor.Connected()
|
// connected := sensor.Connected()
|
||||||
// if !connected {
|
// if !connected {
|
||||||
// println("BMP180 not detected")
|
// println("BMP180 not detected")
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
@@ -38,4 +38,5 @@
|
|||||||
// Each individual driver is contained within its own sub-package within this package and
|
// Each individual driver is contained within its own sub-package within this package and
|
||||||
// there are no interdependencies in order to minimize the final size of compiled code that
|
// there are no interdependencies in order to minimize the final size of compiled code that
|
||||||
// uses any of these drivers.
|
// uses any of these drivers.
|
||||||
|
//
|
||||||
package drivers // import "tinygo.org/x/drivers"
|
package drivers // import "tinygo.org/x/drivers"
|
||||||
|
|||||||
+5
-5
@@ -2,6 +2,7 @@
|
|||||||
//
|
//
|
||||||
// Datasheet:
|
// Datasheet:
|
||||||
// https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
|
// https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
|
||||||
|
//
|
||||||
package ds1307 // import "tinygo.org/x/drivers/ds1307"
|
package ds1307 // import "tinygo.org/x/drivers/ds1307"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,7 +10,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Device wraps an I2C connection to a DS1307 device.
|
// Device wraps an I2C connection to a DS1307 device.
|
||||||
@@ -45,7 +45,7 @@ func (d *Device) SetTime(t time.Time) error {
|
|||||||
// ReadTime returns the date and time
|
// ReadTime returns the date and time
|
||||||
func (d *Device) ReadTime() (time.Time, error) {
|
func (d *Device) ReadTime() (time.Time, error) {
|
||||||
data := make([]byte, 8)
|
data := make([]byte, 8)
|
||||||
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
|
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, err
|
return time.Time{}, err
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ func (d *Device) Read(data []uint8) (n int, err error) {
|
|||||||
if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
|
if int(d.AddressSRAM)+len(data)-1 > SRAMEndAddress {
|
||||||
return 0, errors.New("EOF")
|
return 0, errors.New("EOF")
|
||||||
}
|
}
|
||||||
err = legacy.ReadRegister(d.bus, d.Address, d.AddressSRAM, data)
|
err = d.bus.ReadRegister(d.Address, d.AddressSRAM, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ func (d *Device) SetOscillatorFrequency(sqw uint8) error {
|
|||||||
// IsOscillatorRunning returns if the oscillator is running
|
// IsOscillatorRunning returns if the oscillator is running
|
||||||
func (d *Device) IsOscillatorRunning() bool {
|
func (d *Device) IsOscillatorRunning() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
|
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ func (d *Device) IsOscillatorRunning() bool {
|
|||||||
// SetOscillatorRunning starts/stops internal oscillator by toggling halt bit
|
// SetOscillatorRunning starts/stops internal oscillator by toggling halt bit
|
||||||
func (d *Device) SetOscillatorRunning(running bool) error {
|
func (d *Device) SetOscillatorRunning(running bool) error {
|
||||||
data := make([]byte, 3)
|
data := make([]byte, 3)
|
||||||
err := legacy.ReadRegister(d.bus, d.Address, uint8(TimeDate), data)
|
err := d.bus.ReadRegister(d.Address, uint8(TimeDate), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
// Package ds18b20 provides a driver for the DS18B20 digital thermometer
|
|
||||||
//
|
|
||||||
// Datasheet:
|
|
||||||
// https://www.analog.com/media/en/technical-documentation/data-sheets/DS18B20.pdf
|
|
||||||
package ds18b20 // import "tinygo.org/x/drivers/ds18b20"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Device ROM commands
|
|
||||||
const (
|
|
||||||
CONVERT_TEMPERATURE uint8 = 0x44
|
|
||||||
READ_SCRATCHPAD uint8 = 0xBE
|
|
||||||
WRITE_SCRATCHPAD uint8 = 0x4E
|
|
||||||
)
|
|
||||||
|
|
||||||
type OneWireDevice interface {
|
|
||||||
Write(uint8)
|
|
||||||
Read() uint8
|
|
||||||
Select([]uint8) error
|
|
||||||
Сrc8([]uint8, int) uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// Device wraps a connection to an 1-Wire devices.
|
|
||||||
type Device struct {
|
|
||||||
owd OneWireDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errors list
|
|
||||||
var (
|
|
||||||
errReadTemperature = errors.New("Error: DS18B20. Read temperature error: CRC mismatch.")
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(owd OneWireDevice) Device {
|
|
||||||
return Device{
|
|
||||||
owd: owd,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure. Initializes the device, left for compatibility reasons.
|
|
||||||
func (d Device) Configure() {}
|
|
||||||
|
|
||||||
// ThermometerResolution sets thermometer resolution from 9 to 12 bits
|
|
||||||
func (d Device) ThermometerResolution(romid []uint8, resolution uint8) {
|
|
||||||
if 9 <= resolution && resolution <= 12 {
|
|
||||||
d.owd.Select(romid)
|
|
||||||
d.owd.Write(WRITE_SCRATCHPAD) // send three data bytes to scratchpad (TH, TL, and config)
|
|
||||||
d.owd.Write(0xFF) // to TH
|
|
||||||
d.owd.Write(0x00) // to TL
|
|
||||||
d.owd.Write(((resolution - 9) << 5) | 0x1F) // to resolution config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestTemperature sends request to device
|
|
||||||
func (d Device) RequestTemperature(romid []uint8) {
|
|
||||||
d.owd.Select(romid)
|
|
||||||
d.owd.Write(CONVERT_TEMPERATURE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadTemperatureRaw returns the raw temperature.
|
|
||||||
// ScratchPad memory map:
|
|
||||||
// byte 0: Temperature LSB
|
|
||||||
// byte 1: Temperature MSB
|
|
||||||
func (d Device) ReadTemperatureRaw(romid []uint8) ([]uint8, error) {
|
|
||||||
spb := make([]uint8, 9) // ScratchPad buffer
|
|
||||||
d.owd.Select(romid)
|
|
||||||
d.owd.Write(READ_SCRATCHPAD)
|
|
||||||
for i := 0; i < 9; i++ {
|
|
||||||
spb[i] = d.owd.Read()
|
|
||||||
}
|
|
||||||
if d.owd.Сrc8(spb, 8) != spb[8] {
|
|
||||||
return nil, errReadTemperature
|
|
||||||
}
|
|
||||||
return spb[:2:2], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
|
|
||||||
func (d Device) ReadTemperature(romid []uint8) (int32, error) {
|
|
||||||
raw, err := d.ReadTemperatureRaw(romid)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
t := int32(uint16(raw[0]) | uint16(raw[1])<<8)
|
|
||||||
if t&0x8000 == 0x8000 {
|
|
||||||
t -= 0x10000
|
|
||||||
}
|
|
||||||
return (t * 625 / 10), nil
|
|
||||||
}
|
|
||||||
+11
-46
@@ -8,7 +8,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/internal/legacy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mode uint8
|
type Mode uint8
|
||||||
@@ -38,7 +37,7 @@ func (d *Device) Configure() bool {
|
|||||||
// IsTimeValid return true/false is the time in the device is valid
|
// IsTimeValid return true/false is the time in the device is valid
|
||||||
func (d *Device) IsTimeValid() bool {
|
func (d *Device) IsTimeValid() bool {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -48,7 +47,7 @@ func (d *Device) IsTimeValid() bool {
|
|||||||
// IsRunning returns if the oscillator is running
|
// IsRunning returns if the oscillator is running
|
||||||
func (d *Device) IsRunning() bool {
|
func (d *Device) IsRunning() bool {
|
||||||
data := []uint8{0}
|
data := []uint8{0}
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,7 @@ func (d *Device) IsRunning() bool {
|
|||||||
// SetRunning starts the internal oscillator
|
// SetRunning starts the internal oscillator
|
||||||
func (d *Device) SetRunning(isRunning bool) error {
|
func (d *Device) SetRunning(isRunning bool) error {
|
||||||
data := []uint8{0}
|
data := []uint8{0}
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_CONTROL, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -67,32 +66,22 @@ func (d *Device) SetRunning(isRunning bool) error {
|
|||||||
} else {
|
} else {
|
||||||
data[0] |= 1 << EOSC
|
data[0] |= 1 << EOSC
|
||||||
}
|
}
|
||||||
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_CONTROL, data)
|
err = d.bus.WriteRegister(uint8(d.Address), REG_CONTROL, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTime sets the date and time in the DS3231. The DS3231 hardware supports
|
// SetTime sets the date and time in the DS3231
|
||||||
// only a 2-digit year field, so the current year will be stored as an offset
|
|
||||||
// from the year 2000, which supports the year 2000 until 2100.
|
|
||||||
//
|
|
||||||
// The DS3231 also supports a one-bit 'century' flag which is set by the chip
|
|
||||||
// when the year field rolls over from 99 to 00. The current code interprets
|
|
||||||
// this flag to be the year 2100, which appears to extend the range of years
|
|
||||||
// until the year 2200. However the DS3231 does not incorporate the 'century'
|
|
||||||
// flag in its leap year calculation, so it will incorrectly identify the year
|
|
||||||
// 2100 as a leap year, causing it to increment from 2100-02-28 to 2100-02-29
|
|
||||||
// instead of 2100-03-01.
|
|
||||||
func (d *Device) SetTime(dt time.Time) error {
|
func (d *Device) SetTime(dt time.Time) error {
|
||||||
data := []byte{0}
|
data := []byte{0}
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_STATUS, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_STATUS, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data[0] &^= 1 << OSF
|
data[0] &^= 1 << OSF
|
||||||
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_STATUS, data)
|
err = d.bus.WriteRegister(uint8(d.Address), REG_STATUS, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -103,10 +92,6 @@ func (d *Device) SetTime(dt time.Time) error {
|
|||||||
data[2] = uint8ToBCD(uint8(dt.Hour()))
|
data[2] = uint8ToBCD(uint8(dt.Hour()))
|
||||||
|
|
||||||
year := uint8(dt.Year() - 2000)
|
year := uint8(dt.Year() - 2000)
|
||||||
// This code interprets the centuryFlag to be the year 2100. Warning: The
|
|
||||||
// DS3231 does not incorporate the centuryFlag in its leap year calculation.
|
|
||||||
// It will increment from 2100-02-28 to 2100-02-29, which is incorrect because
|
|
||||||
// the year 2100 is not a leap year in the Gregorian calendar.
|
|
||||||
centuryFlag := uint8(0)
|
centuryFlag := uint8(0)
|
||||||
if year >= 100 {
|
if year >= 100 {
|
||||||
year -= 100
|
year -= 100
|
||||||
@@ -118,7 +103,7 @@ func (d *Device) SetTime(dt time.Time) error {
|
|||||||
data[5] = uint8ToBCD(uint8(dt.Month()) | centuryFlag)
|
data[5] = uint8ToBCD(uint8(dt.Month()) | centuryFlag)
|
||||||
data[6] = uint8ToBCD(year)
|
data[6] = uint8ToBCD(year)
|
||||||
|
|
||||||
err = legacy.WriteRegister(d.bus, uint8(d.Address), REG_TIMEDATE, data)
|
err = d.bus.WriteRegister(uint8(d.Address), REG_TIMEDATE, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -129,7 +114,7 @@ func (d *Device) SetTime(dt time.Time) error {
|
|||||||
// ReadTime returns the date and time
|
// ReadTime returns the date and time
|
||||||
func (d *Device) ReadTime() (dt time.Time, err error) {
|
func (d *Device) ReadTime() (dt time.Time, err error) {
|
||||||
data := make([]uint8, 7)
|
data := make([]uint8, 7)
|
||||||
err = legacy.ReadRegister(d.bus, uint8(d.Address), REG_TIMEDATE, data)
|
err = d.bus.ReadRegister(uint8(d.Address), REG_TIMEDATE, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -151,31 +136,11 @@ func (d *Device) ReadTime() (dt time.Time, err error) {
|
|||||||
// ReadTemperature returns the temperature in millicelsius (mC)
|
// ReadTemperature returns the temperature in millicelsius (mC)
|
||||||
func (d *Device) ReadTemperature() (int32, error) {
|
func (d *Device) ReadTemperature() (int32, error) {
|
||||||
data := make([]uint8, 2)
|
data := make([]uint8, 2)
|
||||||
err := legacy.ReadRegister(d.bus, uint8(d.Address), REG_TEMP, data)
|
err := d.bus.ReadRegister(uint8(d.Address), REG_TEMP, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return milliCelsius(data[0], data[1]), nil
|
return int32(data[0])*1000 + int32((data[1]>>6)*25)*10, nil
|
||||||
}
|
|
||||||
|
|
||||||
// milliCelsius converts the raw temperature bytes (msb and lsb) from the DS3231
|
|
||||||
// into a 32-bit signed integer in units of milli Celsius (1/1000 deg C).
|
|
||||||
//
|
|
||||||
// According to the DS3231 datasheet: "Temperature is represented as a 10-bit
|
|
||||||
// code with a resolution of 0.25 deg C and is accessible at location 11h and
|
|
||||||
// 12h. The temperature is encoded in two's complement format. The upper 8 bits,
|
|
||||||
// the integer portion, are at location 11h and the lower 2 bits, the fractional
|
|
||||||
// portion, are in the upper nibble at location 12h."
|
|
||||||
//
|
|
||||||
// In other words, the msb and lsb bytes should be treated as a signed 16-bit
|
|
||||||
// integer in units of (1/256 deg C). It is possible to convert this into a
|
|
||||||
// 16-bit signed integer in units of centi Celsius (1/100 deg C) with no loss of
|
|
||||||
// precision or dynamic range. But for backwards compatibility, let's instead
|
|
||||||
// convert this into a 32-bit signed integer in units of milli Celsius.
|
|
||||||
func milliCelsius(msb uint8, lsb uint8) int32 {
|
|
||||||
t256 := int16(uint16(msb)<<8 | uint16(lsb))
|
|
||||||
t1000 := int32(t256) / 64 * 250
|
|
||||||
return t1000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint8ToBCD converts a byte to BCD for the DS3231
|
// uint8ToBCD converts a byte to BCD for the DS3231
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
package ds3231
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPositiveMilliCelsius(t *testing.T) {
|
|
||||||
t1000 := milliCelsius(0, 0)
|
|
||||||
if t1000 != 0 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0, 0b01000000)
|
|
||||||
if t1000 != 250 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0, 0b10000000)
|
|
||||||
if t1000 != 500 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0, 0b11000000)
|
|
||||||
if t1000 != 750 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(1, 0b00000000)
|
|
||||||
if t1000 != 1000 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(2, 0b00000000)
|
|
||||||
if t1000 != 2000 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// highest temperature is 127.750C
|
|
||||||
t1000 = milliCelsius(0x7f, 0b11000000)
|
|
||||||
if t1000 != 127750 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNegativeMilliCelsius(t *testing.T) {
|
|
||||||
t1000 := milliCelsius(0xff, 0b11000000)
|
|
||||||
if t1000 != -250 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0xff, 0b10000000)
|
|
||||||
if t1000 != -500 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0xff, 0b01000000)
|
|
||||||
if t1000 != -750 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0xff, 0b00000000)
|
|
||||||
if t1000 != -1000 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
t1000 = milliCelsius(0xfe, 0b00000000)
|
|
||||||
if t1000 != -2000 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lowest temperature is -128.000C
|
|
||||||
t1000 = milliCelsius(0x80, 0b00000000)
|
|
||||||
if t1000 != -128000 {
|
|
||||||
t.Fatal(t1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
//
|
//
|
||||||
// AT command set:
|
// AT command set:
|
||||||
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
||||||
|
//
|
||||||
package espat // import "tinygo.org/x/drivers/espat"
|
package espat // import "tinygo.org/x/drivers/espat"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ func (d *Device) GetDNS(domain string) (string, error) {
|
|||||||
return "", errors.New("Invalid domain lookup result")
|
return "", errors.New("Invalid domain lookup result")
|
||||||
}
|
}
|
||||||
res := strings.Split(r[1], "\r\n")
|
res := strings.Split(r[1], "\r\n")
|
||||||
return strings.Trim(res[0], `"`), nil
|
return res[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectTCPSocket creates a new TCP socket connection for the ESP8266/ESP32.
|
// ConnectTCPSocket creates a new TCP socket connection for the ESP8266/ESP32.
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"machine/usb/hid/mouse"
|
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/as560x"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Let's use the AS5600 to make the world's most useless mouse with just a single X-axis & no buttons (!)
|
|
||||||
machine.I2C0.Configure(machine.I2CConfig{
|
|
||||||
Frequency: machine.TWI_FREQ_400KHZ,
|
|
||||||
SDA: machine.GPIO4,
|
|
||||||
SCL: machine.GPIO5,
|
|
||||||
})
|
|
||||||
as5600 := as560x.NewAS5600(machine.I2C0)
|
|
||||||
as5600.Configure(as560x.Config{})
|
|
||||||
mouse := mouse.New()
|
|
||||||
|
|
||||||
lastAngle := -1
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Millisecond * 10)
|
|
||||||
// Get the magnet status of the AS5600
|
|
||||||
magnetDetected, magnetStrength, err := as5600.MagnetStatus()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Get the raw angle from the AS5600
|
|
||||||
angle, _, err := as5600.RawAngle(as560x.ANGLE_NATIVE)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
str := ""
|
|
||||||
if !magnetDetected {
|
|
||||||
str += "NOT "
|
|
||||||
}
|
|
||||||
str += "detected. Strength is "
|
|
||||||
switch magnetStrength {
|
|
||||||
case as560x.MagnetTooWeak:
|
|
||||||
str += "too weak"
|
|
||||||
case as560x.MagnetTooStrong:
|
|
||||||
str += "too strong"
|
|
||||||
default:
|
|
||||||
str += "ok"
|
|
||||||
}
|
|
||||||
println("Raw angle:", angle, "Magnet was", str)
|
|
||||||
if lastAngle != -1 {
|
|
||||||
diff := int(angle) - lastAngle
|
|
||||||
// correct the zero crossover glitch
|
|
||||||
if diff < -0xc00 {
|
|
||||||
diff += 0xfff
|
|
||||||
} else if diff > 0xc00 {
|
|
||||||
diff -= 0xfff
|
|
||||||
}
|
|
||||||
// debounce the noise (could use the sensor's filters/hysteresis instead?)
|
|
||||||
if math.Abs(float64(diff)) > 2 {
|
|
||||||
// move the mouse x-axis in response to the AS5600
|
|
||||||
mouse.Move(diff, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastAngle = int(angle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// Smoke test for the BMA421/BMA425 sensors.
|
|
||||||
// Warning: this code has _not been tested_. It's only here as a smoke test.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
"tinygo.org/x/drivers/bma42x"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
i2cBus := machine.I2C1
|
|
||||||
i2cBus.Configure(machine.I2CConfig{
|
|
||||||
Frequency: 400 * machine.KHz,
|
|
||||||
SDA: machine.SDA_PIN,
|
|
||||||
SCL: machine.SCL_PIN,
|
|
||||||
})
|
|
||||||
|
|
||||||
sensor := bma42x.NewI2C(i2cBus, bma42x.Address)
|
|
||||||
err := sensor.Configure(bma42x.Config{
|
|
||||||
Device: bma42x.DeviceBMA421 | bma42x.DeviceBMA425,
|
|
||||||
Features: bma42x.FeatureStepCounting,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
println("could not configure BMA421/BMA425:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sensor.Connected() {
|
|
||||||
println("BMA42x not connected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
|
|
||||||
err := sensor.Update(drivers.Acceleration | drivers.Temperature)
|
|
||||||
if err != nil {
|
|
||||||
println("Error reading sensor", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Temperature: %.2f °C\n", float32(sensor.Temperature())/1000)
|
|
||||||
|
|
||||||
accelX, accelY, accelZ := sensor.Acceleration()
|
|
||||||
fmt.Printf("Acceleration: %.2fg %.2fg %.2fg\n", float32(accelX)/1e6, float32(accelY)/1e6, float32(accelZ)/1e6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,9 +27,6 @@ func main() {
|
|||||||
pressure, _ := sensor.ReadPressure()
|
pressure, _ := sensor.ReadPressure()
|
||||||
println("Pressure", float32(pressure)/100000, "hPa")
|
println("Pressure", float32(pressure)/100000, "hPa")
|
||||||
|
|
||||||
altitude, _ := sensor.ReadAltitude()
|
|
||||||
println("Altitude", altitude, "meters")
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/delay"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
time.Sleep(time.Second) // wait for a serial console
|
|
||||||
start := time.Now()
|
|
||||||
for i := 0; i < 2000; i++ {
|
|
||||||
delay.Sleep(50 * time.Microsecond)
|
|
||||||
}
|
|
||||||
duration := time.Since(start)
|
|
||||||
println("sleep of 2000*50µs (100ms) took:", duration.String())
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/onewire"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/ds18b20"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Define pin for DS18B20
|
|
||||||
pin := machine.D2
|
|
||||||
|
|
||||||
ow := onewire.New(pin)
|
|
||||||
romIDs, err := ow.Search(onewire.SEARCH_ROM)
|
|
||||||
if err != nil {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
sensor := ds18b20.New(ow)
|
|
||||||
|
|
||||||
for {
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
|
|
||||||
println()
|
|
||||||
println("Device:", machine.Device)
|
|
||||||
|
|
||||||
println()
|
|
||||||
println("Request Temperature.")
|
|
||||||
for _, romid := range romIDs {
|
|
||||||
println("Sensor RomID: ", hex.EncodeToString(romid))
|
|
||||||
sensor.RequestTemperature(romid)
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait 750ms or more for DS18B20 convert T
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
println()
|
|
||||||
println("Read Temperature")
|
|
||||||
for _, romid := range romIDs {
|
|
||||||
raw, err := sensor.ReadTemperatureRaw(romid)
|
|
||||||
if err != nil {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
println("Sensor RomID: ", hex.EncodeToString(romid))
|
|
||||||
println("Temperature Raw value: ", hex.EncodeToString(raw))
|
|
||||||
|
|
||||||
t, err := sensor.ReadTemperature(romid)
|
|
||||||
if err != nil {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
println("Temperature in celsius milli degrees (°C/1000): ", t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
// More information on the Espressif AT command set at:
|
// More information on the Espressif AT command set at:
|
||||||
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
// https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -18,11 +19,9 @@ import (
|
|||||||
// change actAsAP to true to act as an access point instead of connecting to one.
|
// change actAsAP to true to act as an access point instead of connecting to one.
|
||||||
const actAsAP = false
|
const actAsAP = false
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// these are the default pins for the Arduino Nano33 IoT.
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
// In other words:
|
// In other words:
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
|
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 <--> INTERNET
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -16,11 +17,9 @@ import (
|
|||||||
// change actAsAP to true to act as an access point instead of connecting to one.
|
// change actAsAP to true to act as an access point instead of connecting to one.
|
||||||
const actAsAP = false
|
const actAsAP = false
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// these are the default pins for the Arduino Nano33 IoT.
|
// these are the default pins for the Arduino Nano33 IoT.
|
||||||
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
// change these to connect to a different UART or pins for the ESP8266/ESP32
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
// In other words:
|
// In other words:
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -13,11 +14,9 @@ import (
|
|||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the listener aka "hub". Replace with your own info.
|
// IP address of the listener aka "hub". Replace with your own info.
|
||||||
const hubIP = "0.0.0.0"
|
const hubIP = "0.0.0.0"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
//
|
//
|
||||||
// You must install the Paho MQTT package to build this program:
|
// You must install the Paho MQTT package to build this program:
|
||||||
//
|
//
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -19,11 +20,9 @@ import (
|
|||||||
"tinygo.org/x/drivers/net/mqtt"
|
"tinygo.org/x/drivers/net/mqtt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the MQTT broker to use. Replace with your own info.
|
// IP address of the MQTT broker to use. Replace with your own info.
|
||||||
const server = "tcp://test.mosquitto.org:1883"
|
const server = "tcp://test.mosquitto.org:1883"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
//
|
//
|
||||||
// You must also install the Paho MQTT package to build this program:
|
// You must also install the Paho MQTT package to build this program:
|
||||||
//
|
//
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -20,11 +21,9 @@ import (
|
|||||||
"tinygo.org/x/drivers/net/mqtt"
|
"tinygo.org/x/drivers/net/mqtt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the MQTT broker to use. Replace with your own info.
|
// IP address of the MQTT broker to use. Replace with your own info.
|
||||||
//const server = "tcp://test.mosquitto.org:1883"
|
//const server = "tcp://test.mosquitto.org:1883"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
// In other words:
|
// In other words:
|
||||||
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -13,11 +14,9 @@ import (
|
|||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// access point info
|
||||||
// access point info
|
const ssid = "YOURSSID"
|
||||||
ssid string
|
const pass = "YOURPASS"
|
||||||
pass string
|
|
||||||
)
|
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
// IP address of the server aka "hub". Replace with your own info.
|
||||||
const serverIP = "0.0.0.0"
|
const serverIP = "0.0.0.0"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build m5stack_core2
|
//go:build m5stack_core2
|
||||||
|
// +build m5stack_core2
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build m5stack_core2
|
//go:build m5stack_core2
|
||||||
|
// +build m5stack_core2
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"image/color"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/gc9a01"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.SPI0.Configure(machine.SPIConfig{
|
|
||||||
Frequency: 80000000,
|
|
||||||
})
|
|
||||||
display := gc9a01.New(machine.SPI0, machine.P6, machine.P7, machine.P8, machine.P9)
|
|
||||||
display.Configure(gc9a01.Config{Orientation: gc9a01.HORIZONTAL, Width: 240, Height: 240})
|
|
||||||
|
|
||||||
width, height := display.Size()
|
|
||||||
|
|
||||||
white := color.RGBA{255, 255, 255, 255}
|
|
||||||
red := color.RGBA{255, 0, 0, 255}
|
|
||||||
blue := color.RGBA{0, 0, 255, 255}
|
|
||||||
green := color.RGBA{0, 255, 0, 255}
|
|
||||||
black := color.RGBA{0, 0, 0, 255}
|
|
||||||
|
|
||||||
display.FillScreen(black)
|
|
||||||
|
|
||||||
display.FillRectangle(0, 0, width/2, height/2, white)
|
|
||||||
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
|
||||||
display.FillRectangle(0, height/2, width/2, height/2, green)
|
|
||||||
display.FillRectangle(width/2, height/2, width/2, height/2, blue)
|
|
||||||
display.FillRectangle(width/4, height/4, width/2, height/2, black)
|
|
||||||
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Hour)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build atsamd21
|
//go:build atsamd21
|
||||||
|
// +build atsamd21
|
||||||
|
|
||||||
package initdisplay
|
package initdisplay
|
||||||
|
|
||||||
@@ -8,6 +9,8 @@ import (
|
|||||||
"tinygo.org/x/drivers/ili9341"
|
"tinygo.org/x/drivers/ili9341"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ()
|
||||||
|
|
||||||
func InitDisplay() *ili9341.Device {
|
func InitDisplay() *ili9341.Device {
|
||||||
machine.SPI0.Configure(machine.SPIConfig{
|
machine.SPI0.Configure(machine.SPIConfig{
|
||||||
SCK: machine.SPI0_SCK_PIN,
|
SCK: machine.SPI0_SCK_PIN,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build feather_m0 || feather_m4 || feather_m4_can || feather_nrf52840 || feather_nrf52840_sense || feather_stm32f405 || feather_rp2040
|
//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
|
package initdisplay
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build m5stack
|
//go:build m5stack
|
||||||
|
// +build m5stack
|
||||||
|
|
||||||
package initdisplay
|
package initdisplay
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build m5stack_core2
|
//go:build m5stack_core2
|
||||||
|
// +build m5stack_core2
|
||||||
|
|
||||||
package initdisplay
|
package initdisplay
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build pyportal
|
//go:build pyportal
|
||||||
|
// +build pyportal
|
||||||
|
|
||||||
package initdisplay
|
package initdisplay
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//go:build wioterminal
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
package initdisplay
|
package initdisplay
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
# AT-CMD implementation of at-lora command set
|
|
||||||
|
|
||||||
This example implements the AT command set as used by Seeed in the LoRa-E5 series of boards, but in the form of a TinyGo program that provides a serial interface.
|
|
||||||
|
|
||||||
See https://files.seeedstudio.com/products/317990687/res/LoRa-E5%20AT%20Command%20Specification_V1.0%20.pdf for more information.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tinygo monitor
|
|
||||||
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
|
|
||||||
+AT: OK
|
|
||||||
+VER: 0.0.1 (sx127x v18)
|
|
||||||
```
|
|
||||||
|
|
||||||
# Building
|
|
||||||
|
|
||||||
Run the following commands from the main `drivers` directory.
|
|
||||||
|
|
||||||
## Simulator
|
|
||||||
|
|
||||||
Builds/flashes atcmd console application with simulator instead of actual LoRa radio.
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target pico ./examples/lora/lorawan/atcmd/
|
|
||||||
```
|
|
||||||
|
|
||||||
## PyBadge with LoRa Featherwing
|
|
||||||
|
|
||||||
Builds/flashes atcmd console application on PyBadge using LoRa Featherwing (RFM95/SX1276).
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/atcmd/
|
|
||||||
```
|
|
||||||
|
|
||||||
## LoRa-E5
|
|
||||||
|
|
||||||
Builds/flashes atcmd console application on Lora-E5 using onboard SX126x.
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target lorae5 ./examples/lora/lorawan/atcmd/
|
|
||||||
```
|
|
||||||
|
|
||||||
## Joining a Public Lorawan Network
|
|
||||||
|
|
||||||
```
|
|
||||||
AT+ID=DevEui,0101010101010101
|
|
||||||
AT+ID=AppEui,0123012301230213
|
|
||||||
AT+KEY=APPKEY,AEAEAEAEAEAEAEAAEAEAEAEAEAEAAEAE
|
|
||||||
AT+LW=NET,ON
|
|
||||||
AT+JOIN
|
|
||||||
```
|
|
||||||
|
|
||||||
AT+LW=NET,(ON|OFF) command changes Lora Sync Word to connect on public network(ON) or private networks(OFF)
|
|
||||||
@@ -1,496 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Use to test if connection to module is OK.
|
|
||||||
func quicktest() {
|
|
||||||
writeCommandOutput("AT", "OK")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check firmware version.
|
|
||||||
func version() {
|
|
||||||
writeCommandOutput("VER", common.CurrentVersion()+" ("+common.FirmwareVersion()+")")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to check the ID of the LoRaWAN module, or change the ID.
|
|
||||||
func id(args string) error {
|
|
||||||
cmd := "ID"
|
|
||||||
|
|
||||||
// look for comma in args
|
|
||||||
param, val, hasComma := strings.Cut(args, ",")
|
|
||||||
if hasComma {
|
|
||||||
// set
|
|
||||||
data := strings.Trim(val, "\"'")
|
|
||||||
|
|
||||||
// convert data from hex formatted string
|
|
||||||
data = strings.ReplaceAll(data, " ", "")
|
|
||||||
hexdata, err := hex.DecodeString(data)
|
|
||||||
if err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch param {
|
|
||||||
case "DevAddr":
|
|
||||||
if err := session.SetDevAddr(hexdata); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "DevAddr, "+session.GetDevAddr())
|
|
||||||
case "DevEui":
|
|
||||||
if err := otaa.SetDevEUI(hexdata); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "DevEui, "+otaa.GetDevEUI())
|
|
||||||
case "AppEui":
|
|
||||||
if err := otaa.SetAppEUI(hexdata); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "AppEui, "+otaa.GetAppEUI())
|
|
||||||
default:
|
|
||||||
return errInvalidCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// get
|
|
||||||
switch param {
|
|
||||||
case "DevAddr":
|
|
||||||
writeCommandOutput(cmd, "DevAddr, "+session.GetDevAddr())
|
|
||||||
case "DevEui":
|
|
||||||
writeCommandOutput(cmd, "DevEui, "+otaa.GetDevEUI())
|
|
||||||
case "AppEui":
|
|
||||||
writeCommandOutput(cmd, "AppEui, "+otaa.GetAppEUI())
|
|
||||||
default:
|
|
||||||
writeCommandOutput(cmd, "DevAddr, "+session.GetDevAddr())
|
|
||||||
writeCommandOutput(cmd, "DevEui, "+otaa.GetDevEUI())
|
|
||||||
writeCommandOutput(cmd, "AppEui, "+otaa.GetAppEUI())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to reset the module. If module returns error, then reset function is invalid.
|
|
||||||
func reset() error {
|
|
||||||
radio.Reset()
|
|
||||||
|
|
||||||
writeCommandOutput("RESET", "OK")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send string format frame which is no need to be confirmed by the server.
|
|
||||||
func msg(data string) error {
|
|
||||||
cmd := "MSG"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send string format frame which must be confirmed by the server
|
|
||||||
func cmsg(data string) error {
|
|
||||||
cmd := "CMSG"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: confirmation
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send hex format frame which is no need to be confirmed by the server
|
|
||||||
func msghex(data string) error {
|
|
||||||
cmd := "MSGHEX"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send hex format frame which must be confirmed by the server.
|
|
||||||
func cmsghex(data string) error {
|
|
||||||
cmd := "CMSGHEX"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send string format LoRaWAN proprietary frames
|
|
||||||
func pmsg(data string) error {
|
|
||||||
cmd := "PMSG"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use to send hex format LoRaWAN proprietary frames.
|
|
||||||
func pmsghex(data string) error {
|
|
||||||
cmd := "PMSGHEX"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set PORT number which will be used by MSG/CMSG/MSGHEX/CMSGHEX command to send
|
|
||||||
// message, port number should range from 1 to 255. User should refer to LoRaWAN
|
|
||||||
// specification to choose port.
|
|
||||||
func port(p string) error {
|
|
||||||
cmd := "PMSG"
|
|
||||||
writeCommandOutput(cmd, p)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set ADR function of LoRaWAN module
|
|
||||||
func adr(state string) error {
|
|
||||||
cmd := "ADR"
|
|
||||||
writeCommandOutput(cmd, state)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use LoRaWAN defined DRx to set datarate of LoRaWAN AT modem.
|
|
||||||
func dr(rate string) error {
|
|
||||||
cmd := "DR"
|
|
||||||
writeCommandOutput(cmd, rate)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channel Configuration
|
|
||||||
func ch(channel string) error {
|
|
||||||
cmd := "CH"
|
|
||||||
writeCommandOutput(cmd, channel)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set and Check Power
|
|
||||||
func power(setting string) error {
|
|
||||||
cmd := "POWER"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unconfirmed message repeats times.
|
|
||||||
func rept(setting string) error {
|
|
||||||
cmd := "REPT"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirmed message retry times. Valid range 0~254,
|
|
||||||
// if retry times is less than 2, only one message will
|
|
||||||
// be sent. Random delay 3 - 10s between each retry
|
|
||||||
// (band duty cycle limitation has the priority)
|
|
||||||
func retry(setting string) error {
|
|
||||||
cmd := "RETRY"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rxwin2(setting string) error {
|
|
||||||
cmd := "RXWIN2"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rxwin1(setting string) error {
|
|
||||||
cmd := "RXWIN1"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func key(setting string) error {
|
|
||||||
cmd := "KEY"
|
|
||||||
|
|
||||||
// look for comma in args
|
|
||||||
param, val, hasComma := strings.Cut(setting, ",")
|
|
||||||
if hasComma {
|
|
||||||
// set
|
|
||||||
data := strings.Trim(val, "\"'")
|
|
||||||
|
|
||||||
// convert data from hex formatted string
|
|
||||||
data = strings.ReplaceAll(data, " ", "")
|
|
||||||
hexdata, err := hex.DecodeString(data)
|
|
||||||
if err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch param {
|
|
||||||
case "APPKEY":
|
|
||||||
if err := otaa.SetAppKey(hexdata); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "APPKEY, "+otaa.GetAppKey())
|
|
||||||
default:
|
|
||||||
return errInvalidCommand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cannot get keys
|
|
||||||
return errInvalidCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
func fdefault(setting string) error {
|
|
||||||
cmd := "FDEFAULT"
|
|
||||||
writeCommandOutput(cmd, "OK")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func mode(setting string) error {
|
|
||||||
cmd := "MODE"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func join(setting string) error {
|
|
||||||
// TODO: check that DevEUI, AppEUI, and AppKey have values
|
|
||||||
|
|
||||||
cmd := "JOIN"
|
|
||||||
writeCommandOutput(cmd, "Starting")
|
|
||||||
if err := lorawan.Join(otaa, session); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Network joined")
|
|
||||||
writeCommandOutput(cmd, "DevEui, "+otaa.GetDevEUI())
|
|
||||||
writeCommandOutput(cmd, "AppEui, "+otaa.GetAppEUI())
|
|
||||||
writeCommandOutput(cmd, "DevAddr, "+session.GetDevAddr())
|
|
||||||
writeCommandOutput(cmd, "NetID, "+otaa.GetNetID())
|
|
||||||
writeCommandOutput(cmd, "NwkSKey, "+session.GetNwkSKey())
|
|
||||||
writeCommandOutput(cmd, "AppSKey, "+session.GetAppSKey())
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func beacon(setting string) error {
|
|
||||||
cmd := "BEACON"
|
|
||||||
writeCommandOutput(cmd, "Starting")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func class(setting string) error {
|
|
||||||
cmd := "CLASS"
|
|
||||||
writeCommandOutput(cmd, "Starting")
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func delay(setting string) error {
|
|
||||||
cmd := "DELAY"
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lw(setting string) error {
|
|
||||||
cmd := "LW"
|
|
||||||
|
|
||||||
param, val, hasComma := strings.Cut(setting, ",")
|
|
||||||
if hasComma {
|
|
||||||
if param == "NET" {
|
|
||||||
if val == "ON" {
|
|
||||||
lorawan.SetPublicNetwork(true)
|
|
||||||
} else {
|
|
||||||
lorawan.SetPublicNetwork(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeCommandOutput(cmd, setting)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func wdt(setting string) error {
|
|
||||||
cmd := "WDT"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lowpower(setting string) error {
|
|
||||||
cmd := "LOWPOWER"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func vdd(setting string) error {
|
|
||||||
cmd := "VDD"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func temp(setting string) error {
|
|
||||||
cmd := "TEMP"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rtc(setting string) error {
|
|
||||||
cmd := "RTC"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func eeprom(setting string) error {
|
|
||||||
cmd := "EEPROM"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func uartcmd(setting string) error {
|
|
||||||
cmd := "UART"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func test(setting string) error {
|
|
||||||
cmd := "TEST"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func log(setting string) error {
|
|
||||||
cmd := "LOG"
|
|
||||||
writeCommandOutput(cmd, "Not implemented")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func send(data string) error {
|
|
||||||
cmd := "SEND"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
// remove leading/trailing quotes
|
|
||||||
data = strings.Trim(data, "\"'")
|
|
||||||
|
|
||||||
if err := radio.Tx([]byte(data), defaultTimeout); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendhex(data string) error {
|
|
||||||
cmd := "SENDHEX"
|
|
||||||
writeCommandOutput(cmd, "Start")
|
|
||||||
|
|
||||||
// remove leading/trailing quotes
|
|
||||||
data = strings.Trim(data, "\"'")
|
|
||||||
|
|
||||||
// convert data from hex formatted string
|
|
||||||
data = strings.ReplaceAll(data, " ", "")
|
|
||||||
payload, err := hex.DecodeString(data)
|
|
||||||
if err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := radio.Tx(payload, defaultTimeout); err != nil {
|
|
||||||
writeCommandOutput(cmd, err.Error())
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
writeCommandOutput(cmd, "Done")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func recv(setting string) error {
|
|
||||||
cmd := "RECV"
|
|
||||||
|
|
||||||
data, err := common.Lorarx()
|
|
||||||
if err != nil {
|
|
||||||
writeCommandOutput(cmd, "ERROR "+err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
writeCommandOutput(cmd, string(data))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func recvhex(setting string) error {
|
|
||||||
cmd := "RECVHEX"
|
|
||||||
|
|
||||||
data, err := common.Lorarx()
|
|
||||||
if err != nil {
|
|
||||||
writeCommandOutput(cmd, "ERROR "+err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
writeCommandOutput(cmd, string(data))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func crlf() {
|
|
||||||
uart.Write([]byte("\r\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeCommandOutput(cmd, data string) {
|
|
||||||
uart.Write([]byte("+" + cmd + ": "))
|
|
||||||
uart.Write([]byte(data))
|
|
||||||
crlf()
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
// AT command set console running on the device UART to communicate with
|
|
||||||
// an attached LoRa device.
|
|
||||||
//
|
|
||||||
// Computer <-> UART <-> MCU <-> SPI <-> SX126x/SX127x
|
|
||||||
//
|
|
||||||
// Connect using default baudrate for this hardware, 8-N-1 with your terminal program.
|
|
||||||
// For details on the AT command set, see:
|
|
||||||
// https://files.seeedstudio.com/products/317990687/res/LoRa-E5%20AT%20Command%20Specification_V1.0%20.pdf
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan/region"
|
|
||||||
)
|
|
||||||
|
|
||||||
// change these to test a different UART or pins if available
|
|
||||||
var (
|
|
||||||
uart = machine.Serial
|
|
||||||
tx = machine.UART_TX_PIN
|
|
||||||
rx = machine.UART_RX_PIN
|
|
||||||
input = make([]byte, 0, 64)
|
|
||||||
|
|
||||||
radio lora.Radio
|
|
||||||
session *lorawan.Session
|
|
||||||
otaa *lorawan.Otaa
|
|
||||||
|
|
||||||
defaultTimeout uint32 = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
|
|
||||||
|
|
||||||
var err error
|
|
||||||
radio, err = common.SetupLora()
|
|
||||||
if err != nil {
|
|
||||||
fail(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
session = &lorawan.Session{}
|
|
||||||
otaa = &lorawan.Otaa{}
|
|
||||||
lorawan.UseRadio(radio)
|
|
||||||
|
|
||||||
lorawan.UseRegionSettings(region.EU868())
|
|
||||||
|
|
||||||
for {
|
|
||||||
if uart.Buffered() > 0 {
|
|
||||||
data, _ := uart.ReadByte()
|
|
||||||
|
|
||||||
switch data {
|
|
||||||
case 13:
|
|
||||||
// return key
|
|
||||||
if err := parse(input); err != nil {
|
|
||||||
uart.Write([]byte("ERROR: "))
|
|
||||||
uart.Write([]byte(err.Error()))
|
|
||||||
crlf()
|
|
||||||
}
|
|
||||||
input = input[:0]
|
|
||||||
default:
|
|
||||||
// just capture the character
|
|
||||||
input = append(input, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fail(msg string) {
|
|
||||||
for {
|
|
||||||
uart.Write([]byte(msg))
|
|
||||||
crlf()
|
|
||||||
|
|
||||||
time.Sleep(time.Minute)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errInvalidCommand = errors.New("Invalid command")
|
|
||||||
)
|
|
||||||
|
|
||||||
func parse(data []byte) error {
|
|
||||||
switch {
|
|
||||||
case len(data) < 2, string(data[0:2]) != "AT":
|
|
||||||
return errInvalidCommand
|
|
||||||
case len(data) == 2:
|
|
||||||
// just the AT command by itself
|
|
||||||
quicktest()
|
|
||||||
case len(data) < 6 || data[2] != '+':
|
|
||||||
return errInvalidCommand
|
|
||||||
default:
|
|
||||||
// parse the rest of the command
|
|
||||||
cmd, args, _ := strings.Cut(string(data[3:]), "=")
|
|
||||||
return parseCommand(cmd, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCommand(cmd, args string) error {
|
|
||||||
switch cmd {
|
|
||||||
case "VER":
|
|
||||||
version()
|
|
||||||
case "ID":
|
|
||||||
id(args)
|
|
||||||
case "RESET":
|
|
||||||
reset()
|
|
||||||
case "MSG":
|
|
||||||
msg(args)
|
|
||||||
case "CMSG":
|
|
||||||
cmsg(args)
|
|
||||||
case "MSGHEX":
|
|
||||||
msghex(args)
|
|
||||||
case "CMSGHEX":
|
|
||||||
cmsghex(args)
|
|
||||||
case "PMSG":
|
|
||||||
pmsg(args)
|
|
||||||
case "PMSGHEX":
|
|
||||||
pmsg(args)
|
|
||||||
case "PORT":
|
|
||||||
port(args)
|
|
||||||
case "ADR":
|
|
||||||
adr(args)
|
|
||||||
case "DR":
|
|
||||||
dr(args)
|
|
||||||
case "CH":
|
|
||||||
ch(args)
|
|
||||||
case "POWER":
|
|
||||||
power(args)
|
|
||||||
case "REPT":
|
|
||||||
rept(args)
|
|
||||||
case "RETRY":
|
|
||||||
retry(args)
|
|
||||||
case "RXWIN2":
|
|
||||||
rxwin2(args)
|
|
||||||
case "RXWIN1":
|
|
||||||
rxwin1(args)
|
|
||||||
case "KEY":
|
|
||||||
key(args)
|
|
||||||
case "FDEFAULT":
|
|
||||||
fdefault(args)
|
|
||||||
case "MODE":
|
|
||||||
mode(args)
|
|
||||||
case "JOIN":
|
|
||||||
join(args)
|
|
||||||
case "BEACON":
|
|
||||||
join(args)
|
|
||||||
case "CLASS":
|
|
||||||
class(args)
|
|
||||||
case "DELAY":
|
|
||||||
delay(args)
|
|
||||||
case "LW":
|
|
||||||
lw(args)
|
|
||||||
case "WDT":
|
|
||||||
wdt(args)
|
|
||||||
case "LOWPOWER":
|
|
||||||
lowpower(args)
|
|
||||||
case "VDD":
|
|
||||||
vdd(args)
|
|
||||||
case "TEMP":
|
|
||||||
temp(args)
|
|
||||||
case "RTC":
|
|
||||||
rtc(args)
|
|
||||||
case "EEPROM":
|
|
||||||
eeprom(args)
|
|
||||||
case "UART":
|
|
||||||
uartcmd(args)
|
|
||||||
case "TEST":
|
|
||||||
test(args)
|
|
||||||
case "LOG":
|
|
||||||
log(args)
|
|
||||||
case "RECV":
|
|
||||||
recv(args)
|
|
||||||
case "RECVHEX":
|
|
||||||
recvhex(args)
|
|
||||||
case "SEND":
|
|
||||||
send(args)
|
|
||||||
case "SENDHEX":
|
|
||||||
sendhex(args)
|
|
||||||
default:
|
|
||||||
return errInvalidCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# Simple Lorawan example
|
|
||||||
|
|
||||||
This demo code will connect Lorawan network and send sample uplink message
|
|
||||||
|
|
||||||
You may change your Lorawan keys (AppEUI, DevEUI, AppKEY) in key-default.go
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tinygo monitor
|
|
||||||
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
|
|
||||||
Lorawan Simple Demo
|
|
||||||
Start Lorawan Join sequence
|
|
||||||
loraConnect: Connected !
|
|
||||||
```
|
|
||||||
|
|
||||||
# Building
|
|
||||||
|
|
||||||
## Simulator
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target pico ./examples/lora/lorawan/basic-demo
|
|
||||||
```
|
|
||||||
|
|
||||||
## PyBadge with LoRa Featherwing
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target pybadge -tags featherwing ./examples/lora/lorawan/basic-demo
|
|
||||||
```
|
|
||||||
|
|
||||||
## LoRa-E5
|
|
||||||
|
|
||||||
```
|
|
||||||
tinygo flash -target lorae5 ./examples/lora/lorawan/basic-demo
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Enable debugging
|
|
||||||
|
|
||||||
You can also enable some debug logs with ldflags :
|
|
||||||
|
|
||||||
```
|
|
||||||
$ tinygo build -ldflags="-X 'main.debug=true'" -target=lorae5
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
//go:build !customkeys
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These are sample keys, so the example builds
|
|
||||||
// Either change here, or create a new go file and use customkeys build tag
|
|
||||||
func setLorawanKeys() {
|
|
||||||
otaa.SetAppEUI([]uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
|
|
||||||
otaa.SetDevEUI([]uint8{0xB3, 0xD5, 0x41, 0x00, 0x0A, 0xF1, 0xA4, 0x45})
|
|
||||||
otaa.SetAppKey([]uint8{0x12, 0x22, 0xA3, 0xFF, 0x0C, 0x7B, 0x76, 0x7B, 0x8F, 0xD3, 0x12, 0x4F, 0xCE, 0x7A, 0x32, 0x16})
|
|
||||||
lorawan.SetPublicNetwork(true)
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// Simple code for connecting to Lorawan network and uploading sample payload
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/examples/lora/lorawan/common"
|
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan"
|
|
||||||
"tinygo.org/x/drivers/lora/lorawan/region"
|
|
||||||
)
|
|
||||||
|
|
||||||
var debug string
|
|
||||||
|
|
||||||
const (
|
|
||||||
LORAWAN_JOIN_TIMEOUT_SEC = 180
|
|
||||||
LORAWAN_RECONNECT_DELAY_SEC = 15
|
|
||||||
LORAWAN_UPLINK_DELAY_SEC = 60
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
radio lora.Radio
|
|
||||||
session *lorawan.Session
|
|
||||||
otaa *lorawan.Otaa
|
|
||||||
)
|
|
||||||
|
|
||||||
func loraConnect() error {
|
|
||||||
start := time.Now()
|
|
||||||
var err error
|
|
||||||
for time.Since(start) < LORAWAN_JOIN_TIMEOUT_SEC*time.Second {
|
|
||||||
println("Trying to join network")
|
|
||||||
err = lorawan.Join(otaa, session)
|
|
||||||
if err == nil {
|
|
||||||
println("Connected to network !")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
println("Join error:", err, "retrying in", LORAWAN_RECONNECT_DELAY_SEC, "sec")
|
|
||||||
time.Sleep(time.Second * LORAWAN_RECONNECT_DELAY_SEC)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = errors.New("Unable to join Lorawan network")
|
|
||||||
println(err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func failMessage(err error) {
|
|
||||||
println("FATAL:", err)
|
|
||||||
for {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
println("*** Lorawan basic join and uplink demo ***")
|
|
||||||
|
|
||||||
// Board specific Lorawan initialization
|
|
||||||
var err error
|
|
||||||
radio, err = common.SetupLora()
|
|
||||||
if err != nil {
|
|
||||||
failMessage(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for LoraWan operations
|
|
||||||
session = &lorawan.Session{}
|
|
||||||
otaa = &lorawan.Otaa{}
|
|
||||||
|
|
||||||
// Connect the lorawan with the Lora Radio device.
|
|
||||||
lorawan.UseRadio(radio)
|
|
||||||
|
|
||||||
lorawan.UseRegionSettings(region.EU868())
|
|
||||||
|
|
||||||
// Configure AppEUI, DevEUI, APPKey, and public/private Lorawan Network
|
|
||||||
setLorawanKeys()
|
|
||||||
|
|
||||||
if debug != "" {
|
|
||||||
println("main: Network joined")
|
|
||||||
println("main: DevEui, " + otaa.GetDevEUI())
|
|
||||||
println("main: AppEui, " + otaa.GetAppEUI())
|
|
||||||
println("main: DevAddr, " + otaa.GetAppKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to connect Lorawan network
|
|
||||||
if err := loraConnect(); err != nil {
|
|
||||||
failMessage(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if debug != "" {
|
|
||||||
println("main: NetID, " + otaa.GetNetID())
|
|
||||||
println("main: NwkSKey, " + session.GetNwkSKey())
|
|
||||||
println("main: AppSKey, " + session.GetAppSKey())
|
|
||||||
println("main: Done")
|
|
||||||
}
|
|
||||||
// Try to periodicaly send an uplink sample message
|
|
||||||
upCount := 1
|
|
||||||
for {
|
|
||||||
payload := "Hello TinyGo #" + strconv.Itoa(upCount)
|
|
||||||
|
|
||||||
if err := lorawan.SendUplink([]byte(payload), session); err != nil {
|
|
||||||
println("Uplink error:", err)
|
|
||||||
} else {
|
|
||||||
println("Uplink success, msg=", payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Sleeping for", LORAWAN_UPLINK_DELAY_SEC, "sec")
|
|
||||||
time.Sleep(time.Second * LORAWAN_UPLINK_DELAY_SEC)
|
|
||||||
upCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
//go:build featherwing
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import "machine"
|
|
||||||
|
|
||||||
var (
|
|
||||||
// We assume LoRa Featherwing module with sx127x is connected to PyBadge
|
|
||||||
rstPin = machine.D11
|
|
||||||
csPin = machine.D10
|
|
||||||
dio0Pin = machine.D6
|
|
||||||
dio1Pin = machine.D9
|
|
||||||
spi = machine.SPI0
|
|
||||||
)
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
//go:build lgt92
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import "machine"
|
|
||||||
|
|
||||||
var (
|
|
||||||
rstPin = machine.PB0
|
|
||||||
csPin = machine.PA15
|
|
||||||
dio0Pin = machine.PC13
|
|
||||||
dio1Pin = machine.PB10
|
|
||||||
spi = machine.SPI0
|
|
||||||
)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errRadioNotFound = errors.New("radio not found")
|
|
||||||
errRxTimeout = errors.New("radio RX timeout")
|
|
||||||
)
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//go:build !featherwing && !lgt92 && !stm32wlx && !sx126x
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import "tinygo.org/x/drivers/lora"
|
|
||||||
|
|
||||||
// do simulator setup here
|
|
||||||
func SetupLora() (lora.Radio, error) {
|
|
||||||
return &SimLoraRadio{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SimLoraRadio struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SimLoraRadio) Reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SimLoraRadio) Tx(pkt []uint8, timeoutMs uint32) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SimLoraRadio) Rx(timeoutMs uint32) ([]uint8, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sr *SimLoraRadio) SetFrequency(freq uint32) {}
|
|
||||||
func (sr *SimLoraRadio) SetIqMode(mode uint8) {}
|
|
||||||
func (sr *SimLoraRadio) SetCodingRate(cr uint8) {}
|
|
||||||
func (sr *SimLoraRadio) SetBandwidth(bw uint8) {}
|
|
||||||
func (sr *SimLoraRadio) SetCrc(enable bool) {}
|
|
||||||
func (sr *SimLoraRadio) SetSpreadingFactor(sf uint8) {}
|
|
||||||
func (sr *SimLoraRadio) LoraConfig(cnf lora.Config) {}
|
|
||||||
|
|
||||||
func FirmwareVersion() string {
|
|
||||||
return "simulator " + CurrentVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Lorarx() ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
//go:build stm32wlx
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/sx126x"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FREQ = 868100000
|
|
||||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
|
||||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
loraRadio *sx126x.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var spi = machine.SPI3
|
|
||||||
|
|
||||||
func newRadioControl() sx126x.RadioController {
|
|
||||||
return sx126x.NewRadioControl()
|
|
||||||
}
|
|
||||||
|
|
||||||
// do sx126x setup here
|
|
||||||
func SetupLora() (lora.Radio, error) {
|
|
||||||
loraRadio = sx126x.New(spi)
|
|
||||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
|
||||||
|
|
||||||
// Create radio controller for target
|
|
||||||
loraRadio.SetRadioController(newRadioControl())
|
|
||||||
|
|
||||||
if state := loraRadio.DetectDevice(); !state {
|
|
||||||
return nil, errRadioNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return loraRadio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirmwareVersion() string {
|
|
||||||
return "sx126x"
|
|
||||||
}
|
|
||||||
|
|
||||||
func Lorarx() ([]byte, error) {
|
|
||||||
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
//go:build !stm32wlx && sx126x
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/sx126x"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FREQ = 868100000
|
|
||||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
|
||||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
loraRadio *sx126x.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
spi = machine.SPI0
|
|
||||||
nssPin, busyPin, dio1Pin = machine.GP17, machine.GP10, machine.GP11
|
|
||||||
rxPin, txLowPin, txHighPin = machine.GP13, machine.GP12, machine.GP12
|
|
||||||
)
|
|
||||||
|
|
||||||
func newRadioControl() sx126x.RadioController {
|
|
||||||
return sx126x.NewRadioControl(nssPin, busyPin, dio1Pin, rxPin, txLowPin, txHighPin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// do sx126x setup here
|
|
||||||
func SetupLora() (lora.Radio, error) {
|
|
||||||
loraRadio = sx126x.New(spi)
|
|
||||||
loraRadio.SetDeviceType(sx126x.DEVICE_TYPE_SX1262)
|
|
||||||
|
|
||||||
// Create radio controller for target
|
|
||||||
loraRadio.SetRadioController(newRadioControl())
|
|
||||||
|
|
||||||
if state := loraRadio.DetectDevice(); !state {
|
|
||||||
return nil, errRadioNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return loraRadio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirmwareVersion() string {
|
|
||||||
return "sx126x"
|
|
||||||
}
|
|
||||||
|
|
||||||
func Lorarx() ([]byte, error) {
|
|
||||||
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
//go:build featherwing || lgt92
|
|
||||||
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"machine"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/lora"
|
|
||||||
"tinygo.org/x/drivers/sx127x"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FREQ = 868100000
|
|
||||||
LORA_DEFAULT_RXTIMEOUT_MS = 1000
|
|
||||||
LORA_DEFAULT_TXTIMEOUT_MS = 5000
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
loraRadio *sx127x.Device
|
|
||||||
)
|
|
||||||
|
|
||||||
// do sx127x setup here
|
|
||||||
func SetupLora() (lora.Radio, error) {
|
|
||||||
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
spi.Configure(machine.SPIConfig{Frequency: 500000, Mode: 0})
|
|
||||||
|
|
||||||
loraRadio = sx127x.New(spi, rstPin)
|
|
||||||
loraRadio.SetRadioController(sx127x.NewRadioControl(csPin, dio0Pin, dio1Pin))
|
|
||||||
loraRadio.Reset()
|
|
||||||
|
|
||||||
if state := loraRadio.DetectDevice(); !state {
|
|
||||||
return nil, errRadioNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return loraRadio, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirmwareVersion() string {
|
|
||||||
v := loraRadio.GetVersion()
|
|
||||||
return "sx127x v" + strconv.Itoa(int(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Lorarx() ([]byte, error) {
|
|
||||||
return loraRadio.Rx(LORA_DEFAULT_RXTIMEOUT_MS)
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
const VERSION = "0.0.1"
|
|
||||||
|
|
||||||
func CurrentVersion() string {
|
|
||||||
return VERSION
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
led machine.Pin = machine.LED
|
led machine.Pin = machine.LED
|
||||||
button machine.Pin = machine.D10
|
button machine.Pin = machine.BUTTON
|
||||||
key *makeybutton.Button
|
key *makeybutton.Button
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +25,6 @@ func main() {
|
|||||||
case makeybutton.Released:
|
case makeybutton.Released:
|
||||||
led.Low()
|
led.Low()
|
||||||
}
|
}
|
||||||
// the more frequent the more responsive
|
time.Sleep(100 * time.Millisecond)
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// to read data from the onboard MEMS microphone.
|
// to read data from the onboard MEMS microphone.
|
||||||
//
|
//
|
||||||
// Uses ideas from the https://github.com/adafruit/Adafruit_CircuitPlayground repo.
|
// Uses ideas from the https://github.com/adafruit/Adafruit_CircuitPlayground repo.
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// Connects to an MPU6886 I2C accelerometer/gyroscope.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/mpu6886"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.I2C0.Configure(machine.I2CConfig{})
|
|
||||||
|
|
||||||
accel := mpu6886.New(machine.I2C0)
|
|
||||||
accel.Configure(mpu6886.Config{})
|
|
||||||
|
|
||||||
for {
|
|
||||||
x, y, z, _ := accel.ReadAcceleration()
|
|
||||||
println(x, y, z)
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Connects to an MPU9150 I2C accelerometer/gyroscope.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers/mpu9150"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
machine.I2C0.Configure(machine.I2CConfig{})
|
|
||||||
|
|
||||||
accel := mpu9150.New(machine.I2C0)
|
|
||||||
accel.Configure()
|
|
||||||
|
|
||||||
for {
|
|
||||||
x, y, z := accel.ReadAcceleration(mpu9150.ACCEL_XOUT_H)
|
|
||||||
println(x, y, z)
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
|
||||||
"tinygo.org/x/drivers/ndir"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ndirBus = machine.I2C0
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := ndirBus.Configure(machine.I2CConfig{
|
|
||||||
Frequency: 100_000,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic("i2c config fail:" + err.Error())
|
|
||||||
}
|
|
||||||
// Set the address based on how the resistors are soldered.
|
|
||||||
// True means the left and middle pads are joined.
|
|
||||||
ndirAddr := ndir.Addr(true, false)
|
|
||||||
dev := ndir.NewDevI2C(ndirBus, ndirAddr)
|
|
||||||
err = dev.Init()
|
|
||||||
if err != nil {
|
|
||||||
panic("ndir init fail:" + err.Error())
|
|
||||||
}
|
|
||||||
// Datasheet tells us to wait 12 seconds before reading from the sensor.
|
|
||||||
time.Sleep(12 * time.Second)
|
|
||||||
for {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
err := dev.Update(drivers.AllMeasurements)
|
|
||||||
if err != nil {
|
|
||||||
println(err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
println("PPM:", dev.PPMCO2())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"time"
|
|
||||||
"tinygo.org/x/drivers/onewire"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
pin := machine.D2
|
|
||||||
|
|
||||||
ow := onewire.New(pin)
|
|
||||||
|
|
||||||
for {
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
|
|
||||||
println()
|
|
||||||
println("Device:", machine.Device)
|
|
||||||
|
|
||||||
romIDs, err := ow.Search(onewire.SEARCH)
|
|
||||||
if err != nil {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
for _, romid := range romIDs {
|
|
||||||
println(hex.EncodeToString(romid))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(romIDs) == 1 {
|
|
||||||
// only 1 device on bus
|
|
||||||
r, err := ow.ReadAddress()
|
|
||||||
if err != nil {
|
|
||||||
println(err)
|
|
||||||
}
|
|
||||||
println(hex.EncodeToString(r))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,16 +7,15 @@
|
|||||||
//
|
//
|
||||||
// You must install the Paho MQTT package to build this program:
|
// You must install the Paho MQTT package to build this program:
|
||||||
//
|
//
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
//
|
//
|
||||||
// You can check that mqttpub is running successfully with the following command.
|
// You can check that mqttpub is running successfully with the following command.
|
||||||
//
|
//
|
||||||
// mosquitto_sub -h test.mosquitto.org -t tinygo
|
// mosquitto_sub -h test.mosquitto.org -t tinygo
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
@@ -29,23 +28,23 @@ import (
|
|||||||
// You can override the setting with the init() in another source code.
|
// You can override the setting with the init() in another source code.
|
||||||
// func init() {
|
// func init() {
|
||||||
// ssid = "your-ssid"
|
// ssid = "your-ssid"
|
||||||
// pass = "your-password"
|
// password = "your-password"
|
||||||
// debug = true
|
// debug = true
|
||||||
// server = "tinygo.org"
|
// server = "tinygo.org"
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
password string
|
||||||
server string = "tcp://test.mosquitto.org:1883"
|
server string = "tcp://test.mosquitto.org:1883"
|
||||||
debug = false
|
debug = false
|
||||||
)
|
)
|
||||||
|
|
||||||
var buf [0x400]byte
|
var buf [0x400]byte
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
var lastRequestTime time.Time
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var adaptor *rtl8720dn.Driver
|
var adaptor *rtl8720dn.RTL8720DN
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := run()
|
err := run()
|
||||||
@@ -60,17 +59,18 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
// change the UART and pins as needed for platforms other than the WioTerminal.
|
rtl, err := setupRTL8720DN()
|
||||||
adaptor = rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
if err != nil {
|
||||||
adaptor.Debug(debug)
|
return err
|
||||||
adaptor.Configure()
|
}
|
||||||
|
net.UseDriver(rtl)
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
ip, subnet, gateway, err := rtl.GetIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/rtl8720dn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
uart UARTx
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleInterrupt(interrupt.Interrupt) {
|
||||||
|
// should reset IRQ
|
||||||
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
|
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||||
|
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
machine.RTL8720D_CHIP_PU.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.RTL8720D_CHIP_PU.High()
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
if debug {
|
||||||
|
waitSerial()
|
||||||
|
}
|
||||||
|
|
||||||
|
uart = UARTx{
|
||||||
|
UART: &machine.UART{
|
||||||
|
Buffer: machine.NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||||
|
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||||
|
|
||||||
|
rtl := rtl8720dn.New(uart)
|
||||||
|
rtl.Debug(debug)
|
||||||
|
|
||||||
|
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UARTx struct {
|
||||||
|
*machine.UART
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||||
|
if u.Buffered() == 0 {
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return u.UART.Read(p)
|
||||||
|
}
|
||||||
@@ -7,17 +7,16 @@
|
|||||||
//
|
//
|
||||||
// You must also install the Paho MQTT package to build this program:
|
// You must also install the Paho MQTT package to build this program:
|
||||||
//
|
//
|
||||||
// go get -u github.com/eclipse/paho.mqtt.golang
|
// go get -u github.com/eclipse/paho.mqtt.golang
|
||||||
//
|
//
|
||||||
// You can check that mqttpub/mqttsub is running successfully with the following command.
|
// You can check that mqttpub/mqttsub is running successfully with the following command.
|
||||||
//
|
//
|
||||||
// mosquitto_sub -h test.mosquitto.org -t tinygo/tx
|
// mosquitto_sub -h test.mosquitto.org -t tinygo/tx
|
||||||
// mosquitto_pub -h test.mosquitto.org -t tinygo/rx -m "hello world"
|
// mosquitto_pub -h test.mosquitto.org -t tinygo/rx -m "hello world"
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
@@ -30,23 +29,23 @@ import (
|
|||||||
// You can override the setting with the init() in another source code.
|
// You can override the setting with the init() in another source code.
|
||||||
// func init() {
|
// func init() {
|
||||||
// ssid = "your-ssid"
|
// ssid = "your-ssid"
|
||||||
// pass = "your-password"
|
// password = "your-password"
|
||||||
// debug = true
|
// debug = true
|
||||||
// server = "tinygo.org"
|
// server = "tinygo.org"
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
password string
|
||||||
server string = "tcp://test.mosquitto.org:1883"
|
server string = "tcp://test.mosquitto.org:1883"
|
||||||
debug = false
|
debug = false
|
||||||
)
|
)
|
||||||
|
|
||||||
var buf [0x400]byte
|
var buf [0x400]byte
|
||||||
|
|
||||||
var lastRequestTime time.Time
|
var lastRequestTime time.Time
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var adaptor *rtl8720dn.Driver
|
var adaptor *rtl8720dn.RTL8720DN
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := run()
|
err := run()
|
||||||
@@ -69,17 +68,18 @@ func subHandler(client mqtt.Client, msg mqtt.Message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
// change the UART and pins as needed for platforms other than the WioTerminal.
|
rtl, err := setupRTL8720DN()
|
||||||
adaptor = rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
if err != nil {
|
||||||
adaptor.Debug(debug)
|
return err
|
||||||
adaptor.Configure()
|
}
|
||||||
|
net.UseDriver(rtl)
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
ip, subnet, gateway, err := rtl.GetIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/rtl8720dn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
uart UARTx
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleInterrupt(interrupt.Interrupt) {
|
||||||
|
// should reset IRQ
|
||||||
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
|
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||||
|
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
machine.RTL8720D_CHIP_PU.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.RTL8720D_CHIP_PU.High()
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
if debug {
|
||||||
|
waitSerial()
|
||||||
|
}
|
||||||
|
|
||||||
|
uart = UARTx{
|
||||||
|
UART: &machine.UART{
|
||||||
|
Buffer: machine.NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||||
|
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||||
|
|
||||||
|
rtl := rtl8720dn.New(uart)
|
||||||
|
rtl.Debug(debug)
|
||||||
|
|
||||||
|
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UARTx struct {
|
||||||
|
*machine.UART
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||||
|
if u.Buffered() == 0 {
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return u.UART.Read(p)
|
||||||
|
}
|
||||||
@@ -4,31 +4,28 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/net"
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IP address of the server aka "hub". Replace with your own info.
|
// IP address of the server aka "hub". Replace with your own info.
|
||||||
// You can override the setting with the init() in another source code.
|
// You can override the setting with the init() in another source code.
|
||||||
// func init() {
|
// func init() {
|
||||||
// ssid = "your-ssid"
|
// ssid = "your-ssid"
|
||||||
// pass = "your-password"
|
// password = "your-password"
|
||||||
// ntpHost = "129.6.15.29"
|
// ntpHost = "129.6.15.29"
|
||||||
// debug = true
|
// debug = true
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
password string
|
||||||
ntpHost = "129.6.15.29"
|
ntpHost = "129.6.15.29"
|
||||||
debug = false
|
debug = false
|
||||||
)
|
)
|
||||||
|
|
||||||
const NTP_PACKET_SIZE = 48
|
const NTP_PACKET_SIZE = 48
|
||||||
@@ -44,16 +41,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
rtl, err := setupRTL8720DN()
|
||||||
adaptor.Debug(debug)
|
if err != nil {
|
||||||
adaptor.Configure()
|
return err
|
||||||
|
}
|
||||||
|
net.UseDriver(rtl)
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
ip, subnet, gateway, err := rtl.GetIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -100,7 +99,9 @@ func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
|
|||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
continue // no packet received yet
|
continue // no packet received yet
|
||||||
} else if n != NTP_PACKET_SIZE {
|
} else if n != NTP_PACKET_SIZE {
|
||||||
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
if n != NTP_PACKET_SIZE {
|
||||||
|
return time.Time{}, fmt.Errorf("expected NTP packet size of %d: %d", NTP_PACKET_SIZE, n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return parseNTPpacket(), nil
|
return parseNTPpacket(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/rtl8720dn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
uart UARTx
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleInterrupt(interrupt.Interrupt) {
|
||||||
|
// should reset IRQ
|
||||||
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
|
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||||
|
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
machine.RTL8720D_CHIP_PU.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.RTL8720D_CHIP_PU.High()
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
uart = UARTx{
|
||||||
|
UART: &machine.UART{
|
||||||
|
Buffer: machine.NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||||
|
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||||
|
|
||||||
|
rtl := rtl8720dn.New(uart)
|
||||||
|
rtl.Debug(debug)
|
||||||
|
|
||||||
|
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UARTx struct {
|
||||||
|
*machine.UART
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||||
|
if u.Buffered() == 0 {
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return u.UART.Read(p)
|
||||||
|
}
|
||||||
@@ -4,30 +4,28 @@
|
|||||||
// You can open a server to accept connections from this program using:
|
// You can open a server to accept connections from this program using:
|
||||||
//
|
//
|
||||||
// nc -w 5 -lk 8080
|
// nc -w 5 -lk 8080
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers/net"
|
"tinygo.org/x/drivers/net"
|
||||||
"tinygo.org/x/drivers/rtl8720dn"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// You can override the setting with the init() in another source code.
|
// You can override the setting with the init() in another source code.
|
||||||
// func init() {
|
// func init() {
|
||||||
// ssid = "your-ssid"
|
// ssid = "sghome-gw"
|
||||||
// pass = "your-password"
|
// password = "3af25537b4524"
|
||||||
// serverIP = "192.168.1.119"
|
// serverIP = "192.168.1.119"
|
||||||
// debug = true
|
// debug = true
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
password string
|
||||||
serverIP = ""
|
serverIP = ""
|
||||||
debug = false
|
debug = false
|
||||||
)
|
)
|
||||||
@@ -43,16 +41,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
rtl, err := setupRTL8720DN()
|
||||||
adaptor.Debug(debug)
|
if err != nil {
|
||||||
adaptor.Configure()
|
return err
|
||||||
|
}
|
||||||
|
net.UseDriver(rtl)
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
ip, subnet, gateway, err := rtl.GetIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/rtl8720dn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
uart UARTx
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleInterrupt(interrupt.Interrupt) {
|
||||||
|
// should reset IRQ
|
||||||
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
|
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||||
|
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
machine.RTL8720D_CHIP_PU.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.RTL8720D_CHIP_PU.High()
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
uart = UARTx{
|
||||||
|
UART: &machine.UART{
|
||||||
|
Buffer: machine.NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||||
|
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||||
|
|
||||||
|
rtl := rtl8720dn.New(uart)
|
||||||
|
rtl.Debug(debug)
|
||||||
|
|
||||||
|
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UARTx struct {
|
||||||
|
*machine.UART
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||||
|
if u.Buffered() == 0 {
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return u.UART.Read(p)
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
|
||||||
|
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -16,17 +14,17 @@ import (
|
|||||||
// You can override the setting with the init() in another source code.
|
// You can override the setting with the init() in another source code.
|
||||||
// func init() {
|
// func init() {
|
||||||
// ssid = "your-ssid"
|
// ssid = "your-ssid"
|
||||||
// pass = "your-password"
|
// password = "your-password"
|
||||||
// debug = true
|
// debug = true
|
||||||
// url = "https://www.example.com"
|
// url = "https://www.example.com"
|
||||||
// test_root_ca = "..."
|
// test_root_ca = "..."
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ssid string
|
ssid string
|
||||||
pass string
|
password string
|
||||||
url string = "https://www.example.com"
|
url string = "https://www.example.com"
|
||||||
debug = false
|
debug = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set the test_root_ca created by the following command
|
// Set the test_root_ca created by the following command
|
||||||
@@ -59,6 +57,7 @@ var buf [0x1000]byte
|
|||||||
|
|
||||||
var lastRequestTime time.Time
|
var lastRequestTime time.Time
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
|
var adaptor *rtl8720dn.RTL8720DN
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := run()
|
err := run()
|
||||||
@@ -69,19 +68,20 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() error {
|
func run() error {
|
||||||
adaptor := rtl8720dn.New(machine.UART3, machine.PB24, machine.PC24, machine.RTL8720D_CHIP_PU)
|
rtl, err := setupRTL8720DN()
|
||||||
adaptor.Debug(debug)
|
if err != nil {
|
||||||
adaptor.Configure()
|
return err
|
||||||
|
}
|
||||||
adaptor.SetRootCA(&test_root_ca)
|
rtl.SetRootCA(&test_root_ca)
|
||||||
|
net.UseDriver(rtl)
|
||||||
http.SetBuf(buf[:])
|
http.SetBuf(buf[:])
|
||||||
|
|
||||||
err := adaptor.ConnectToAccessPoint(ssid, pass, 10*time.Second)
|
err = rtl.ConnectToAccessPoint(ssid, password, 10*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, subnet, gateway, err := adaptor.GetIP()
|
ip, subnet, gateway, err := rtl.GetIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//go:build wioterminal
|
||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/rtl8720dn"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
uart UARTx
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleInterrupt(interrupt.Interrupt) {
|
||||||
|
// should reset IRQ
|
||||||
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
|
uart.Bus.INTFLAG.SetBits(sam.SERCOM_USART_INT_INTFLAG_RXC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRTL8720DN() (*rtl8720dn.RTL8720DN, error) {
|
||||||
|
machine.RTL8720D_CHIP_PU.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
machine.RTL8720D_CHIP_PU.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.RTL8720D_CHIP_PU.High()
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
waitSerial()
|
||||||
|
|
||||||
|
uart = UARTx{
|
||||||
|
UART: &machine.UART{
|
||||||
|
Buffer: machine.NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uart.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, handleInterrupt)
|
||||||
|
uart.Configure(machine.UARTConfig{TX: machine.PB24, RX: machine.PC24, BaudRate: 614400})
|
||||||
|
|
||||||
|
rtl := rtl8720dn.New(uart)
|
||||||
|
rtl.Debug(debug)
|
||||||
|
|
||||||
|
_, err := rtl.Rpc_tcpip_adapter_init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for user to open serial console
|
||||||
|
func waitSerial() {
|
||||||
|
for !machine.Serial.DTR() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UARTx struct {
|
||||||
|
*machine.UART
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UARTx) Read(p []byte) (n int, err error) {
|
||||||
|
if u.Buffered() == 0 {
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return u.UART.Read(p)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user