Compare commits

...

72 Commits

Author SHA1 Message Date
deadprogram 1cbf1a6f3d release: v0.17.1
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:38:55 +02:00
deadprogram 001bdb43ba release: v0.17.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:20:03 +02:00
deadprogram f7ae6fac6d modules: switch to use tinygo-org version of tinyfs package
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-07-01 20:00:52 +02:00
sago35 a575b2a4ed Update comments 2021-06-27 16:33:32 +02:00
sago35 0bc3702dd0 rtl8720dn: add support for rtl8720dn 2021-06-27 16:33:32 +02:00
sago35 b53a8a17e7 ili9341: add standard SPI driver 2021-06-27 08:08:27 +02:00
sago35 5e117c162c ws2812: rename the pin to ws2812 2021-06-26 14:04:13 +02:00
sago35 24dfd8795a sdcard: add write functionality to examples/sdcard/tinyfs 2021-06-23 18:34:26 +02:00
sago35 a748451cab Merge pull request #275 from tinygo-org/ws2812-add-nrf52833
ws2812: add tag for nrf52833
2021-06-23 20:33:53 +09:00
deadprogram a811483fd4 ws2812: add tag for nrf52833
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-06-20 11:11:08 +02:00
Daniel Bridges 7b565e8cb0 Disable interrupts before sending ws2812 data 2021-06-17 09:24:49 +02:00
sago35 5645eb3f91 ws2812: add support for qtpy and atsame5x 2021-06-01 21:09:08 +02:00
sago35 6b914f7af7 sdcard: add support for fatfs 2021-05-31 17:26:21 +02:00
Ayke van Laethem 5a02fe068b apa102: use 4-byte buffer to improve speed
Instead of sending the APA102 data byte by byte, it's more efficient to
send multiple bytes at once (especially when the SPI peripheral uses
DMA). This requires the apa102.Device object to be a pointer receiver to
avoid excessive heap allocations.

This commit also just happens to work around a hardware bug on the
nrf52832:
https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52832_Rev2%2FERR%2FnRF52832%2FRev2%2Flatest%2Fanomaly_832_58.html&anchor=anomaly_832_58
2021-05-30 22:39:50 +02:00
Ayke van Laethem 5ecefde991 bmi160: avoid heap allocations
The nrf52 series chips use DMA for writing and reading SPI data, which
means that the transmit and receive buffer slices escape. This can
easily be solved by pre-allocating the buffer in the BMI160 driver and
reusing this buffer every time.
2021-05-30 22:11:27 +02:00
Yurii Soldak 9adbde99a2 wifinina: avoid fmt package 2021-05-28 18:09:29 +02:00
Yurii Soldak a09ec31e7a Fix RSSI command for WiFiNINA
+ Print current SSID
+ Wait for correct time before printing it out
+ Cleanup
2021-05-27 08:00:13 +02:00
sago35 d07ad40373 sdcard: add support for spi sdcard driver 2021-05-23 11:22:42 +02:00
sago35 aa17ffd1cb uart: use machine.Serial as the default output 2021-05-14 13:26:59 +02:00
deadprogram ce03bebc34 release: prepare for release v0.16.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 15:51:16 +02:00
deadprogram dfd652ca1f docs: up to 65 devices
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 15:30:41 +02:00
Ayke van Laethem c765ef3970 servo: add driver using PWM
This PR adds support for controlling servos. For example, on the Arduino
Uno it should be able to control up to 6 servos jitter-free when using
all available PWM pins.

I haven't added support for setting a position in degrees, mainly
because this varies by servo and it's probably necessary to configure
the bounds in some way. Therefore, I added just SetMicroseconds. This
makes the API possible to use and leaves the possibility of adding a
SetPosition in the future.
2021-05-12 15:29:18 +02:00
akif999 428db3cd12 mcp2515: add support for mcp2515 CAN device 2021-05-12 13:37:02 +02:00
deadprogram d7f619ca21 docs: update count of supported devices to 63
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:24:16 +02:00
Kenneth Bell d1ace44754 aht20: add device 2021-05-12 09:21:52 +02:00
Kenneth Bell 6b58fdc95a tester: add a mock for command-oriented i2c devices 2021-05-12 09:21:52 +02:00
Yurii Soldak bd2530abee Example of ssd1306 with 128x64 display over I2C 2021-05-12 09:14:51 +02:00
Yurii Soldak 3bcde1485c Enable reset screen for SSD1306 via I2C 2021-05-12 09:14:51 +02:00
deadprogram 351700e48d wifinina: add information about Adafruit boards with ESP32 wifi coprocessors, and modify examples to remove code that was both not being used, and also prevented many Adafruit boards from being able to be targeted by the examples
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:13:09 +02:00
deadprogram cbcb62af01 wifinina: update docs to simplify the nina-fw update process
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-12 09:13:09 +02:00
Yurii Soldak 19bb773e5b fix println + cleanup 2021-05-12 09:11:18 +02:00
Yurii Soldak 69cc0b22c4 Example that connects to AP and prints ip addresses, time and mac 2021-05-12 09:11:18 +02:00
Kenneth Bell 2a48b5c25d wifinina: fix getMACAddress and getTime
Tested against Adafruit AirLift (compatibile variant of wifinina)
2021-05-12 09:11:18 +02:00
deadprogram e6a822f68b docs: up to 62 devices for the README
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-11 18:27:00 +02:00
Kenneth Bell f65bce6d36 ina260: add new i2c device 2021-05-11 11:13:29 +02:00
Yurii Soldak 67b8a341a6 Make TLS work over WiFiNINA
Verified on Arduino Nano33 IoT and nina fw v1.4.5
2021-05-11 10:59:52 +02:00
Tobias Theel b869d27170 remove debug flag and remove unnecessary padding call
(cherry picked from commit 9d3e63232b)
2021-05-11 10:59:52 +02:00
Tobias Theel 107932a201 fix padding and implement missing functions
(cherry picked from commit 0aa0bde76e)
2021-05-11 10:59:52 +02:00
sago35 d2db0c28e2 doc: update README.md 2021-05-10 14:42:12 +02:00
sago35 761bcfc4db pcf8563: add support for pcf8563 real time clock 2021-05-10 14:35:01 +02:00
Kenneth Bell 91dadd5535 Add 16-bit register mock device 2021-05-10 12:15:52 +02:00
Alan Wang f7dc106fc8 tm1637: add support for tm1637 7-segment LED 2021-05-07 18:05:44 +02:00
Ayke van Laethem df343190c2 tone: add package for producing tones using the PWM interface 2021-05-05 14:49:23 +02:00
deadprogram 6bc466f79b pwm: update drivers with PWM to use new interface
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-05-05 14:44:24 +02:00
Daniel M. Lambea 23776bf906 flash/drivers: fix EraseBlocks method which is erasing sectors instead 2021-04-05 14:44:56 +02:00
Ayke van Laethem e77e9249cd all: use interfaces for UART objects
This makes it possible to replace UART objects with dummy
implementations, for example. Or allows changing the `machine.UART` type
to `*machine.UART` without breaking compatibility.
2021-04-02 17:31:28 +02:00
Quentin Smith 1345bc2161 p1am: documentation and example program 2021-04-02 17:23:38 +02:00
Quentin Smith ab795cc186 p1am: support the P1AM-100 hardware watchdog 2021-04-02 17:23:38 +02:00
Quentin Smith 36213a1cdc p1am: fetch base controller version number 2021-04-02 17:23:38 +02:00
Quentin Smith 963c903d71 p1am: support discrete inputs and outputs 2021-04-02 17:23:38 +02:00
Quentin Smith 2cec480fb8 p1am: initial driver for the base controller
All the driver can currently do is initialize the base controller and enumerate
the connected modules.
2021-04-02 17:23:38 +02:00
Quentin Smith 68da7f437b p1am: import constants from P1AM Arduino library 2021-04-02 17:23:38 +02:00
sago35 d0632fccfa add .vscode/ to .gitignore 2021-03-28 12:23:16 +02:00
sago35 2c0a74df4d delete .vscode/settings.json 2021-03-28 18:50:51 +09:00
sago35 c6228a0677 Merge remote-tracking branch 'origin/release' into dev 2021-03-28 18:44:35 +09:00
deadprogram 33ec7fc98f examples: correct go fmt error
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:28:41 +01:00
deadprogram 75c15d5d0b build: correct error in Makefile from invalid merge
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:28:12 +01:00
Nerzal e1deb45aac add 4x4 keypad driver (#226)
add 4x4 keypad driver
2021-03-26 18:19:40 +01:00
deadprogram d1cafbc2b2 docs: add missing new drivers added since last release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:12:02 +01:00
Ayke van Laethem 0b6bfda8cf all: do not take the pointer of an I2C object
This is in preparation of PR
https://github.com/tinygo-org/tinygo/pull/1693, which makes machine.I2C0
and similar objects of pointer type, so they can be freely passed
around.
2021-03-26 18:10:39 +01:00
Nerzal 84408279de add 4x4 keypad driver (#226)
add 4x4 keypad driver
2021-03-26 18:10:39 +01:00
deadprogram de1e6a626a Prepare for drivers release 0.15.1 to get tag correct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:10:39 +01:00
deadprogram 7531c9d334 Prepare for drivers release 0.15.0
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:10:39 +01:00
pleomaxx3002 ee44900c25 DHTXX driver (#235)
dhtXX: add new driver for dht thermometer
2021-03-26 18:09:48 +01:00
deadprogram b9a70aeb6f docs: add missing new drivers added since last release
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:05:00 +01:00
deadprogram cad0a320b7 docs: update year in license to 2021
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
Nick Craig-Wood a53a39922b hd44780: add a mode to work with boards where the RW pin is grounded
On some HD44780 boards (eg the Keyestudio LCD1602 expansion shield),
the RW pin isn't brought out and is permanently grounded.

This means that the board can't be read from, and in particular the
busy status can't be read.

This patch adapts the package to work with boards like these.

To signal this to the package, set the RW pin to machine.NoPin.

The package will then disallow all reading and use adjustable timing
based writing. The timing can be adjusted the configuration.
2021-03-26 18:03:15 +01:00
deadprogram 41d6a4c3fa adc: update drivers with ADC to use new config struct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
deadprogram 60ba0e3b30 st7789: correct errors on various godoc comments
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
deadprogram 2b5f43029c st7789: add scrolling functions to match st7735
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-26 18:03:15 +01:00
Tobias Theel a771641339 max7219: add driver support 2021-03-26 18:03:15 +01:00
deadprogram 5741ceb9d1 Prepare for drivers release 0.15.1 to get tag correct
Signed-off-by: deadprogram <ron@hybridgroup.com>
2021-03-06 13:51:27 +01:00
136 changed files with 19763 additions and 1679 deletions
+1
View File
@@ -1 +1,2 @@
build
.vscode/
+68
View File
@@ -1,3 +1,71 @@
0.17.1
---
- To correct an error in the release process. Same as 0.17.0.
0.17.0
---
- **new devices**
- rtl8720dn: add support for rtl8720dn
- sdcard: add support for spi sdcard driver, along with fatfs
- **enhancements**
- apa102: use 4-byte buffer to improve speed
- bmi160: avoid heap allocations
- ili9341: add standard SPI driver
- wifinina
- avoid fmt package
- Fix RSSI command for WiFiNINA + Print current SSID + Wait for correct time before printing it out + Cleanup
- ws2812
- rename the pin to ws2812
- add tag for nrf52833
- Disable interrupts before sending ws2812 data
- add support for qtpy and atsame5x
- **core**
- modules: switch to use tinygo-org version of tinyfs package
- all: use machine.Serial as the default output
0.16.0
---
- **new devices**
- aht20: add device
- ina260: add new i2c device
- keypad: add 4x4 keypad driver (#226)
- max7219: add driver support
- mcp2515: add support for mcp2515 CAN device
- p1am: support the P1AM-100 hardware watchdog
- pcf8563: add support for pcf8563 real time clock
- servo: add driver using PWM
- tm1637: add support for tm1637 7-segment LED
- tone: add package for producing tones using the PWM interface
- **enhancements**
- pwm: update drivers with PWM to use new interface
- wifinina: Make TLS work over WiFiNINA Verified on Arduino Nano33 IoT and nina fw v1.4.5
- ssd1306: Enable reset screen for SSD1306 via I2C
- st7789: add scrolling functions to match st7735
- **bugfixes**
- wifinina:
- fix getMACAddress and getTime
- fix println + cleanup
- remove debug flag and remove unnecessary padding call
- fix padding and implement missing functions
- flash: fix EraseBlocks method which is erasing sectors instead
- **core**
- all: use interfaces for UART objects
- all: do not take the pointer of an I2C object
- adc: update drivers with ADC to use new config struct
- **testing**
- tester:
- add a mock for command-oriented i2c devices
- add 16-bit register mock device
- **docs**
- ssd1306: example of ssd1306 with 128x64 display over I2C
- wifinina:
- add information about Adafruit boards with ESP32 wifi coprocessors, and modify examples to remove code that was both not being used, and also prevented many Adafruit boards from being able to be targeted by the examples
- update docs to simplify the nina-fw update process
- example that connects to AP and prints ip addresses, time and mac
- p1am: documentation and example program
- add missing new drivers added since last release
0.15.0
---
- **new devices**
+34 -1
View File
@@ -89,16 +89,22 @@ smoke-test:
@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=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
@@ -115,6 +121,10 @@ smoke-test:
@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
@@ -165,13 +175,36 @@ endif
@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
DRIVERS = $(wildcard */)
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
pcf8563 mcp2515 servo sdcard rtl8720dn
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
unit-test:
+12 -1
View File
@@ -52,12 +52,13 @@ func main() {
## Currently supported devices
The following 56 devices are supported.
The following 67 devices are supported.
| 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 |
| [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C |
@@ -80,24 +81,33 @@ The following 56 devices are supported.
| [HD44780 LCD controller](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | GPIO/I2C |
| [HUB75 RGB led matrix](https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf) | SPI |
| [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 |
| [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 |
| [LSM6DS3 accelerometer](https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) | I2C |
| [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 |
| [MCP23017 port expander](https://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf) | I2C |
| [MCP3008 analog to digital converter (ADC)](http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf) | SPI |
| [MCP2515 Stand-Alone CAN Controller with SPI Interface](https://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Family-Data-Sheet-DS20001801K.pdf) | SPI |
| [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 |
| [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/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.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 |
@@ -105,6 +115,7 @@ The following 56 devices are supported.
| [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 |
| [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 |
+108
View File
@@ -0,0 +1,108 @@
package aht20
import (
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to an AHT20 device.
type Device struct {
bus drivers.I2C
Address uint16
humidity uint32
temp uint32
}
// New creates a new AHT20 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
}
}
// Configure the device
func (d *Device) Configure() {
// Check initialization state
status := d.Status()
if status&0x08 == 1 {
// Device is initialized
return
}
// Force initialization
d.bus.Tx(d.Address, []byte{CMD_INITIALIZE, 0x08, 0x00}, nil)
time.Sleep(10 * time.Millisecond)
}
// Reset the device
func (d *Device) Reset() {
d.bus.Tx(d.Address, []byte{CMD_SOFTRESET}, nil)
}
// Status of the device
func (d *Device) Status() byte {
data := []byte{0}
d.bus.Tx(d.Address, []byte{CMD_STATUS}, data)
return data[0]
}
// Read the temperature and humidity
//
// The actual temperature and humidity are stored
// and can be accessed using `Temp` and `Humidity`.
func (d *Device) Read() error {
d.bus.Tx(d.Address, []byte{CMD_TRIGGER, 0x33, 0x00}, nil)
data := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
for retry := 0; retry < 3; retry++ {
time.Sleep(80 * time.Millisecond)
err := d.bus.Tx(d.Address, nil, data)
if err != nil {
return err
}
// If measurement complete, store values
if data[0]&0x04 != 0 && data[0]&0x80 == 0 {
d.humidity = uint32(data[1])<<12 | uint32(data[2])<<4 | uint32(data[3])>>4
d.temp = (uint32(data[3])&0xF)<<16 | uint32(data[4])<<8 | uint32(data[5])
return nil
}
}
return ErrTimeout
}
func (d *Device) RawHumidity() uint32 {
return d.humidity
}
func (d *Device) RawTemp() uint32 {
return d.temp
}
func (d *Device) RelHumidity() float32 {
return (float32(d.humidity) * 100) / 0x100000
}
func (d *Device) DeciRelHumidity() int32 {
return (int32(d.humidity) * 1000) / 0x100000
}
// Temperature in degrees celsius
func (d *Device) Celsius() float32 {
return (float32(d.temp*200.0) / 0x100000) - 50
}
// Temperature in mutiples of one tenth of a degree celsius
//
// Using this method avoids floating point calculations.
func (d *Device) DeciCelsius() int32 {
return ((int32(d.temp) * 2000) / 0x100000) - 500
}
+74
View File
@@ -0,0 +1,74 @@
package aht20
import (
"testing"
qt "github.com/frankban/quicktest"
"tinygo.org/x/drivers/tester"
)
func TestDefaultI2CAddress(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
c.Assert(uint8(dev.Address), qt.Equals, uint8(Address))
}
func TestInitialization(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fdev := tester.NewI2CDeviceCmd(c, Address)
fdev.Commands = defaultCommands()
bus.AddDevice(fdev)
// Set status to uninitialized to force initialization
fdev.Commands[CMD_STATUS].Response[0] = 0x0C
dev := New(bus)
dev.Configure()
// Check initialization command invoked
c.Assert(fdev.Commands[CMD_INITIALIZE].Invocations > 0, qt.Equals, true)
}
func TestRead(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fdev := tester.NewI2CDeviceCmd(c, Address)
fdev.Commands = defaultCommands()
bus.AddDevice(fdev)
dev := New(bus)
dev.Read()
// Should be 25deg (250 decidegrees)
c.Assert(dev.DeciCelsius(), qt.Equals, int32(250))
// Should be 36.3% (363 decipercent)
c.Assert(dev.DeciRelHumidity(), qt.Equals, int32(363))
}
func defaultCommands() map[uint8]*tester.Cmd {
return map[uint8]*tester.Cmd{
CMD_INITIALIZE: {
Command: []byte{0xBE},
Mask: []byte{0xFF},
Response: []byte{},
},
CMD_TRIGGER: {
Command: []byte{0xAC, 0x33, 0x00},
Mask: []byte{0xFF, 0xFF, 0xFF},
Response: []byte{0x1C, 0x5D, 0x10, 0x66, 0x01, 0xD2, 0x93},
},
CMD_SOFTRESET: {
Command: []byte{0xBA},
Mask: []byte{0xFF},
Response: []byte{},
},
CMD_STATUS: {
Command: []byte{0x71},
Mask: []byte{0xFF},
Response: []byte{0x1C},
},
}
}
+20
View File
@@ -0,0 +1,20 @@
package aht20
import "errors"
const (
Address = 0x38
CMD_INITIALIZE = 0xBE
CMD_STATUS = 0x71
CMD_TRIGGER = 0xAC
CMD_SOFTRESET = 0xBA
STATUS_BUSY = 0x80
STATUS_CALIBRATED = 0x08
)
var (
ErrBusy = errors.New("device busy")
ErrTimeout = errors.New("timeout")
)
+19 -17
View File
@@ -27,44 +27,46 @@ var startFrame = []byte{0x00, 0x00, 0x00, 0x00}
type Device struct {
bus drivers.SPI
Order int
buf [4]byte
}
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI) Device {
return Device{bus: b, Order: BGR}
func New(b drivers.SPI) *Device {
return &Device{bus: b, Order: BGR}
}
// NewSoftwareSPI returns a new APA102 driver that will use a software based
// implementation of the SPI protocol.
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) Device {
func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device {
return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay})
}
// WriteColors writes the given RGBA color slice out using the APA102 protocol.
// The A value (Alpha channel) is used for brightness, set to 0xff (255) for maximum.
func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
func (d *Device) WriteColors(cs []color.RGBA) (n int, err error) {
d.startFrame()
// write data
for _, c := range cs {
// brightness is scaled to 5 bit value
d.bus.Transfer(0xe0 | (c.A >> 3))
d.buf[0] = 0xe0 | (c.A >> 3)
// set the colors
switch d.Order {
case BRG:
d.bus.Transfer(c.B)
d.bus.Transfer(c.R)
d.bus.Transfer(c.G)
d.buf[1] = c.B
d.buf[2] = c.R
d.buf[3] = c.G
case GRB:
d.bus.Transfer(c.G)
d.bus.Transfer(c.R)
d.bus.Transfer(c.B)
d.buf[1] = c.G
d.buf[2] = c.R
d.buf[3] = c.B
case BGR:
d.bus.Transfer(c.B)
d.bus.Transfer(c.G)
d.bus.Transfer(c.R)
d.buf[1] = c.B
d.buf[2] = c.G
d.buf[3] = c.R
}
d.bus.Tx(d.buf[:], nil)
}
d.endFrame(len(cs))
@@ -73,7 +75,7 @@ func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
}
// Write the raw bytes using the APA102 protocol.
func (d Device) Write(buf []byte) (n int, err error) {
func (d *Device) Write(buf []byte) (n int, err error) {
d.startFrame()
d.bus.Tx(buf, nil)
d.endFrame(len(buf) / 4)
@@ -82,14 +84,14 @@ func (d Device) Write(buf []byte) (n int, err error) {
}
// startFrame sends the start bytes for a strand of LEDs.
func (d Device) startFrame() {
func (d *Device) startFrame() {
d.bus.Tx(startFrame, nil)
}
// endFrame sends the end frame marker with one extra bit per LED so
// long strands of LEDs receive the necessary termination for updates.
// See https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/
func (d Device) endFrame(count int) {
func (d *Device) endFrame(count int) {
for i := 0; i < count/16; i++ {
d.bus.Transfer(0xff)
}
+24 -5
View File
@@ -13,6 +13,8 @@ type DeviceSPI struct {
// Chip select pin
CSB machine.Pin
buf [7]byte
// SPI bus (requires chip select to be usable).
Bus drivers.SPI
}
@@ -80,7 +82,10 @@ func (d *DeviceSPI) Reset() error {
// ReadTemperature returns the temperature in celsius milli degrees (°C/1000).
func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
data := []byte{0x80 | reg_TEMPERATURE_0, 0, 0}
data := d.buf[:3]
data[0] = 0x80 | reg_TEMPERATURE_0
data[1] = 0
data[2] = 0
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -113,7 +118,11 @@ func (d *DeviceSPI) ReadTemperature() (temperature int32, err error) {
// and the sensor is not moving the returned value will be around 1000000 or
// -1000000.
func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
data := []byte{0x80 | reg_ACC_XL, 0, 0, 0, 0, 0, 0}
data := d.buf[:7]
data[0] = 0x80 | reg_ACC_XL
for i := 1; i < len(data); i++ {
data[i] = 0
}
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -139,7 +148,11 @@ func (d *DeviceSPI) ReadAcceleration() (x int32, y int32, z int32, err error) {
// rotation along one axis and while doing so integrate all values over time,
// you would get a value close to 360000000.
func (d *DeviceSPI) ReadRotation() (x int32, y int32, z int32, err error) {
data := []byte{0x80 | reg_GYR_XL, 0, 0, 0, 0, 0, 0}
data := d.buf[:7]
data[0] = 0x80 | reg_GYR_XL
for i := 1; i < len(data); i++ {
data[i] = 0
}
d.CSB.Low()
err = d.Bus.Tx(data, data)
d.CSB.High()
@@ -185,7 +198,9 @@ func (d *DeviceSPI) readRegister(address uint8) uint8 {
// I don't know why but it appears necessary to sleep for a bit here.
time.Sleep(time.Millisecond)
data := []byte{0x80 | address, 0}
data := d.buf[:2]
data[0] = 0x80 | address
data[1] = 0
d.CSB.Low()
d.Bus.Tx(data, data)
d.CSB.High()
@@ -198,7 +213,11 @@ func (d *DeviceSPI) writeRegister(address, data uint8) {
// I don't know why but it appears necessary to sleep for a bit here.
time.Sleep(time.Millisecond)
buf := d.buf[:2]
buf[0] = address
buf[1] = data
d.CSB.Low()
d.Bus.Tx([]byte{address, data}, []byte{0, 0})
d.Bus.Tx(buf, buf)
d.CSB.High()
}
+3 -3
View File
@@ -20,17 +20,17 @@ package espat // import "tinygo.org/x/drivers/espat"
import (
"errors"
"machine"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/net"
)
// Device wraps UART connection to the ESP8266/ESP32.
type Device struct {
bus machine.UART
bus drivers.UART
// command responses that come back from the ESP8266/ESP32
response []byte
@@ -43,7 +43,7 @@ type Device struct {
var ActiveDevice *Device
// New returns a new espat driver. Pass in a fully configured UART bus.
func New(b machine.UART) *Device {
func New(b drivers.UART) *Device {
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
}
+1 -1
View File
@@ -9,7 +9,7 @@ import (
)
var (
i2c = &machine.I2C0
i2c = machine.I2C0
sensor = adt7410.New(i2c)
)
+55
View File
@@ -0,0 +1,55 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/aht20"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
dev := aht20.New(machine.I2C0)
dev.Configure()
dev.Reset()
for {
time.Sleep(500 * time.Millisecond)
err := dev.Read()
if err != nil {
println("Error", err)
continue
}
println("temp ", fmtD(dev.DeciCelsius(), 3, 1), "C")
println("humidity", fmtD(dev.DeciRelHumidity(), 3, 1), "%")
}
}
func fmtD(val int32, i int, f int) string {
result := make([]byte, i+f+1)
neg := false
if val < 0 {
val = -val
neg = true
}
for p := len(result) - 1; p >= 0; p-- {
result[p] = byte(int32('0') + (val % 10))
val = val / 10
if p == i+1 && p > 0 {
p--
result[p] = '.'
}
}
if neg {
result[0] = '-'
}
return string(result)
}
+15 -8
View File
@@ -13,9 +13,9 @@ import (
)
var (
apa apa102.Device
apa *apa102.Device
led = machine.PWM{machine.LED}
pwm = machine.TCC0
leds = make([]color.RGBA, 1)
wheel = &Wheel{Brightness: 0x10}
)
@@ -27,12 +27,19 @@ func init() {
apa = apa102.NewSoftwareSPI(machine.PA00, machine.PA01, 1)
// Configure the regular on-board LED for PWM fading
machine.InitPWM()
led.Configure()
err := pwm.Configure(machine.PWMConfig{})
if err != nil {
println("failed to configure PWM")
return
}
}
func main() {
channelLED, err := pwm.Channel(machine.LED)
if err != nil {
println("failed to configure LED PWM channel")
return
}
// We'll fade the on-board LED in a goroutine to show/ensure that the APA102
// works fine with the scheduler enabled. Comment this out to test this code
@@ -43,11 +50,11 @@ func main() {
brightening = !brightening
continue
}
var brightness uint16 = uint16(i) << 8
var brightness uint32 = uint32(i)
if !brightening {
brightness = 0xFFFF - brightness
brightness = 256 - brightness
}
led.Set(brightness)
pwm.Set(channelLED, pwm.Top()*brightness/256)
time.Sleep(5 * time.Millisecond)
}
}()
+1 -1
View File
@@ -30,7 +30,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.UART0
console = machine.Serial
adaptor *espat.Device
)
+1 -1
View File
@@ -36,7 +36,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.UART0
console = machine.Serial
adaptor *espat.Device
topic = "tinygo"
+1 -1
View File
@@ -37,7 +37,7 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.UART0
console = machine.Serial
adaptor *espat.Device
cl mqtt.Client
+1 -1
View File
@@ -20,7 +20,7 @@ var (
input [consoleBufLen]byte
store [storageBufLen]byte
console = machine.UART0
console = machine.Serial
dev *flash.Device
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS I2C Example")
machine.I2C0.Configure(machine.I2CConfig{})
ublox := gps.NewI2C(&machine.I2C0)
ublox := gps.NewI2C(machine.I2C0)
parser := gps.NewParser()
var fix gps.Fix
for {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
func main() {
println("GPS UART Example")
machine.UART1.Configure(machine.UARTConfig{BaudRate: 9600})
ublox := gps.NewUART(&machine.UART1)
ublox := gps.NewUART(machine.UART1)
parser := gps.NewParser()
var fix gps.Fix
for {
File diff suppressed because it is too large Load Diff
+9 -6
View File
@@ -25,7 +25,7 @@ const (
)
var (
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8)]uint16{}
frameBuffer = [(graphics.BALLHEIGHT + 8) * (graphics.BALLWIDTH + 8) * 2]uint8{}
startTime int64
frame int64
@@ -179,7 +179,8 @@ func main() {
c = BGCOLOR
}
}
frameBuffer[y*int(width)+x] = c
frameBuffer[(y*int(width)+x)*2] = byte(c >> 8)
frameBuffer[(y*int(width)+x)*2+1] = byte(c)
bx1++ // Increment bitmap position counters (X axis)
bgx1++
}
@@ -190,7 +191,7 @@ func main() {
bgy++
}
display.DrawRGBBitmap(minx, miny, frameBuffer[:width*height], width, height)
display.DrawRGBBitmap8(minx, miny, frameBuffer[:width*height*2], width, height)
// Show approximate frame rate
frame++
@@ -215,11 +216,13 @@ func DrawBackground() {
b = graphics.Background[j*byteWidth+k/8]
}
if b&0x80 == 0 {
frameBuffer[k] = BGCOLOR
frameBuffer[2*k] = byte(BGCOLOR >> 8)
frameBuffer[2*k+1] = byte(BGCOLOR & 0xFF)
} else {
frameBuffer[k] = GRIDCOLOR
frameBuffer[2*k] = byte(GRIDCOLOR >> 8)
frameBuffer[2*k+1] = byte(GRIDCOLOR & 0xFF)
}
}
display.DrawRGBBitmap(0, j, frameBuffer[0:w], w, 1)
display.DrawRGBBitmap8(0, j, frameBuffer[0:w*2], w, 1)
}
}
+63
View File
@@ -0,0 +1,63 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/ina260"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{})
dev := ina260.New(machine.I2C0)
dev.Configure(ina260.Config{
AverageMode: ina260.AVGMODE_16,
VoltConvTime: ina260.CONVTIME_140USEC,
CurrentConvTime: ina260.CONVTIME_140USEC,
Mode: ina260.MODE_CONTINUOUS | ina260.MODE_VOLTAGE | ina260.MODE_CURRENT,
})
if dev.Connected() {
println("INA260 detected")
} else {
println("INA260 NOT detected")
return
}
for {
microvolts := dev.Voltage()
microamps := dev.Current()
microwatts := dev.Power()
println(fmtD(microvolts, 4, 3), "mV,", fmtD(microamps, 4, 3), "mA,", fmtD(microwatts, 4, 3), "mW")
time.Sleep(10 * time.Millisecond)
}
}
func fmtD(val int32, i int, f int) string {
result := make([]byte, i+f+1)
neg := false
if val < 0 {
val = -val
neg = true
}
for p := len(result) - 1; p >= 0; p-- {
result[p] = byte(int32('0') + (val % 10))
val = val / 10
if p == i+1 && p > 0 {
p--
result[p] = '.'
}
}
if neg {
result[0] = '-'
}
return string(result)
}
+38
View File
@@ -0,0 +1,38 @@
package main
import (
"machine"
"tinygo.org/x/drivers/keypad4x4"
)
func main() {
mapping := map[uint8]string{
1: "1",
2: "2",
3: "3",
4: "A",
5: "4",
6: "5",
7: "6",
8: "B",
9: "7",
10: "8",
11: "9",
12: "C",
13: "*",
14: "0",
15: "#",
16: "D",
}
keypadDevice := keypad4x4.NewDevice(machine.D2, machine.D3, machine.D4, machine.D5, machine.D6, machine.D7, machine.D8, machine.D9)
keypadDevice.Configure()
for {
key := keypadDevice.GetKey()
if key != keypad4x4.NoKeyPressed {
println("Button: ", mapping[key])
}
}
}
+18 -6
View File
@@ -8,19 +8,31 @@ import (
)
const (
maxSpeed = 30000
maxSpeed = 100
)
func main() {
machine.InitPWM()
err := machine.TCC0.Configure(machine.PWMConfig{
Period: 16384e3, // 16.384ms
})
if err != nil {
println(err.Error())
return
}
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, machine.PWM{machine.D12})
spc, err := machine.TCC0.Channel(machine.D12)
if err != nil {
println(err.Error())
return
}
wheel := l293x.NewWithSpeed(machine.D10, machine.D11, spc, machine.TCC0)
wheel.Configure()
for i := 0; i <= 10; i++ {
println("Forward")
var i uint16
for i = 0; i < maxSpeed; i += 1000 {
var i uint32
for i = 0; i < maxSpeed; i += 10 {
wheel.Forward(i)
time.Sleep(time.Millisecond * 100)
}
@@ -30,7 +42,7 @@ func main() {
time.Sleep(time.Millisecond * 1000)
println("Backward")
for i = 0; i < maxSpeed; i += 1000 {
for i = 0; i < maxSpeed; i += 10 {
wheel.Backward(i)
time.Sleep(time.Millisecond * 100)
}
+25 -6
View File
@@ -8,19 +8,38 @@ import (
)
const (
maxSpeed = 30000
maxSpeed = 100
)
func main() {
machine.InitPWM()
machine.D11.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.D12.Configure(machine.PinConfig{Mode: machine.PinOutput})
wheel := l9110x.NewWithSpeed(machine.PWM{machine.D11}, machine.PWM{machine.D12})
err := machine.TCC0.Configure(machine.PWMConfig{})
if err != nil {
println(err.Error())
return
}
ca, err := machine.TCC0.Channel(machine.D11)
if err != nil {
println(err.Error())
return
}
cb, err := machine.TCC0.Channel(machine.D12)
if err != nil {
println(err.Error())
return
}
wheel := l9110x.NewWithSpeed(ca, cb, machine.TCC0)
wheel.Configure()
for i := 0; i <= 10; i++ {
println("Forward")
var i uint16
for i = 0; i < maxSpeed; i += 1000 {
var i uint32
for i = 0; i < maxSpeed; i += 10 {
wheel.Forward(i)
time.Sleep(time.Millisecond * 100)
}
@@ -30,7 +49,7 @@ func main() {
time.Sleep(time.Millisecond * 1000)
println("Backward")
for i = 0; i < maxSpeed; i += 1000 {
for i = 0; i < maxSpeed; i += 10 {
wheel.Backward(i)
time.Sleep(time.Millisecond * 100)
}
+135
View File
@@ -0,0 +1,135 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/max72xx"
)
// example for a 4 digit 7 segment display
func main() {
// Pins for Arduino Nano 33 IOT
err := machine.SPI0.Configure(machine.SPIConfig{
SDO: machine.D11, // default SDO pin
SCK: machine.D13, // default sck pin
LSBFirst: false,
Frequency: 10000000,
})
if err != nil {
println(err.Error())
}
driver := max72xx.NewDevice(machine.SPI0, machine.D6)
driver.Configure()
digitNumber := 4
driver.StopDisplayTest()
driver.SetDecodeMode(4)
driver.SetScanLimit(4)
driver.StopShutdownMode()
for i := 1; i < int(digitNumber); i++ {
driver.WriteCommand(byte(i), byte(Blank))
}
for {
for _, character := range characters {
println("writing", "characterValue:", character.String())
driver.WriteCommand(byte(4), byte(character))
driver.WriteCommand(byte(3), byte(character))
driver.WriteCommand(byte(2), byte(character))
driver.WriteCommand(byte(1), byte(character))
time.Sleep(500 * time.Millisecond)
}
time.Sleep(time.Second)
}
}
var characters = []Character{
Zero,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Dash,
E,
H,
L,
P,
Blank,
Dot,
}
// Each bit translates to a pin, which is driven high or low
type Character byte
func (char Character) String() string {
switch char {
case Zero:
return "0"
case One:
return "1"
case Two:
return "2"
case Three:
return "3"
case Four:
return "4"
case Five:
return "5"
case Six:
return "6"
case Seven:
return "7"
case Eight:
return "8"
case Nine:
return "9"
case Dash:
return "-"
case E:
return "E"
case H:
return "H"
case L:
return "L"
case P:
return "P"
case Blank:
return ""
case Dot:
return "."
}
return ""
}
const (
Zero Character = 0 //126
One Character = 1 //48
Two Character = 2 // 109
Three Character = 3 // 121
Four Character = 4
Five Character = 5
Six Character = 6
Seven Character = 7
Eight Character = 8
Nine Character = 9
Dash Character = 10
E Character = 11
H Character = 12
L Character = 13
P Character = 14
Blank Character = 15
Dot Character = 128
)
+55
View File
@@ -0,0 +1,55 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/mcp2515"
)
var (
spi = machine.SPI0
csPin = machine.D5
)
func main() {
spi.Configure(machine.SPIConfig{
Frequency: 115200,
SCK: machine.SPI0_SCK_PIN,
SDO: machine.SPI0_SDO_PIN,
SDI: machine.SPI0_SDI_PIN,
Mode: 0})
can := mcp2515.New(spi, csPin)
can.Configure()
err := can.Begin(mcp2515.CAN500kBps, mcp2515.Clock8MHz)
if err != nil {
failMessage(err.Error())
}
for {
err := can.Tx(0x111, 8, []byte{0x00, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA})
if err != nil {
failMessage(err.Error())
}
if can.Received() {
msg, err := can.Rx()
if err != nil {
failMessage(err.Error())
}
fmt.Printf("CAN-ID: %03X dlc: %d data: ", msg.ID, msg.Dlc)
for _, b := range msg.Data {
fmt.Printf("%02X ", b)
}
fmt.Print("\r\n")
}
time.Sleep(time.Millisecond * 500)
}
}
func failMessage(msg string) {
for {
println(msg)
time.Sleep(1 * time.Second)
}
}
+74
View File
@@ -0,0 +1,74 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/p1am"
)
func main() {
for {
if err := loop(); err != nil {
fmt.Printf("loop failed, retrying: %v\n", err)
time.Sleep(500 * time.Millisecond)
}
}
}
func loop() error {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sw := machine.SWITCH
sw.Configure(machine.PinConfig{Mode: machine.PinInput})
if err := p1am.Controller.Initialize(); err != nil {
return fmt.Errorf("initializing controller: %w", err)
}
version, err := p1am.Controller.Version()
if err != nil {
return fmt.Errorf("fetching base controller version: %w", err)
}
fmt.Printf("Base controller version: %d.%d.%d\n", version[0], version[1], version[2])
for i := 1; i <= p1am.Controller.Slots; i++ {
slot := p1am.Controller.Slot(i)
fmt.Printf("Slot %d: ID 0x%08x, Props %+v\n", i, slot.ID, slot.Props)
}
slot1 := p1am.Controller.Slot(1)
var lastInput uint32
state := sw.Get()
for {
if active, err := p1am.Controller.Active(); err != nil || !active {
return fmt.Errorf("controller active %v: %v", active, err)
}
if state != sw.Get() {
state = sw.Get()
fmt.Printf("New switch state: %v\n", state)
if slot1.Props.DO > 0 {
if err := slot1.Channel(1).WriteDiscrete(state); err != nil {
return err
}
}
}
if slot1.Props.DI > 0 {
sstate, err := slot1.ReadDiscrete()
if err != nil {
return fmt.Errorf("reading slot: %w", err)
}
if sstate != lastInput {
lastInput = sstate
fmt.Printf("new DI state: %#b\n", sstate)
}
}
if state {
led.High()
} else {
led.Low()
}
time.Sleep(time.Millisecond * 10)
}
return nil
}
+45
View File
@@ -0,0 +1,45 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
time.Sleep(3 * time.Second)
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 50, 0, time.UTC))
rtc.SetAlarm(time.Date(2006, 1, 2, 15, 5, 0, 0, time.UTC))
rtc.EnableAlarmInterrupt()
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
if rtc.AlarmTriggered() {
fmt.Printf("alarm triggered\r\n")
rtc.ClearAlarm()
}
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
for {
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1HZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32HZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_1KHZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_32KHZ)
time.Sleep(3 * time.Second)
rtc.SetOscillatorFrequency(pcf8563.RTC_COT_DISABLE)
time.Sleep(3 * time.Second)
}
}
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
+46
View File
@@ -0,0 +1,46 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/pcf8563"
)
var (
i2c = machine.I2C0
rtc = pcf8563.New(i2c)
)
func main() {
i2c.Configure(machine.I2CConfig{Frequency: machine.TWI_FREQ_400KHZ})
rtc.Reset()
time.Sleep(3 * time.Second)
rtc.SetTime(time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC))
rtc.SetTimer(15 * time.Second)
rtc.EnableTimerInterrupt()
prev := -1
for {
for {
t, _ := rtc.ReadTime()
if prev != t.Second() {
fmt.Printf("%s\r\n", t.String())
prev = t.Second()
if rtc.TimerTriggered() {
fmt.Printf("timer triggered\r\n")
rtc.ClearTimer()
rtc.SetTimer(10 * time.Second)
}
break
}
time.Sleep(time.Millisecond * 100)
}
}
}
+141
View File
@@ -0,0 +1,141 @@
package main
import (
"fmt"
"strings"
"time"
"tinygo.org/x/drivers/net"
"tinygo.org/x/drivers/net/tls"
"tinygo.org/x/drivers/rtl8720dn"
)
// You can override the setting with the init() in another source code.
// func init() {
// ssid = "your-ssid"
// password = "your-password"
// debug = true
// server = "tinygo.org"
// test_root_ca = "..."
// }
var (
ssid string
password string
server string = "www.example.com"
debug = false
)
// Set the test_root_ca created by the following command
// $ openssl s_client -showcerts -verify 5 -connect www.example.com:443 < /dev/null
var test_root_ca = `-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
`
var buf [0x400]byte
var lastRequestTime time.Time
var conn net.Conn
var adaptor *rtl8720dn.RTL8720DN
func main() {
err := run()
for err != nil {
fmt.Printf("error: %s\r\n", err.Error())
time.Sleep(5 * time.Second)
}
}
func run() error {
rtl, err := setupRTL8720DN()
if err != nil {
return err
}
rtl.SetRootCA(&test_root_ca)
net.UseDriver(rtl)
err = rtl.ConnectToAP(ssid, password)
if err != nil {
return err
}
ip, subnet, gateway, err := rtl.GetIP()
if err != nil {
return err
}
fmt.Printf("IP Address : %s\r\n", ip)
fmt.Printf("Mask : %s\r\n", subnet)
fmt.Printf("Gateway : %s\r\n", gateway)
cnt := 0
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPSRequest()
cnt++
fmt.Printf("-------- %d --------\r\n", cnt)
}
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
println("Read error: " + err.Error())
} else {
print(string(buf[0:n]))
}
}
}
}
func makeHTTPSRequest() {
var err error
if conn != nil {
conn.Close()
}
message("\r\n---------------\r\nDialing TCP connection")
conn, err = tls.Dial("tcp", server, nil)
for ; err != nil; conn, err = tls.Dial("tcp", server, nil) {
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
print("Sending HTTPS request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", strings.Split(server, ":")[0])
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
lastRequestTime = time.Now()
}
func message(msg string) {
println(msg, "\r")
}
@@ -0,0 +1,71 @@
// +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)
}
@@ -0,0 +1,143 @@
package main
import (
"fmt"
"image/color"
"time"
"tinygo.org/x/drivers/net"
"tinygo.org/x/drivers/rtl8720dn"
"tinygo.org/x/tinyfont/proggy"
"tinygo.org/x/tinyterm"
)
// You can override the setting with the init() in another source code.
// func init() {
// ssid = "your-ssid"
// password = "your-password"
// debug = true
// server = "tinygo.org"
// }
var (
ssid string
password string
server string = "tinygo.org"
debug = false
)
var (
terminal = tinyterm.NewTerminal(display)
black = color.RGBA{0, 0, 0, 255}
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}
font = &proggy.TinySZ8pt7b
)
var buf [0x400]byte
var lastRequestTime time.Time
var conn net.Conn
var adaptor *rtl8720dn.RTL8720DN
func main() {
display.FillScreen(black)
backlight.High()
terminal.Configure(&tinyterm.Config{
Font: font,
FontHeight: 10,
FontOffset: 6,
})
err := run()
for err != nil {
fmt.Fprintf(terminal, "error: %s\r\n", err.Error())
time.Sleep(5 * time.Second)
}
}
func run() error {
fmt.Fprintf(terminal, "setupRTL8720DN()\r\n")
rtl, err := setupRTL8720DN()
if err != nil {
return err
}
net.UseDriver(rtl)
fmt.Fprintf(terminal, "ConnectToAP()\r\n")
err = rtl.ConnectToAP(ssid, password)
if err != nil {
return err
}
fmt.Fprintf(terminal, "connected\r\n\r\n")
ip, subnet, gateway, err := rtl.GetIP()
if err != nil {
return err
}
fmt.Fprintf(terminal, "IP Address : %s\r\n", ip)
fmt.Fprintf(terminal, "Mask : %s\r\n", subnet)
fmt.Fprintf(terminal, "Gateway : %s\r\n", gateway)
cnt := 0
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
cnt++
fmt.Fprintf(terminal, "-------- %d --------\r\n", cnt)
}
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
fmt.Fprintf(terminal, "Read error: "+err.Error()+"\r\n")
} else {
fmt.Fprintf(terminal, string(buf[0:n]))
}
}
}
}
func makeHTTPRequest() {
var err error
if conn != nil {
conn.Close()
}
// make TCP connection
ip := net.ParseIP(server)
raddr := &net.TCPAddr{IP: ip, Port: 80}
laddr := &net.TCPAddr{Port: 8080}
message("\r\n---------------\r\nDialing TCP connection")
conn, err = net.DialTCP("tcp", laddr, raddr)
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
fmt.Fprintf(terminal, "Connected!\r\n")
fmt.Fprintf(terminal, "Sending HTTP request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", server)
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
fmt.Fprintf(terminal, "Sent!\r\n\r\n")
lastRequestTime = time.Now()
}
func message(msg string) {
fmt.Fprintf(terminal, "%s\r\n", msg)
}
@@ -0,0 +1,97 @@
// +build wioterminal
package main
import (
"device/sam"
"machine"
"runtime/interrupt"
"time"
"tinygo.org/x/drivers/ili9341"
"tinygo.org/x/drivers/rtl8720dn"
)
var (
uart UARTx
)
var (
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
backlight = machine.LCD_BACKLIGHT
)
func init() {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 40000000,
})
display.Configure(ili9341.Config{})
backlight.Configure(machine.PinConfig{machine.PinOutput})
}
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)
}
+116
View File
@@ -0,0 +1,116 @@
package main
import (
"fmt"
"time"
"tinygo.org/x/drivers/net"
"tinygo.org/x/drivers/rtl8720dn"
)
// You can override the setting with the init() in another source code.
// func init() {
// ssid = "your-ssid"
// password = "your-password"
// debug = true
// server = "tinygo.org"
// }
var (
ssid string
password string
server string = "tinygo.org"
debug = false
)
var buf [0x400]byte
var lastRequestTime time.Time
var conn net.Conn
var adaptor *rtl8720dn.RTL8720DN
func main() {
err := run()
for err != nil {
fmt.Printf("error: %s\r\n", err.Error())
time.Sleep(5 * time.Second)
}
}
func run() error {
rtl, err := setupRTL8720DN()
if err != nil {
return err
}
net.UseDriver(rtl)
err = rtl.ConnectToAP(ssid, password)
if err != nil {
return err
}
ip, subnet, gateway, err := rtl.GetIP()
if err != nil {
return err
}
fmt.Printf("IP Address : %s\r\n", ip)
fmt.Printf("Mask : %s\r\n", subnet)
fmt.Printf("Gateway : %s\r\n", gateway)
cnt := 0
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
cnt++
fmt.Printf("-------- %d --------\r\n", cnt)
}
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
println("Read error: " + err.Error())
} else {
print(string(buf[0:n]))
}
}
}
}
func makeHTTPRequest() {
var err error
if conn != nil {
conn.Close()
}
// make TCP connection
ip := net.ParseIP(server)
raddr := &net.TCPAddr{IP: ip, Port: 80}
laddr := &net.TCPAddr{Port: 8080}
message("\r\n---------------\r\nDialing TCP connection")
conn, err = net.DialTCP("tcp", laddr, raddr)
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
print("Sending HTTP request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", server)
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
lastRequestTime = time.Now()
}
func message(msg string) {
println(msg, "\r")
}
@@ -0,0 +1,71 @@
// +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)
}
+363
View File
@@ -0,0 +1,363 @@
package main
import (
"fmt"
"io"
"machine"
"os"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers/sdcard"
)
const consoleBufLen = 64
const storageBufLen = 1024
var (
debug = false
input [consoleBufLen]byte
store [storageBufLen]byte
console = machine.Serial
dev *sdcard.Device
commands map[string]cmdfunc = map[string]cmdfunc{
"": cmdfunc(noop),
"help": cmdfunc(help),
"dbg": cmdfunc(dbg),
"erase": cmdfunc(erase),
"lsblk": cmdfunc(lsblk),
"write": cmdfunc(write),
"xxd": cmdfunc(xxd),
}
his history
)
type history struct {
buf [32]string
wp int
idx int
}
func (h *history) Add(cmd string) {
if len(cmd) == 0 {
h.idx = h.wp
return
}
if h.wp == len(h.buf)-1 {
for i := 1; i < len(h.buf); i++ {
h.buf[i-1] = h.buf[i]
}
h.wp--
}
h.buf[h.wp] = cmd
h.wp++
h.idx = h.wp
}
func (h *history) PeekPrev() string {
if h.idx > 0 {
h.idx--
}
return h.buf[h.idx]
}
func (h *history) PeekNext() string {
if h.idx < h.wp {
h.idx++
}
return h.buf[h.idx]
}
type cmdfunc func(argv []string)
const (
StateInput = iota
StateEscape
StateEscBrc
StateCSI
)
func RunFor(device *sdcard.Device) {
dev = device
prompt()
var state = StateInput
for i := 0; ; {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if debug {
fmt.Printf("\rdata: %x, his.idx: %d\r\n\r", data, his.idx)
prompt()
console.Write(input[:i])
}
switch state {
case StateInput:
switch data {
case 0x8:
fallthrough
case 0x7f: // this is probably wrong... works on my machine tho :)
// backspace
if i > 0 {
i -= 1
console.Write([]byte{0x8, 0x20, 0x8})
}
case 13:
// return key
console.Write([]byte("\r\n"))
runCommand(string(input[:i]))
his.Add(string(input[:i]))
prompt()
i = 0
continue
case 27:
// escape
state = StateEscape
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
if i < (consoleBufLen - 1) {
console.WriteByte(data)
input[i] = data
i++
}
}
}
case StateEscape:
switch data {
case 0x5b:
state = StateEscBrc
default:
state = StateInput
}
case StateEscBrc:
switch data {
case 0x41:
// up
println()
prompt()
cmd := his.PeekPrev()
i = len(cmd)
copy(input[:i], []byte(cmd))
console.Write(input[:i])
state = StateInput
case 0x42:
//down
println()
prompt()
cmd := his.PeekNext()
i = len(cmd)
copy(input[:i], []byte(cmd))
console.Write(input[:i])
state = StateInput
default:
// TODO: handle escape sequences
state = StateInput
}
default:
// TODO: handle escape sequences
state = StateInput
}
} else {
time.Sleep(1 * time.Millisecond)
}
}
}
func runCommand(line string) {
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
cmd := argv[0]
cmdfn, ok := commands[cmd]
if !ok {
println("unknown command: " + line)
return
}
cmdfn(argv)
}
func noop(argv []string) {}
func help(argv []string) {
fmt.Printf("help\r\n")
fmt.Printf("dbg\r\n")
fmt.Printf("erase\r\n")
fmt.Printf("lsblk\r\n")
fmt.Printf("write <hex offset> <bytes>\r\n")
fmt.Printf("xxd <start address> <length>\r\n")
}
func dbg(argv []string) {
if debug {
debug = false
println("Console debbuging off")
} else {
debug = true
println("Console debbuging on")
}
}
func lsblk(argv []string) {
csd := dev.CSD
sectors, err := csd.Sectors()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
return
}
cid := dev.CID
fmt.Printf(
"\r\n-------------------------------------\r\n"+
" Device Information: \r\n"+
"-------------------------------------\r\n"+
" JEDEC ID: %v\r\n"+
" Serial: %v\r\n"+
" Status 1: %02x\r\n"+
" Status 2: %02x\r\n"+
" \r\n"+
" Max clock speed (MHz): %d\r\n"+
" Has Sector Protection: %t\r\n"+
" Supports Fast Reads: %t\r\n"+
" Supports QSPI Reads: %t\r\n"+
" Supports QSPI Write: %t\r\n"+
" Write Status Split: %t\r\n"+
" Single Status Byte: %t\r\n"+
"-Sectors: %d\r\n"+
"-Bytes (Sectors * 512) %d\r\n"+
"-ManufacturerID %02X\r\n"+
"-OEMApplicationID %04X\r\n"+
"-ProductName %s\r\n"+
"-ProductVersion %s\r\n"+
"-ProductSerialNumber %08X\r\n"+
"-ManufacturingYear %02X\r\n"+
"-ManufacturingMonth %02X\r\n"+
"-Always1 %d\r\n"+
"-CRC %02X\r\n"+
"-------------------------------------\r\n\r\n",
"attrs.JedecID", // attrs.JedecID,
cid.ProductSerialNumber, // serialNumber1,
0, // status1,
0, // status2,
csd.TRAN_SPEED, // attrs.MaxClockSpeedMHz,
false, // attrs.HasSectorProtection,
false, // attrs.SupportsFastRead,
false, // attrs.SupportsQSPI,
false, // attrs.SupportsQSPIWrites,
false, // attrs.WriteStatusSplit,
false, // attrs.SingleStatusByte,
sectors,
csd.Size(),
cid.ManufacturerID,
cid.OEMApplicationID,
cid.ProductName,
cid.ProductVersion,
cid.ProductSerialNumber,
cid.ManufacturingYear,
cid.ManufacturingMonth,
cid.Always1,
cid.CRC,
)
}
func erase(argv []string) {
fmt.Printf("erase - not impl\r\n")
}
var writeBuf [256]byte
func write(argv []string) {
if len(argv) < 3 {
println("usage: write <hex offset> <bytes>")
return
}
var err error
var addr uint64 = 0x0
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
buf := writeBuf[:0]
for i := 0; i < len(argv[2]); i += 2 {
var b uint64
if b, err = strconv.ParseUint(argv[2][i:i+2], 16, 8); err != nil {
println("Invalid bytes: " + err.Error() + "\r\n")
return
}
buf = append(buf, byte(b))
}
if _, err = dev.WriteAt(buf, int64(addr)); err != nil {
println("Write error: " + err.Error() + "\r\n")
}
}
func xxd(argv []string) {
var err error
var addr uint64 = 0x0
var size int = 64
switch len(argv) {
case 3:
if size, err = strconv.Atoi(argv[2]); err != nil {
println("Invalid size argument: " + err.Error() + "\r\n")
return
}
if size > storageBufLen || size < 1 {
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", storageBufLen)
return
}
fallthrough
case 2:
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
fallthrough
case 1:
// no args supplied, so nothing to do here, just use the defaults
default:
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
return
}
buf := store[0:size]
_, err = dev.ReadAt(buf, int64(addr))
if err != nil {
fmt.Printf("xxd err : %s\r\n", err.Error())
}
xxdfprint(os.Stdout, uint32(addr), buf)
}
func xxdfprint(w io.Writer, offset uint32, b []byte) {
var l int
var buf16 = make([]byte, 16)
for i, c := 0, len(b); i < c; i += 16 {
l = i + 16
if l >= c {
l = c
}
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
for j, n := 0, l-i; j < 16; j++ {
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
buf16[j] = '.'
} else {
buf16[j] = b[i+j]
}
}
console.Write(buf16)
println()
}
}
func prompt() {
print("==> ")
}
+17
View File
@@ -0,0 +1,17 @@
// +build feather_m4 feather_m4_can feather_nrf52840
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D10
ledPin = machine.LED
}
@@ -0,0 +1,17 @@
// +build grandcentral-m4
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_CS_PIN
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build atsamd21,!p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D2
ledPin = machine.LED
}
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/sdcard"
)
var (
spi machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
csPin machine.Pin
ledPin machine.Pin
)
func main() {
waitSerial()
fmt.Printf("sdcard console\r\n")
led := ledPin
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
err := sd.Configure()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
for {
time.Sleep(time.Hour)
}
}
go RunFor(&sd)
for {
led.High()
time.Sleep(200 * time.Millisecond)
led.Low()
time.Sleep(200 * time.Millisecond)
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
+17
View File
@@ -0,0 +1,17 @@
// +build p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_SS_PIN
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build pygamer
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D4
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build pyportal
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D32 // SD_CS
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build wioterminal
package main
import (
"machine"
)
func init() {
spi = machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
csPin = machine.SS2
ledPin = machine.LED
}
+542
View File
@@ -0,0 +1,542 @@
// +build tinygo
package console
import (
"fmt"
"io"
"machine"
"os"
"strconv"
"strings"
"time"
"tinygo.org/x/tinyfs"
)
const consoleBufLen = 64
const startBlock = 0
const blockCount = 0
var (
debug = false
input [consoleBufLen]byte
console = machine.Serial
readyLED = machine.LED
flashdev tinyfs.BlockDevice
fs tinyfs.Filesystem
currdir = "/"
commands = map[string]cmdfunc{
"": noop,
"dbg": dbg,
"help": help,
"lsblk": lsblk,
"mount": mount,
"umount": umount,
"format": format,
"xxd": xxd,
"ls": ls,
"samples": samples,
"mkdir": mkdir,
"cat": cat,
"create": create,
"write": write,
"rm": rm,
}
)
type cmdfunc func(argv []string)
const (
StateInput = iota
StateEscape
StateEscBrc
StateCSI
)
func RunFor(dev tinyfs.BlockDevice, filesys tinyfs.Filesystem) {
flashdev = dev
fs = filesys
readyLED.Configure(machine.PinConfig{Mode: machine.PinOutput})
readyLED.High()
readyLED.Low()
println("SPI Configured. Reading flash info")
/*
lfsConfig := flashlfs.NewConfig()
if blockCount == 0 {
lfsConfig.BlockCount = (flashdev.Attrs().TotalSize / lfsConfig.BlockSize) - startBlock
} else {
lfsConfig.BlockCount = blockCount
}
println("Start block:", startBlock)
println("Block count:", lfsConfig.BlockCount)
blockdev = flashlfs.NewBlockDevice(flashdev, startBlock, lfsConfig.BlockSize)
*/
prompt()
var state = StateInput
for i := 0; ; {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if debug {
fmt.Printf("\rdata: %x\r\n\r", data)
prompt()
console.Write(input[:i])
}
switch state {
case StateInput:
switch data {
case 0x8:
fallthrough
case 0x7f: // this is probably wrong... works on my machine tho :)
// backspace
if i > 0 {
i -= 1
console.Write([]byte{0x8, 0x20, 0x8})
}
case 13:
// return key
if console.Buffered() > 0 {
data, _ := console.ReadByte()
if data != 10 {
println("\r\nunexpected: \r", int(data))
}
}
console.Write([]byte("\r\n"))
runCommand(string(input[:i]))
prompt()
i = 0
continue
case 27:
// escape
state = StateEscape
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
if i < (consoleBufLen - 1) {
console.WriteByte(data)
input[i] = data
i++
}
}
}
case StateEscape:
switch data {
case 0x5b:
state = StateEscBrc
default:
state = StateInput
}
default:
// TODO: handle escape sequences
state = StateInput
}
}
}
}
func runCommand(line string) {
argv := strings.SplitN(strings.TrimSpace(line), " ", -1)
cmd := argv[0]
cmdfn, ok := commands[cmd]
if !ok {
println("unknown command: " + line)
return
}
cmdfn(argv)
}
func noop(argv []string) {}
func help(argv []string) {
fmt.Printf("help\r\n")
fmt.Printf(" show help\r\n")
fmt.Printf("dbg\r\n")
fmt.Printf(" toggle debug mode\r\n")
fmt.Printf("xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
fmt.Printf(" hexdump the specified address\r\n")
fmt.Printf("ls <target file>\r\n")
fmt.Printf(" list information\r\n")
fmt.Printf("samples\r\n")
fmt.Printf(" write some files in the root directory\r\n")
fmt.Printf("mkdir <target dir>\r\n")
fmt.Printf(" create directory\r\n")
fmt.Printf("cat <target file>\r\n")
fmt.Printf(" print the contents of file\r\n")
fmt.Printf("create <target file>\r\n")
fmt.Printf(" create file\r\n")
fmt.Printf("write <target file>\r\n")
fmt.Printf(" write to file (press CTRL-D to exit)\r\n")
fmt.Printf("rm\r\n")
}
func dbg(argv []string) {
if debug {
debug = false
println("Console debugging off")
} else {
debug = true
println("Console debugging on")
}
}
func lsblk(argv []string) {
fmt.Printf("lsblk : not implement\r\n")
}
func mount(argv []string) {
if err := fs.Mount(); err != nil {
println("Could not mount LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully mounted LittleFS filesystem.\r\n")
}
}
func format(argv []string) {
if err := fs.Format(); err != nil {
println("Could not format LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully formatted LittleFS filesystem.\r\n")
}
}
func umount(argv []string) {
if err := fs.Unmount(); err != nil {
println("Could not unmount LittleFS filesystem: " + err.Error() + "\r\n")
} else {
println("Successfully unmounted LittleFS filesystem.\r\n")
}
}
/*
var err error
if fatfs == nil {
fatfs, err = fat.New(fatdisk)
if err != nil {
fatfs = nil
println("could not load FAT filesystem: " + err.Error() + "\r\n")
}
fmt.Printf("loaded fs\r\n")
}
if rootdir == nil {
rootdir, err = fatfs.RootDir()
if err != nil {
rootdir = nil
println("could not load rootdir: " + err.Error() + "\r\n")
}
fmt.Printf("loaded rootdir\r\n")
}
if currdir == nil {
currdir = rootdir
}
*/
func ls(argv []string) {
path := "/"
if len(argv) > 1 {
path = strings.TrimSpace(argv[1])
}
dir, err := fs.Open(path)
if err != nil {
fmt.Printf("Could not open directory %s: %v\r\n", path, err)
return
}
defer dir.Close()
infos, err := dir.Readdir(0)
_ = infos
if err != nil {
fmt.Printf("Could not read directory %s: %v\r\n", path, err)
return
}
for _, info := range infos {
s := "-rwxrwxrwx"
if info.IsDir() {
s = "drwxrwxrwx"
}
fmt.Printf("%s %5d %s\r\n", s, info.Size(), info.Name())
}
}
func mkdir(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying mkdir to " + tgt)
}
if tgt == "" {
println("Usage: mkdir <target dir>")
return
}
err := fs.Mkdir(tgt, 0777)
if err != nil {
println("Could not mkdir " + tgt + ": " + err.Error())
}
}
func rm(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying rm to " + tgt)
}
if tgt == "" {
println("Usage: rm <target dir>")
return
}
err := fs.Remove(tgt)
if err != nil {
println("Could not rm " + tgt + ": " + err.Error())
}
}
func samples(argv []string) {
buf := make([]byte, 90)
for i := 0; i < 5; i++ {
name := fmt.Sprintf("file%d.txt", i)
if bytes, err := createSampleFile(name, buf); err != nil {
fmt.Printf("%s\r\n", err)
return
} else {
fmt.Printf("wrote %d bytes to %s\r\n", bytes, name)
}
}
}
func create(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying create to " + tgt)
}
buf := make([]byte, 90)
if bytes, err := createSampleFile(tgt, buf); err != nil {
fmt.Printf("%s\r\n", err)
return
} else {
fmt.Printf("wrote %d bytes to %s\r\n", bytes, tgt)
}
}
func write(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying receive to " + tgt)
}
buf := make([]byte, 1)
f, err := fs.OpenFile(tgt, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
if err != nil {
fmt.Printf("error opening %s: %s\r\n", tgt, err.Error())
return
}
defer f.Close()
var n int
for {
if console.Buffered() > 0 {
data, _ := console.ReadByte()
switch data {
case 0x04:
fmt.Printf("wrote %d bytes to %s\r\n", n, tgt)
return
default:
// anything else, just echo the character if it is printable
if strconv.IsPrint(rune(data)) {
console.WriteByte(data)
}
buf[0] = data
if _, err := f.Write(buf); err != nil {
fmt.Printf("\nerror writing: %s\r\n", err)
return
}
n++
}
}
}
}
func createSampleFile(name string, buf []byte) (int, error) {
for j := uint8(0); j < uint8(len(buf)); j++ {
buf[j] = 0x20 + j
}
f, err := fs.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC)
if err != nil {
return 0, fmt.Errorf("error opening %s: %s", name, err.Error())
}
defer f.Close()
bytes, err := f.Write(buf)
if err != nil {
return 0, fmt.Errorf("error writing %s: %s", name, err.Error())
}
return bytes, nil
}
/*
func cd(argv []string) {
if fatfs == nil || rootdir == nil {
mnt(nil)
}
if len(argv) == 1 {
currdir = rootdir
return
}
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying to cd to " + tgt)
}
if tgt == "" {
println("Usage: cd <target dir>")
return
}
if debug {
println("Getting entry")
}
entry := currdir.Entry(tgt)
if entry == nil {
println("File not found: " + tgt)
return
}
if !entry.IsDir() {
println("Not a directory: " + tgt)
return
}
if debug {
println("Getting dir")
}
cd, err := entry.Dir()
if err != nil {
println("Could not cd to " + tgt + ": " + err.Error())
}
currdir = cd
}
*/
func cat(argv []string) {
tgt := ""
if len(argv) == 2 {
tgt = strings.TrimSpace(argv[1])
}
if debug {
println("Trying to cat to " + tgt)
}
if tgt == "" {
println("Usage: cat <target file>")
return
}
if debug {
println("Getting entry")
}
f, err := fs.Open(tgt)
if err != nil {
println("Could not open: " + err.Error())
return
}
defer f.Close()
if f.IsDir() {
println("Not a file: " + tgt)
return
}
off := 0x0
buf := make([]byte, 64)
for {
n, err := f.Read(buf)
if err != nil {
if err == io.EOF {
break
}
println("Error reading " + tgt + ": " + err.Error())
time.Sleep(1 * time.Second)
}
xxdfprint(os.Stdout, uint32(off), buf[:n])
off += n
}
}
func xxd(argv []string) {
var err error
var addr uint64 = 0x0
var size int = 64
switch len(argv) {
case 3:
if size, err = strconv.Atoi(argv[2]); err != nil {
println("Invalid size argument: " + err.Error() + "\r\n")
return
}
if size > 512 || size < 1 {
fmt.Printf("Size of hexdump must be greater than 0 and less than %d\r\n", 512)
return
}
fallthrough
case 2:
/*
if argv[1][:2] != "0x" {
println("Invalid hex address (should start with 0x)")
return
}
*/
if addr, err = strconv.ParseUint(argv[1], 16, 32); err != nil {
println("Invalid address: " + err.Error() + "\r\n")
return
}
fallthrough
case 1:
// no args supplied, so nothing to do here, just use the defaults
default:
println("usage: xxd <hex address, ex: 0xA0> <size of hexdump in bytes>\r\n")
return
}
buf := make([]byte, size)
//bsz := uint64(flash.SectorSize)
//blockdev.ReadBlock(uint32(addr/bsz), uint32(addr%bsz), buf)
flashdev.ReadAt(buf, int64(addr))
xxdfprint(os.Stdout, uint32(addr), buf)
}
func xxdfprint(w io.Writer, offset uint32, b []byte) {
var l int
var buf16 = make([]byte, 16)
for i, c := 0, len(b); i < c; i += 16 {
l = i + 16
if l >= c {
l = c
}
fmt.Fprintf(w, "%08x: % x ", offset+uint32(i), b[i:l])
for j, n := 0, l-i; j < 16; j++ {
if j >= n || !strconv.IsPrint(rune(b[i+j])) || b[i+j] >= 0x80 {
buf16[j] = '.'
} else {
buf16[j] = b[i+j]
}
}
console.Write(buf16)
println()
}
}
func prompt() {
print("==> ")
}
+17
View File
@@ -0,0 +1,17 @@
// +build feather_m4 feather_m4_can feather_nrf52840
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D10
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build grandcentral-m4
package main
import (
"machine"
)
func init() {
spi = machine.SPI1
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_CS_PIN
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build atsamd21,!p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D2
ledPin = machine.LED
}
+49
View File
@@ -0,0 +1,49 @@
package main
import (
"fmt"
"machine"
"time"
"tinygo.org/x/drivers/examples/sdcard/tinyfs/console"
"tinygo.org/x/drivers/sdcard"
"tinygo.org/x/tinyfs/fatfs"
)
var (
spi machine.SPI
sckPin machine.Pin
sdoPin machine.Pin
sdiPin machine.Pin
csPin machine.Pin
ledPin machine.Pin
)
func main() {
waitSerial()
sd := sdcard.New(spi, sckPin, sdoPin, sdiPin, csPin)
err := sd.Configure()
if err != nil {
fmt.Printf("%s\r\n", err.Error())
for {
time.Sleep(time.Hour)
}
}
filesystem := fatfs.New(&sd)
// Configure FATFS with sector size (must match value in ff.h - use 512)
filesystem.Configure(&fatfs.Config{
SectorSize: 512,
})
console.RunFor(&sd, filesystem)
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
+17
View File
@@ -0,0 +1,17 @@
// +build p1am_100
package main
import (
"machine"
)
func init() {
spi = machine.SDCARD_SPI
sckPin = machine.SDCARD_SCK_PIN
sdoPin = machine.SDCARD_SDO_PIN
sdiPin = machine.SDCARD_SDI_PIN
csPin = machine.SDCARD_SS_PIN
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build pygamer
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D4
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build pyportal
package main
import (
"machine"
)
func init() {
spi = machine.SPI0
sckPin = machine.SPI0_SCK_PIN
sdoPin = machine.SPI0_SDO_PIN
sdiPin = machine.SPI0_SDI_PIN
csPin = machine.D32 // SD_CS
ledPin = machine.LED
}
+17
View File
@@ -0,0 +1,17 @@
// +build wioterminal
package main
import (
"machine"
)
func init() {
spi = machine.SPI2
sckPin = machine.SCK2
sdoPin = machine.SDO2
sdiPin = machine.SDI2
csPin = machine.SS2
ledPin = machine.LED
}
+43
View File
@@ -0,0 +1,43 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/servo"
)
// Configuration for the Arduino Uno.
// Please change the PWM and pin if you want to try this example on a different
// board.
var (
pwm = machine.Timer1
pin = machine.D9
)
func main() {
s, err := servo.New(pwm, pin)
if err != nil {
for {
println("could not configure servo")
time.Sleep(time.Second)
}
return
}
println("setting to 0°")
s.SetMicroseconds(1000)
time.Sleep(3 * time.Second)
println("setting to 45°")
s.SetMicroseconds(1500)
time.Sleep(3 * time.Second)
println("setting to 90°")
s.SetMicroseconds(2000)
time.Sleep(3 * time.Second)
for {
time.Sleep(time.Second)
}
}
+60
View File
@@ -0,0 +1,60 @@
// This example shows how to use 128x64 display over I2C
// Tested on Seeeduino XIAO Expansion Board https://wiki.seeedstudio.com/Seeeduino-XIAO-Expansion-Board/
//
// According to manual, I2C address of the display is 0x78, but that's 8-bit address.
// TinyGo operates on 7-bit addresses and respective 7-bit address would be 0x3C, which we use below.
//
// To learn more about different types of I2C addresses, please see following page
// https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing
package main
import (
"machine"
"image/color"
"time"
"tinygo.org/x/drivers/ssd1306"
)
func main() {
machine.I2C0.Configure(machine.I2CConfig{
Frequency: machine.TWI_FREQ_400KHZ,
})
display := ssd1306.NewI2C(machine.I2C0)
display.Configure(ssd1306.Config{
Address: 0x3C,
Width: 128,
Height: 64,
})
display.ClearDisplay()
x := int16(0)
y := int16(0)
deltaX := int16(1)
deltaY := int16(1)
for {
pixel := display.GetPixel(x, y)
c := color.RGBA{255, 255, 255, 255}
if pixel {
c = color.RGBA{0, 0, 0, 255}
}
display.SetPixel(x, y, c)
display.Display()
x += deltaX
y += deltaY
if x == 0 || x == 127 {
deltaX = -deltaX
}
if y == 0 || y == 63 {
deltaY = -deltaY
}
time.Sleep(1 * time.Millisecond)
}
}
+40
View File
@@ -0,0 +1,40 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/tm1637"
)
func main() {
tm := tm1637.New(machine.D2, machine.D3, 7) // clk, dio, brightness
tm.Configure()
tm.ClearDisplay()
tm.DisplayText([]byte("Tiny"))
time.Sleep(time.Millisecond * 1000)
tm.ClearDisplay()
tm.DisplayChr(byte('G'), 1)
tm.DisplayDigit(0, 2) // looks like O
time.Sleep(time.Millisecond * 1000)
tm.DisplayClock(12, 59, true)
for i := uint8(0); i < 8; i++ {
tm.Brightness(i)
time.Sleep(time.Millisecond * 200)
}
i := int16(0)
for {
tm.DisplayNumber(i)
i++
time.Sleep(time.Millisecond * 50)
}
}
+33
View File
@@ -0,0 +1,33 @@
package main
import (
"machine"
"time"
"tinygo.org/x/drivers/tone"
)
var (
// Configuration for the Adafruit Circuit Playground Bluefruit.
pwm = machine.PWM0
pin = machine.D12
)
func main() {
speaker, err := tone.New(pwm, pin)
if err != nil {
println("failed to configure PWM")
return
}
// Two tone siren.
for {
println("nee")
speaker.SetNote(tone.B5)
time.Sleep(time.Second / 2)
println("naw")
speaker.SetNote(tone.A5)
time.Sleep(time.Second / 2)
}
}
+146
View File
@@ -0,0 +1,146 @@
// This example connects to Access Point and prints some info
package main
import (
"machine"
"strconv"
"time"
"tinygo.org/x/drivers/wifinina"
)
// access point info
const ssid = ""
const pass = ""
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
)
func setup() {
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
adaptor = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
println("----------------------------------------")
printSSID()
printRSSI()
printMac()
printIPs()
printTime()
time.Sleep(10 * time.Second)
}
}
func printSSID() {
print("SSID: ")
ssid, err := adaptor.GetCurrentSSID()
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
println(ssid)
}
func printRSSI() {
print("RSSI: ")
rssi, err := adaptor.GetCurrentRSSI()
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
println(strconv.Itoa(int(rssi)))
}
func printIPs() {
ip, subnet, gateway, err := adaptor.GetIP()
if err != nil {
println("IP: Unknown (error: ", err.Error(), ")")
return
}
println("IP: ", ip.String())
println("Subnet: ", subnet.String())
println("Gateway: ", gateway.String())
}
func printTime() {
print("Time: ")
t, err := adaptor.GetTime()
for {
if err != nil {
println("Unknown (error: ", err.Error(), ")")
return
}
if t != 0 {
break
}
time.Sleep(time.Second)
t, err = adaptor.GetTime()
}
println(time.Unix(int64(t), 0).String())
}
func printMac() {
print("MAC: ")
mac, err := adaptor.GetMACAddress()
if err != nil {
println("Unknown (", err.Error(), ")")
}
println(mac.String())
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
println("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
println("Connection status: " + st.String())
time.Sleep(1 * time.Second)
st, _ = adaptor.GetConnectionStatus()
}
println("Connected.")
}
+2 -6
View File
@@ -35,10 +35,7 @@ const server = "tcp://test.mosquitto.org:1883"
var (
// these are the default pins for the Arduino Nano33 IoT.
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -48,7 +45,6 @@ var (
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Configure SPI for 8Mhz, Mode 0, MSB First
@@ -94,7 +90,7 @@ func main() {
println(err.Error())
}
}
time.Sleep(1 * time.Millisecond)
time.Sleep(100 * time.Millisecond)
}
// Right now this code is never reached. Need a way to trigger it...
+1 -6
View File
@@ -32,12 +32,8 @@ const server = "tcp://test.mosquitto.org:1883"
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -55,7 +51,6 @@ func subHandler(client mqtt.Client, msg mqtt.Message) {
func main() {
time.Sleep(3000 * time.Millisecond)
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
rand.Seed(time.Now().UnixNano())
// Configure SPI for 8Mhz, Mode 0, MSB First
+29 -12
View File
@@ -23,33 +23,41 @@ const ntpHost = "129.6.15.29"
const NTP_PACKET_SIZE = 48
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
b = make([]byte, NTP_PACKET_SIZE)
)
func main() {
// Init esp32
func setup() {
// Configure SPI for 8Mhz, Mode 0, MSB First
machine.NINA_SPI.Configure(machine.SPIConfig{
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
// these are the default pins for the Arduino Nano33 IoT.
adaptor = wifinina.New(machine.NINA_SPI,
adaptor = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
// connect to access point
connectToAP()
// now make UDP connection
@@ -80,10 +88,13 @@ func main() {
}
}
// Right now this code is never reached. Need a way to trigger it...
println("Disconnecting UDP...")
conn.Close()
println("Done.")
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) {
@@ -140,6 +151,12 @@ func clearBuffer() {
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
+1 -6
View File
@@ -29,10 +29,7 @@ const serverIP = ""
var (
// these are the default pins for the Arduino Nano33 IoT.
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -42,8 +39,6 @@ var buf = &bytes.Buffer{}
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
+151
View File
@@ -0,0 +1,151 @@
// This example opens a TCP connection using a device with WiFiNINA firmware
// and sends a HTTPS request to retrieve a webpage
//
// You shall see "strict-transport-security" header in the response,
// this confirms communication is indeed over HTTPS
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
//
package main
import (
"fmt"
"machine"
"strings"
"time"
"tinygo.org/x/drivers/net"
"tinygo.org/x/drivers/net/tls"
"tinygo.org/x/drivers/wifinina"
)
// access point info
const ssid = ""
const pass = ""
// IP address of the server aka "hub". Replace with your own info.
const server = "tinygo.org"
// these are the default pins for the Arduino Nano33 IoT.
// change these to connect to a different UART or pins for the ESP8266/ESP32
var (
// these are the default pins for the Arduino Nano33 IoT.
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
)
var buf [256]byte
var lastRequestTime time.Time
var conn net.Conn
func setup() {
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
SDO: machine.NINA_SDO,
SDI: machine.NINA_SDI,
SCK: machine.NINA_SCK,
})
adaptor = wifinina.New(spi,
machine.NINA_CS,
machine.NINA_ACK,
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPSRequest()
}
}
}
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
println("Read error: " + err.Error())
} else {
print(string(buf[0:n]))
}
}
}
}
func makeHTTPSRequest() {
var err error
if conn != nil {
conn.Close()
}
message("\r\n---------------\r\nDialing TCP connection")
conn, err = tls.Dial("tcp", server, nil)
for ; err != nil; conn, err = tls.Dial("tcp", server, nil) {
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
print("Sending HTTPS request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", strings.Split(server, ":")[0])
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
lastRequestTime = time.Now()
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; {
message("Connection status: " + st.String())
time.Sleep(1 * time.Second)
st, _ = adaptor.GetConnectionStatus()
}
message("Connected.")
time.Sleep(2 * time.Second)
ip, _, _, err := adaptor.GetIP()
for ; err != nil; ip, _, _, err = adaptor.GetIP() {
message(err.Error())
time.Sleep(1 * time.Second)
}
message(ip.String())
}
func message(msg string) {
println(msg, "\r")
}
+30 -27
View File
@@ -27,10 +27,7 @@ const server = "tinygo.org"
var (
// these are the default pins for the Arduino Nano33 IoT.
uart = machine.UART2
tx = machine.NINA_TX
rx = machine.NINA_RX
spi = machine.NINA_SPI
spi = machine.NINA_SPI
// this is the ESP chip that has the WIFININA firmware flashed on it
adaptor *wifinina.Device
@@ -41,10 +38,7 @@ var buf [256]byte
var lastRequestTime time.Time
var conn net.Conn
func main() {
uart.Configure(machine.UARTConfig{TX: tx, RX: rx})
func setup() {
// Configure SPI for 8Mhz, Mode 0, MSB First
spi.Configure(machine.SPIConfig{
Frequency: 8 * 1e6,
@@ -59,16 +53,33 @@ func main() {
machine.NINA_GPIO0,
machine.NINA_RESETN)
adaptor.Configure()
}
func main() {
setup()
waitSerial()
connectToAP()
for {
loop()
readConnection()
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
}
}
println("Done.")
}
func loop() {
// Wait for user to open serial console
func waitSerial() {
for !machine.Serial.DTR() {
time.Sleep(100 * time.Millisecond)
}
}
func readConnection() {
if conn != nil {
for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) {
if err != nil {
@@ -78,9 +89,6 @@ func loop() {
}
}
}
if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 {
makeHTTPRequest()
}
}
func makeHTTPRequest() {
@@ -98,7 +106,7 @@ func makeHTTPRequest() {
message("\r\n---------------\r\nDialing TCP connection")
conn, err = net.DialTCP("tcp", laddr, raddr)
for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) {
message("connection failed: " + err.Error())
message("Connection failed: " + err.Error())
time.Sleep(5 * time.Second)
}
println("Connected!\r")
@@ -106,7 +114,7 @@ func makeHTTPRequest() {
print("Sending HTTP request...")
fmt.Fprintln(conn, "GET / HTTP/1.1")
fmt.Fprintln(conn, "Host:", server)
fmt.Fprintln(conn, "User-Agent: TinyGo/0.10.0")
fmt.Fprintln(conn, "User-Agent: TinyGo")
fmt.Fprintln(conn, "Connection: close")
fmt.Fprintln(conn)
println("Sent!\r\n\r")
@@ -114,19 +122,14 @@ func makeHTTPRequest() {
lastRequestTime = time.Now()
}
func readLine(conn *net.TCPSerialConn) string {
println("Attempting to read...\r")
b := buf[:]
for expiry := time.Now().Unix() + 10; time.Now().Unix() > expiry; {
if n, err := conn.Read(b); n > 0 && err == nil {
return string(b[0:n])
}
}
return ""
}
// connect to access point
func connectToAP() {
if len(ssid) == 0 || len(pass) == 0 {
for {
println("Connection failed: Either ssid or password not set")
time.Sleep(10 * time.Second)
}
}
time.Sleep(2 * time.Second)
message("Connecting to " + ssid)
adaptor.SetPassphrase(ssid, pass)
+2 -1
View File
@@ -4,6 +4,7 @@ package main
import "machine"
// Replace neo in the code below to match the pin
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo = machine.D2
var led = machine.LED
+2 -1
View File
@@ -5,6 +5,7 @@ package main
import "machine"
// This is the pin assignment for the Digispark only.
// Replace neo in the code below to match the pin
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = 0
var led = machine.LED
-1
View File
@@ -15,7 +15,6 @@ import (
var leds [10]color.RGBA
func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
+4 -3
View File
@@ -1,9 +1,10 @@
// +build !digispark,!arduino
// +build !digispark,!arduino,!qtpy
package main
import "machine"
// Replace neo in the code below to match the pin
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.NEOPIXELS
var neo machine.Pin = machine.WS2812
var led = machine.LED
+16
View File
@@ -0,0 +1,16 @@
// +build qtpy
package main
import "machine"
// Replace neo and led in the code below to match the pin
// that you are using if different.
var neo machine.Pin = machine.NEOPIXELS
var led = machine.NoPin
func init() {
pwr := machine.NEOPIXELS_POWER
pwr.Configure(machine.PinConfig{Mode: machine.PinOutput})
pwr.High()
}
+1 -2
View File
@@ -290,9 +290,8 @@ func (dev *Device) EraseBlockSize() int64 {
// supports this. The start and len parameters are in block numbers, use
// EraseBlockSize to map addresses to blocks.
func (dev *Device) EraseBlocks(start, len int64) error {
// TODO: maybe combine sector erase operations into block erase operations
for i := start; i < start+len; i++ {
if err := dev.EraseSector(uint32(i)); err != nil {
if err := dev.EraseBlock(uint32(i)); err != nil {
return err
}
}
+3
View File
@@ -5,4 +5,7 @@ go 1.15
require (
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/frankban/quicktest v1.10.2
tinygo.org/x/tinyfont v0.2.1
tinygo.org/x/tinyfs v0.1.0
tinygo.org/x/tinyterm v0.1.0
)
+11
View File
@@ -1,3 +1,4 @@
github.com/bgould/http v0.0.0-20190627042742-d268792bdee7/go.mod h1:BTqvVegvwifopl4KTEDth6Zezs9eR+lCWhvGKvkxJHE=
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/frankban/quicktest v1.10.2 h1:19ARM85nVi4xH7xPXuc5eM/udya5ieh7b/Sv+d844Tk=
@@ -9,5 +10,15 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
tinygo.org/x/drivers v0.14.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.15.1/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/drivers v0.16.0/go.mod h1:uT2svMq3EpBZpKkGO+NQHjxjGf1f42ra4OnMMwQL2aI=
tinygo.org/x/tinyfont v0.2.1 h1:FAaemBzw8wsfhAtG6fWW+QjyWw/K8YqEeiWo4N1pv4o=
tinygo.org/x/tinyfont v0.2.1/go.mod h1:eLqnYSrFRjt5STxWaMeOWJTzrKhXqpWw7nU3bPfKOAM=
tinygo.org/x/tinyfs v0.1.0 h1:yx1Tq9L60rpCm6HURo45x+Tnag+O9RGSbQfgeCb6XYU=
tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20=
tinygo.org/x/tinyterm v0.1.0 h1:80i+j+KWoxCFa/Xfp6pWbh79x+8zUdMXC1vaKj2QhkY=
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
+2 -3
View File
@@ -4,7 +4,6 @@ package gps // import "tinygo.org/x/drivers/gps"
import (
"encoding/hex"
"errors"
"machine"
"strings"
"time"
@@ -21,13 +20,13 @@ type Device struct {
buffer []byte
bufIdx int
sentence strings.Builder
uart *machine.UART
uart drivers.UART
bus drivers.I2C
address uint16
}
// NewUART creates a new UART GPS connection. The UART must already be configured.
func NewUART(uart *machine.UART) Device {
func NewUART(uart drivers.UART) Device {
return Device{
uart: uart,
buffer: make([]byte, bufferSize),
+17 -1
View File
@@ -160,6 +160,20 @@ func (d *Device) DrawRGBBitmap(x, y int16, data []uint16, w, h int16) error {
return nil
}
// DrawRGBBitmap8 copies an RGB bitmap to the internal buffer at given coordinates
func (d *Device) DrawRGBBitmap8(x, y int16, data []uint8, w, h int16) error {
k, i := d.Size()
if x < 0 || y < 0 || w <= 0 || h <= 0 ||
x >= k || (x+w) > k || y >= i || (y+h) > i {
return errors.New("rectangle coordinates outside display area")
}
d.setWindow(x, y, w, h)
d.startWrite()
d.driver.write8sl(data)
d.endWrite()
return nil
}
// FillRectangle fills a rectangle at given coordinates with a color
func (d *Device) FillRectangle(x, y, width, height int16, c color.RGBA) error {
k, i := d.Size()
@@ -300,7 +314,9 @@ func (d *Device) sendCommand(cmd byte, data []byte) {
d.dc.Low()
d.driver.write8(cmd)
d.dc.High()
d.driver.write8sl(data)
if data != nil {
d.driver.write8sl(data)
}
d.endWrite()
}
+71
View File
@@ -0,0 +1,71 @@
// +build !atsamd51,!atsamd21
package ili9341
import (
"machine"
)
var buf [64]byte
type spiDriver struct {
bus machine.SPI
}
func NewSPI(bus machine.SPI, dc, cs, rst machine.Pin) *Device {
return &Device{
dc: dc,
cs: cs,
rst: rst,
rd: machine.NoPin,
driver: &spiDriver{
bus: bus,
},
}
}
func (pd *spiDriver) configure(config *Config) {
}
func (pd *spiDriver) write8(b byte) {
buf[0] = b
pd.bus.Tx(buf[:1], nil)
}
func (pd *spiDriver) write8n(b byte, n int) {
buf[0] = b
for i := 0; i < n; i++ {
pd.bus.Tx(buf[:1], nil)
}
}
func (pd *spiDriver) write8sl(b []byte) {
pd.bus.Tx(b, nil)
}
func (pd *spiDriver) write16(data uint16) {
buf[0] = uint8(data >> 8)
buf[1] = uint8(data)
pd.bus.Tx(buf[:2], nil)
}
func (pd *spiDriver) write16n(data uint16, n int) {
for i := 0; i < len(buf); i += 2 {
buf[i] = uint8(data >> 8)
buf[i+1] = uint8(data)
}
for i := 0; i < (n >> 5); i++ {
pd.bus.Tx(buf[:], nil)
}
pd.bus.Tx(buf[:n%64], nil)
}
func (pd *spiDriver) write16sl(data []uint16) {
for i, c := 0, len(data); i < c; i++ {
buf[0] = uint8(data[i] >> 8)
buf[1] = uint8(data[i])
pd.bus.Tx(buf[:2], nil)
}
}
+112
View File
@@ -0,0 +1,112 @@
package ina260
import "tinygo.org/x/drivers"
// Device wraps an I2C connection to an INA260 device.
type Device struct {
bus drivers.I2C
Address uint16
}
// Config holds the configuration of the INA260 device.
type Config struct {
// One of AVGMODE_XXX
AverageMode byte
// One of CONVTIME_XXXXUSEC
VoltConvTime byte
// One of CONVTIME_XXXXUSEC
CurrentConvTime byte
// Multiple of MODE_XXXX
Mode byte
}
// New creates a new INA260 connection. The I2C bus must already be
// configured.
//
// This function only creates the Device object, it does not touch the device.
func New(bus drivers.I2C) Device {
return Device{
bus: bus,
Address: Address,
}
}
// Configure sets up the device.
//
// This only needs to be called to override built-in defaults. By default,
// the device starts with:
//
// * AverageMode = AVGMODE_1
// * VoltConvTime = CONVTIME_1100USEC
// * CurrentConvTime = CONVTIME_1100USEC
// * Mode = MODE_CONTINUOUS | MODE_VOLTAGE | MODE_CURRENT
//
func (d *Device) Configure(cfg Config) {
var val uint16
val = uint16(cfg.AverageMode&0x7) << 9
val |= uint16(cfg.VoltConvTime&0x7) << 6
val |= uint16(cfg.CurrentConvTime&0x7) << 3
val |= uint16(cfg.Mode & 0x7)
d.WriteRegister(REG_CONFIG, val)
}
// Resets the device, setting all registers to default values
func (d *Device) Reset() {
d.WriteRegister(REG_CONFIG, 0x8000)
}
// Connected returns whether an INA260 has been found.
func (d *Device) Connected() bool {
return d.ReadRegister(REG_MANF_ID) == MANF_ID &&
(d.ReadRegister(REG_DIE_ID)&DEVICE_ID_MASK) == DEVICE_ID
}
// Gets the measured current in µA (max resolution 1.25mA)
func (d *Device) Current() int32 {
val := d.ReadRegister(REG_CURRENT)
if val&0x8000 == 0 {
return int32(val) * 1250
}
// Two's complement, convert to signed int
return -(int32(^val) + 1) * 1250
}
// Gets the measured voltage in µV (max resolution 1.25mV)
func (d *Device) Voltage() int32 {
val := d.ReadRegister(REG_BUSVOLTAGE)
if val&0x8000 == 0 {
return int32(val) * 1250
}
// Two's complement, convert to signed int
return -(int32(^val) + 1) * 1250
}
// Gets the measured power in µW (max resolution 10mW)
func (d *Device) Power() int32 {
return int32(d.ReadRegister(REG_POWER)) * 10000
}
// Read a register
func (d *Device) ReadRegister(reg uint8) uint16 {
data := []byte{0, 0}
d.bus.ReadRegister(uint8(d.Address), reg, data)
return (uint16(data[0]) << 8) | uint16(data[1])
}
// Write to a register
func (d *Device) WriteRegister(reg uint8, v uint16) {
data := []byte{0, 0}
data[0] = byte(v >> 8)
data[1] = byte(v & 0xff)
d.bus.WriteRegister(uint8(d.Address), reg, data)
}
+80
View File
@@ -0,0 +1,80 @@
package ina260
import (
"testing"
qt "github.com/frankban/quicktest"
"tinygo.org/x/drivers/tester"
)
func TestDefaultI2CAddress(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
dev := New(bus)
c.Assert(dev.Address, qt.Equals, uint16(Address))
}
func TestConnected(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
bus.AddDevice(fake)
dev := New(bus)
c.Assert(dev.Connected(), qt.Equals, true)
}
func TestVoltage(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_BUSVOLTAGE] = 0x2570
bus.AddDevice(fake)
dev := New(bus)
// Datasheet: 2570h = 11.98V = 11980mV = 11980000uV
c.Assert(dev.Voltage(), qt.Equals, int32(11980000))
}
func TestCurrent(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_CURRENT] = 0x2710
bus.AddDevice(fake)
dev := New(bus)
// Datasheet: 2710h = 12.5A = 12500mA = 12500000uA
c.Assert(dev.Current(), qt.Equals, int32(12500000))
}
func TestPower(t *testing.T) {
c := qt.New(t)
bus := tester.NewI2CBus(c)
fake := tester.NewI2CDevice16(c, Address)
fake.Registers = defaultRegisters()
fake.Registers[REG_POWER] = 0x3A7F
bus.AddDevice(fake)
dev := New(bus)
// 3A7Fh = 149.75W = 149750mW = 149750000uW
c.Assert(dev.Power(), qt.Equals, int32(149750000))
}
// defaultRegisters returns the default values for all of the device's registers.
// set TI INA260 datasheet for power-on defaults
func defaultRegisters() map[uint8]uint16 {
return map[uint8]uint16{
REG_CONFIG: 0x6127,
REG_CURRENT: 0x0000,
REG_BUSVOLTAGE: 0x0000,
REG_POWER: 0x0000,
REG_MASKENABLE: 0x0000,
REG_ALERTLIMIT: 0x0000,
REG_MANF_ID: 0x5449,
REG_DIE_ID: 0x2270,
}
}
+50
View File
@@ -0,0 +1,50 @@
package ina260
// The default I2C address for this device.
//
// The actual address is configurable by connecting address pins.
const Address = 0x40
// Registers
const (
REG_CONFIG = 0x00
REG_CURRENT = 0x01
REG_BUSVOLTAGE = 0x02
REG_POWER = 0x03
REG_MASKENABLE = 0x06
REG_ALERTLIMIT = 0x07
REG_MANF_ID = 0xFE
REG_DIE_ID = 0xFF
)
// Well-Known Values
const (
MANF_ID = 0x5449 // TI
DEVICE_ID = 0x2270 // 227h
DEVICE_ID_MASK = 0xFFF0
AVGMODE_1 = 0
AVGMODE_4 = 1
AVGMODE_16 = 2
AVGMODE_64 = 3
AVGMODE_128 = 4
AVGMODE_256 = 5
AVGMODE_512 = 6
AVGMODE_1024 = 7
CONVTIME_140USEC = 0
CONVTIME_204USEC = 1
CONVTIME_332USEC = 2
CONVTIME_588USEC = 3
CONVTIME_1100USEC = 4 // 1.1 ms
CONVTIME_2116USEC = 5 // 2.1 ms
CONVTIME_4156USEC = 6 // 4.2 ms
CONVTIME_8244USEC = 7 // 8.2 ms
MODE_CONTINUOUS = 0x4
MODE_TRIGGERED = 0x0
MODE_VOLTAGE = 0x2
MODE_NO_VOLTAGE = 0x0
MODE_CURRENT = 0x1
MODE_NO_CURRENT = 0x0
)
+107
View File
@@ -0,0 +1,107 @@
package keypad4x4
import (
"machine"
)
// NoKeyPressed is used, when no key was pressed
const NoKeyPressed = 255
// Device is used as 4x4 keypad driver
type Device interface {
Configure()
GetKey() uint8
GetIndices() (int, int)
}
// device is a driver for 4x4 keypads
type device struct {
inputEnabled bool
lastColumn int
lastRow int
columns [4]machine.Pin
rows [4]machine.Pin
mapping [4][4]uint8
}
// takes r4 -r1 pins and c4 - c1 pins
func NewDevice(r4, r3, r2, r1, c4, c3, c2, c1 machine.Pin) Device {
result := &device{}
result.columns = [4]machine.Pin{c4, c3, c2, c1}
result.rows = [4]machine.Pin{r4, r3, r2, r1}
return result
}
// Configure sets the column pins as input and the row pins as output
func (keypad *device) Configure() {
inputConfig := machine.PinConfig{Mode: machine.PinInputPullup}
for i := range keypad.columns {
keypad.columns[i].Configure(inputConfig)
}
outputConfig := machine.PinConfig{Mode: machine.PinOutput}
for i := range keypad.rows {
keypad.rows[i].Configure(outputConfig)
keypad.rows[i].High()
}
keypad.mapping = [4][4]uint8{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
{12, 13, 14, 15},
}
keypad.inputEnabled = true
keypad.lastColumn = -1
keypad.lastRow = -1
}
// GetKey returns the code for the given key.
// The codes start with 0 at the upper left end of the keypad and end with 15 at the lower right end of the keypad
// Example:
// 0 1 2 3
// 4 5 6 7
// 8 9 10 11
// 12 13 14 15
// returns 255 for no keyPressed
func (keypad *device) GetKey() uint8 {
row, column := keypad.GetIndices()
if row == -1 && column == -1 {
return NoKeyPressed
}
return keypad.mapping[row][column]
}
// GetIndices returns the position of the pressed key
func (keypad *device) GetIndices() (int, int) {
for rowIndex, rowPin := range keypad.rows {
rowPin.Low()
for columnIndex := range keypad.columns {
columnPin := keypad.columns[columnIndex]
if !columnPin.Get() && keypad.inputEnabled {
keypad.inputEnabled = false
keypad.lastColumn = columnIndex
keypad.lastRow = rowIndex
return keypad.lastRow, keypad.lastColumn
}
if columnPin.Get() &&
columnIndex == keypad.lastColumn &&
rowIndex == keypad.lastRow &&
!keypad.inputEnabled {
keypad.inputEnabled = true
}
}
rowPin.High()
}
return -1, -1
}
+38 -16
View File
@@ -56,49 +56,71 @@ func (d *Device) Stop() {
d.en.Low()
}
// PWM is the interface necessary for controlling the motor driver.
type PWM interface {
Configure(config machine.PWMConfig) error
Channel(pin machine.Pin) (channel uint8, err error)
Top() uint32
Set(channel uint8, value uint32)
SetPeriod(period uint64) error
}
// PWMDevice is a motor with speed control.
// a1 and a2 are the directional GPIO pins.
// en is the PWM pin that controls the motor speed.
type PWMDevice struct {
a1, a2 machine.Pin
en machine.PWM
spc uint8
pwm PWM
}
// NewWithSpeed returns a new PWMMotor driver that uses a PWM pin to control speed.
func NewWithSpeed(direction1, direction2 machine.Pin, speedPin machine.PWM) PWMDevice {
// NewWithSpeed returns a new PWMMotor driver that uses an already configured PWM channel
// to control speed.
func NewWithSpeed(direction1, direction2 machine.Pin, spc uint8, pwm PWM) PWMDevice {
return PWMDevice{
a1: direction1,
a2: direction2,
en: speedPin,
a1: direction1,
a2: direction2,
spc: spc,
pwm: pwm,
}
}
// Configure configures the PWMDevice.
func (d *PWMDevice) Configure() {
// Configure configures the PWMDevice. Note that the PWM interface and
// channel must already be configured, this function will not do it for you.
func (d *PWMDevice) Configure() error {
d.a1.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.a2.Configure(machine.PinConfig{Mode: machine.PinOutput})
d.en.Configure()
d.Stop()
return nil
}
// Forward turns motor on in forward direction at specific speed.
func (d *PWMDevice) Forward(speed uint16) {
// Forward turns motor on in forward direction at specific speed as a percentage.
func (d *PWMDevice) Forward(speed uint32) {
if speed > 100 {
speed = 100
}
d.a1.High()
d.a2.Low()
d.en.Set(speed)
d.pwm.Set(d.spc, d.pwm.Top()*speed/100)
}
// Backward turns motor on in backward direction at specific speed.
func (d *PWMDevice) Backward(speed uint16) {
// Backward turns motor on in backward direction at specific speed as a percentage.
func (d *PWMDevice) Backward(speed uint32) {
if speed > 100 {
speed = 100
}
d.a1.Low()
d.a2.High()
d.en.Set(speed)
d.pwm.Set(d.spc, d.pwm.Top()*speed/100)
}
// Stop turns motor off.
func (d *PWMDevice) Stop() {
d.a1.Low()
d.a2.Low()
d.en.Set(0)
d.pwm.Set(d.spc, 0)
}
+29 -19
View File
@@ -49,42 +49,52 @@ func (d *Device) Stop() {
d.ib.Low()
}
// PWM is the interface necessary for controlling the motor driver.
type PWM interface {
Configure(config machine.PWMConfig) error
Channel(pin machine.Pin) (channel uint8, err error)
Top() uint32
Set(channel uint8, value uint32)
SetPeriod(period uint64) error
}
// PWMDevice is a motor with speed control.
// ia and ib are the directional/speed PWM pins.
type PWMDevice struct {
ia, ib machine.PWM
pwm PWM
ca, cb uint8
}
// NewWithSpeed returns a new PWMMotor driver that uses 2 PWM pins to control both direction and speed.
func NewWithSpeed(direction1, direction2 machine.PWM) PWMDevice {
func NewWithSpeed(ca, cb uint8, pwm PWM) PWMDevice {
return PWMDevice{
ia: direction1,
ib: direction2,
pwm: pwm,
ca: ca,
cb: cb,
}
}
// Configure configures the PWMDevice.
func (d *PWMDevice) Configure() {
d.ia.Configure()
d.ib.Configure()
// Configure configures the PWMDevice. Note that the pins, PWM interface,
// and channels must all already be configured.
func (d *PWMDevice) Configure() (err error) {
d.Stop()
return
}
// Forward turns motor on in forward direction at specific speed.
func (d *PWMDevice) Forward(speed uint16) {
d.ia.Set(speed)
d.ib.Set(0)
// Forward turns motor on in forward direction at specific speed as a percentage.
func (d *PWMDevice) Forward(speed uint32) {
d.pwm.Set(d.ca, d.pwm.Top()*speed/100)
d.pwm.Set(d.cb, 0)
}
// Backward turns motor on in backward direction at specific speed.
func (d *PWMDevice) Backward(speed uint16) {
d.ia.Set(0)
d.ib.Set(speed)
// Backward turns motor on in backward direction at specific speed as a percentage.
func (d *PWMDevice) Backward(speed uint32) {
d.pwm.Set(d.ca, 0)
d.pwm.Set(d.cb, d.pwm.Top()*speed/100)
}
// Stop turns motor off.
func (d *PWMDevice) Stop() {
d.ia.Set(0)
d.ib.Set(0)
d.pwm.Set(d.ca, 0)
d.pwm.Set(d.cb, 0)
}
+85
View File
@@ -0,0 +1,85 @@
// Driver works for max7219 and 7221
// Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf
package max72xx
import (
"machine"
)
type Device struct {
bus machine.SPI
cs machine.Pin
}
// NewDriver creates a new max7219 connection. The SPI wire must already be configured
// The SPI frequency must not be higher than 10MHz.
// parameter cs: the datasheet also refers to this pin as "load" pin.
func NewDevice(bus machine.SPI, cs machine.Pin) *Device {
return &Device{
bus: bus,
cs: cs,
}
}
// Configure setups the pins.
func (driver *Device) Configure() {
outPutConfig := machine.PinConfig{Mode: machine.PinOutput}
driver.cs.Configure(outPutConfig)
}
// SetScanLimit sets the scan limit. Maximum is 8.
// Example: a 4 digit 7SegmentDisplay has a scan limit of 4
func (driver *Device) SetScanLimit(digitNumber uint8) {
driver.WriteCommand(byte(REG_SCANLIMIT), byte(digitNumber-1))
}
// SetDecodeMode sets the decode mode for 7 segment displays.
// digitNumber = 1 -> 1 digit gets decoded
// digitNumber = 2 or 3, or 4 -> 4 digit are being decoded
// digitNumber = 8 -> 8 digits are being decoded
// digitNumber 0 || digitNumber > 8 -> no decoding is being used
func (driver *Device) SetDecodeMode(digitNumber uint8) {
switch digitNumber {
case 1: // only decode first digit
driver.WriteCommand(REG_DECODE_MODE, 0x01)
case 2, 3, 4: // decode digits 3-0
driver.WriteCommand(REG_DECODE_MODE, 0x0F)
case 8: // decode 8 digits
driver.WriteCommand(REG_DECODE_MODE, 0xFF)
default:
driver.WriteCommand(REG_DECODE_MODE, 0x00)
}
}
// StartShutdownMode sets the IC into a low power shutdown mode.
func (driver *Device) StartShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x00)
}
// StartShutdownMode sets the IC into normal operation mode.
func (driver *Device) StopShutdownMode() {
driver.WriteCommand(REG_SHUTDOWN, 0x01)
}
// StartDisplayTest starts a display test.
func (driver *Device) StartDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x01)
}
// StopDisplayTest stops the display test and gets into normal operation mode.
func (driver *Device) StopDisplayTest() {
driver.WriteCommand(REG_DISPLAY_TEST, 0x00)
}
func (driver *Device) writeByte(data byte) {
driver.bus.Transfer(data)
}
// WriteCommand write data to a given register.
func (driver *Device) WriteCommand(register, data byte) {
driver.cs.Low()
driver.writeByte(register)
driver.writeByte(data)
driver.cs.High()
}
+18
View File
@@ -0,0 +1,18 @@
package max72xx
const (
REG_NOOP byte = 0x00
REG_DIGIT0 byte = 0x01
REG_DIGIT1 byte = 0x02
REG_DIGIT2 byte = 0x03
REG_DIGIT3 byte = 0x04
REG_DIGIT4 byte = 0x05
REG_DIGIT5 byte = 0x06
REG_DIGIT6 byte = 0x07
REG_DIGIT7 byte = 0x08
REG_DECODE_MODE byte = 0x09 // turn of for led matrix, turn on for digits
REG_INTENSITY byte = 0x0A
REG_SCANLIMIT byte = 0x0B
REG_SHUTDOWN byte = 0x0C // turn on for no shutdown mode
REG_DISPLAY_TEST byte = 0x0F // turn off for no display test
)
+1 -1
View File
@@ -211,7 +211,7 @@ func TestInitWithError(t *testing.T) {
c.Assert(dev, qt.IsNil)
}
func newDevice(bus *tester.I2CBus, addr uint8) *tester.I2CDevice {
func newDevice(bus *tester.I2CBus, addr uint8) *tester.I2CDevice8 {
fdev := bus.NewDevice(addr)
// IODIRA and IODIRB are all ones by default.
fdev.Registers[rIODIR] = 0xff
+786
View File
@@ -0,0 +1,786 @@
// Package mcp2515 implements a driver for the MCP2515 CAN Controller.
//
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Stand-Alone-CAN-Controller-with-SPI-20001801J.pdf
//
// Reference: https://github.com/coryjfowler/MCP_CAN_lib
package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
import (
"errors"
"fmt"
"machine"
"time"
"tinygo.org/x/drivers"
)
// Device wraps MCP2515 SPI CAN Module.
type Device struct {
spi SPI
cs machine.Pin
msg *CANMsg
mcpMode byte
}
// CANMsg stores CAN message fields.
type CANMsg struct {
ID uint32
Dlc uint8
Data []byte
Ext bool
Rtr bool
}
const (
bufferSize int = 64
)
// New returns a new MCP2515 driver. Pass in a fully configured SPI bus.
func New(b drivers.SPI, csPin machine.Pin) *Device {
d := &Device{
spi: SPI{
bus: b,
tx: make([]byte, 0, bufferSize),
rx: make([]byte, 0, bufferSize),
},
cs: csPin,
msg: &CANMsg{},
}
return d
}
// Configure sets up the device for communication.
func (d *Device) Configure() {
d.cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
}
const beginTimeoutValue int = 10
// Begin starts the CAN controller.
func (d *Device) Begin(speed byte, clock byte) error {
timeOutCount := 0
for {
err := d.init(speed, clock)
if err == nil {
break
}
timeOutCount++
if timeOutCount >= beginTimeoutValue {
return err
}
}
return nil
}
// Received returns true if CAN message is received.
func (d *Device) Received() bool {
res, err := d.readStatus()
if err != nil {
panic(err)
}
// if RX STATUS INSTRUCTION result is not 0x00 (= No RX message)
// TODO: reconsider this logic
return (res & mcpStatRxifMask) != 0x00
}
// Rx returns received CAN message.
func (d *Device) Rx() (*CANMsg, error) {
err := d.readMsg()
return d.msg, err
}
// Tx transmits CAN Message.
func (d *Device) Tx(canid uint32, dlc uint8, data []byte) error {
// TODO: add ext, rtrBit, waitSent
timeoutCount := 0
var bufNum, res uint8
var err error
res = mcpAlltxbusy
for res == mcpAlltxbusy && (timeoutCount < timeoutvalue) {
if timeoutCount > 0 {
time.Sleep(time.Microsecond * 10)
}
bufNum, res, err = d.getNextFreeTxBuf()
if err != nil {
return err
}
timeoutCount++
}
if timeoutCount == timeoutvalue {
return fmt.Errorf("Tx: Tx timeout")
}
err = d.writeCANMsg(bufNum, canid, 0, 0, dlc, data)
if err != nil {
return err
}
return nil
}
func (d *Device) init(speed, clock byte) error {
err := d.Reset()
if err != nil {
return err
}
if err := d.setCANCTRLMode(modeConfig); err != nil {
return fmt.Errorf("setCANCTRLMode %s: ", err)
}
time.Sleep(time.Millisecond * 10)
// set baudrate
if err := d.configRate(speed, clock); err != nil {
return fmt.Errorf("configRate %s: ", err)
}
time.Sleep(time.Millisecond * 10)
if err := d.initCANBuffers(); err != nil {
return fmt.Errorf("initCANBuffers: %s ", err)
}
if err := d.setRegister(mcpCANINTE, mcpRX0IF|mcpRX1IF); err != nil {
return fmt.Errorf("setRegister: %s ", err)
}
if err := d.modifyRegister(mcpRXB0CTRL, mcpRxbRxMask|mcpRxbBuktMask, mcpRxbRxStdExt|mcpRxbBuktMask); err != nil {
return fmt.Errorf("modifyRegister: %s ", err)
}
if err := d.modifyRegister(mcpRXB1CTRL, mcpRxbRxMask, mcpRxbRxStdExt); err != nil {
return fmt.Errorf("modifyRegister: %s ", err)
}
if err := d.setMode(modeNormal); err != nil {
return fmt.Errorf("setMode %s: ", err)
}
time.Sleep(time.Millisecond * 10)
return nil
}
// Reset resets mcp2515.
func (d *Device) Reset() error {
d.cs.Low()
_, err := d.spi.readWrite(mcpReset)
d.cs.High()
// time.Sleep(time.Microsecond * 4)
if err != nil {
return err
}
time.Sleep(time.Millisecond * 10)
return nil
}
func (d *Device) setCANCTRLMode(newMode byte) error {
// If the chip is asleep and we want to change mode then a manual wake needs to be done
// This is done by setting the wake up interrupt flag
// This undocumented trick was found at https://github.com/mkleemann/can/blob/master/can_sleep_mcp2515.c
m, err := d.getMode()
if err != nil {
return err
}
if m == modeSleep && newMode != modeSleep {
r, err := d.readRegister(mcpCANINTE)
if err != nil {
return err
}
wakeIntEnabled := (r & mcpWAKIF) == 0x00
if !wakeIntEnabled {
d.modifyRegister(mcpCANINTE, mcpWAKIF, mcpWAKIF)
}
// Set wake flag (this does the actual waking up)
d.modifyRegister(mcpCANINTF, mcpWAKIF, mcpWAKIF)
// Wait for the chip to exit SLEEP and enter LISTENONLY mode.
// If the chip is not connected to a CAN bus (or the bus has no other powered nodes) it will sometimes trigger the wake interrupt as soon
// as it's put to sleep, but it will stay in SLEEP mode instead of automatically switching to LISTENONLY mode.
// In this situation the mode needs to be manually set to LISTENONLY.
if err := d.requestNewMode(modeListenOnly); err != nil {
return err
}
// Turn wake interrupt back off if it was originally off
if !wakeIntEnabled {
d.modifyRegister(mcpCANINTE, mcpWAKIF, 0)
}
}
// Clear wake flag
d.modifyRegister(mcpCANINTF, mcpWAKIF, 0)
return d.requestNewMode(newMode)
}
func (d *Device) setMode(opMode byte) error {
if opMode != modeSleep {
d.mcpMode = opMode
}
err := d.setCANCTRLMode(opMode)
if err != nil {
return err
}
return nil
}
func (d *Device) getMode() (byte, error) {
r, err := d.readRegister(mcpCANSTAT)
if err != nil {
return 0, err
}
return r & modeMask, nil
}
func (d *Device) configRate(speed, clock byte) error {
// TODO: add another baudrate
var cfg1, cfg2, cfg3 byte
set := true
switch clock {
case Clock16MHz:
switch speed {
case CAN500kBps:
cfg1 = mcp16mHz500kBpsCfg1
cfg2 = mcp16mHz500kBpsCfg2
cfg3 = mcp16mHz500kBpsCfg3
case CAN1000kBps:
cfg1 = mcp16mHz1000kBpsCfg1
cfg2 = mcp16mHz1000kBpsCfg2
cfg3 = mcp16mHz1000kBpsCfg3
default:
set = false
}
case Clock8MHz:
switch speed {
case CAN500kBps:
cfg1 = mcp8mHz500kBpsCfg1
cfg2 = mcp8mHz500kBpsCfg2
cfg3 = mcp8mHz500kBpsCfg3
case CAN1000kBps:
cfg1 = mcp8mHz1000kBpsCfg1
cfg2 = mcp8mHz1000kBpsCfg2
cfg3 = mcp8mHz1000kBpsCfg3
default:
set = false
}
default:
set = false
}
if !set {
return errors.New("invalid parameter")
}
if err := d.setRegister(mcpCNF1, cfg1); err != nil {
return err
}
if err := d.setRegister(mcpCNF2, cfg2); err != nil {
return err
}
if err := d.setRegister(mcpCNF3, cfg3); err != nil {
return err
}
return nil
}
func (d *Device) initCANBuffers() error {
a1 := byte(mcpTXB0CTRL)
a2 := byte(mcpTXB1CTRL)
a3 := byte(mcpTXB2CTRL)
for i := 0; i < 14; i++ {
if err := d.setRegister(a1, 0); err != nil {
return err
}
if err := d.setRegister(a2, 0); err != nil {
return err
}
if err := d.setRegister(a3, 0); err != nil {
return err
}
a1++
a2++
a3++
}
if err := d.setRegister(mcpRXB0CTRL, 0); err != nil {
return err
}
if err := d.setRegister(mcpRXB1CTRL, 0); err != nil {
return err
}
return nil
}
func (d *Device) readMsg() error {
status, err := d.readRxTxStatus()
if err != nil {
return err
}
if (status & mcpRX0IF) == 0x01 {
err := d.readRxBuffer(mcpReadRx0)
if err != nil {
return err
}
} else if (status & mcpRX1IF) == 0x02 {
err := d.readRxBuffer(mcpReadRx1)
if err != nil {
return err
}
} else {
return fmt.Errorf("readMsg: nothing is received")
}
return nil
}
func (d *Device) readRxBuffer(loadAddr uint8) error {
msg := d.msg
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(loadAddr)
if err != nil {
return err
}
err = d.spi.read(4)
if err != nil {
return err
}
buf := d.spi.rx
msg.ID = uint32((uint32(buf[0]) << 3) + (uint32(buf[1]) >> 5))
msg.Ext = false
if (buf[1] & mcpTxbExideM) == mcpTxbExideM {
// extended id
msg.ID = uint32(uint32(msg.ID<<2) + uint32(buf[1]&0x03))
msg.ID = uint32(uint32(msg.ID<<8) + uint32(buf[2]))
msg.ID = uint32(uint32(msg.ID<<8) + uint32(buf[3]))
msg.Ext = true
}
err = d.spi.read(1)
if err != nil {
return err
}
msgSize := d.spi.rx[0]
msg.Dlc = uint8(msgSize & mcpDlcMask)
msg.Rtr = false
if (msgSize & mcpRtrMask) == 0x40 {
msg.Rtr = true
}
readLen := uint8(canMaxCharInMessage)
if msg.Dlc < canMaxCharInMessage {
readLen = msg.Dlc
}
err = d.spi.read(int(readLen))
if err != nil {
return err
}
msg.Data = d.spi.rx
return err
}
func (d *Device) getNextFreeTxBuf() (uint8, uint8, error) {
status, err := d.readStatus()
if err != nil {
return 0, mcpAlltxbusy, err
}
status &= mcpStatTxPendingMask
bufNum := uint8(0x00)
if status == mcpStatTxPendingMask {
return 0, mcpAlltxbusy, nil
}
for i := 0; i < int(mcpNTxbuffers-nReservedTx(0)); i++ {
if (status & txStatusPendingFlag(uint8(i))) == 0 {
bufNum = txCtrlReg(uint8(i)) + 1
d.modifyRegister(mcpCANINTF, txIfFlag(uint8(i)), 0)
return bufNum, mcp2515Ok, nil
}
}
return 0, mcpAlltxbusy, nil
}
func (d *Device) writeCANMsg(bufNum uint8, canid uint32, ext, rtrBit, dlc uint8, data []byte) error {
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(txSidhToLoad(bufNum))
if err != nil {
return err
}
err = d.spi.clearBuffer(tx)
if err != nil {
return err
}
err = d.spi.setTxBufData(canid, ext, rtrBit, dlc, data)
if err != nil {
return err
}
err = d.spi.write()
if err != nil {
return err
}
// Since cs.Low and cs.High are executed in d.startTransmission,
// it is necessary to set cs.High once to separate the instruction of mcp2515.
d.cs.High()
err = d.startTransmission(bufNum)
if err != nil {
return err
}
return nil
}
func (s *SPI) setTxBufData(canid uint32, ext, rtrBit, dlc uint8, data []byte) error {
canid = canid & 0x0FFFF
if ext == 1 {
// TODO: add Extended ID
err := s.setTxData(0)
if err != nil {
return err
}
err = s.setTxData(0)
if err != nil {
return err
}
err = s.setTxData(0)
if err != nil {
return err
}
err = s.setTxData(0)
if err != nil {
return err
}
} else {
err := s.setTxData(byte(canid >> 3))
if err != nil {
return err
}
err = s.setTxData(byte((canid & 0x07) << 5))
if err != nil {
return err
}
err = s.setTxData(0)
if err != nil {
return err
}
err = s.setTxData(0)
if err != nil {
return err
}
}
if rtrBit == 1 {
dlc |= mcpRtrMask
} else {
dlc |= (0)
}
err := s.setTxData(dlc)
if err != nil {
return err
}
for _, d := range data {
err := s.setTxData(d)
if err != nil {
return err
}
}
return nil
}
func (d *Device) startTransmission(bufNum uint8) error {
d.cs.Low()
_, err := d.spi.readWrite(txSidhToRTS(bufNum))
d.cs.High()
if err != nil {
return err
}
return nil
}
func nReservedTx(number uint8) uint8 {
if number < mcpNTxbuffers {
return number
}
return mcpNTxbuffers - 1
}
func txStatusPendingFlag(i uint8) uint8 {
ret := uint8(0)
switch i {
case 0:
ret = mcpStatTx0Pending
case 1:
ret = mcpStatTx1Pending
case 2:
ret = mcpStatTx2Pending
}
return ret
}
func txCtrlReg(status uint8) uint8 {
ret := uint8(0)
switch status {
case 0:
ret = mcpTXB0CTRL
case 1:
ret = mcpTXB1CTRL
case 2:
ret = mcpTXB2CTRL
}
return ret
}
func txIfFlag(i uint8) uint8 {
ret := uint8(0)
switch i {
case 0:
ret = mcpTX0IF
case 1:
ret = mcpTX1IF
case 2:
ret = mcpTX2IF
}
return ret
}
func txSidhToSidh(i uint8) uint8 {
ret := uint8(0)
switch i {
case mcpTX0IF:
ret = mcpTXB0SIDH
case mcpTX1IF:
ret = mcpTXB1SIDH
case mcpTX2IF:
ret = mcpTXB2SIDH
}
return ret
}
func txSidhToRTS(i uint8) uint8 {
ret := uint8(0)
switch i {
case mcpTXB0SIDH:
ret = mcpRtsTx0
case mcpTXB1SIDH:
ret = mcpRtsTx1
case mcpTXB2SIDH:
ret = mcpRtsTx2
}
return ret
}
func txSidhToLoad(i uint8) uint8 {
ret := uint8(0)
switch i {
case mcpTXB0SIDH:
ret = mcpLoadTx0
case mcpTXB1SIDH:
ret = mcpLoadTx1
case mcpTXB2SIDH:
ret = mcpLoadTx2
}
return ret
}
func (d *Device) setRegister(addr, value byte) error {
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(mcpWrite)
if err != nil {
return err
}
_, err = d.spi.readWrite(addr)
if err != nil {
return err
}
_, err = d.spi.readWrite(value)
if err != nil {
return err
}
// time.Sleep(time.Microsecond * 4)
return nil
}
func (d *Device) readRegister(addr byte) (byte, error) {
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(mcpRead)
if err != nil {
return 0, err
}
_, err = d.spi.readWrite(addr)
if err != nil {
return 0, err
}
err = d.spi.read(1)
if err != nil {
return 0, err
}
// time.Sleep(time.Microsecond * 4)
return d.spi.rx[0], nil
}
func (d *Device) modifyRegister(addr, mask, data byte) error {
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(mcpBitMod)
if err != nil {
return err
}
_, err = d.spi.readWrite(addr)
if err != nil {
return err
}
_, err = d.spi.readWrite(mask)
if err != nil {
return err
}
_, err = d.spi.readWrite(data)
if err != nil {
return err
}
// time.Sleep(time.Microsecond * 4)
return nil
}
func (d *Device) requestNewMode(newMode byte) error {
s := time.Now()
for {
err := d.modifyRegister(mcpCANCTRL, modeMask, newMode)
if err != nil {
return err
}
r, err := d.readRegister(mcpCANSTAT)
if err != nil {
return err
}
if r&modeMask == newMode {
return nil
} else if e := time.Now(); e.Sub(s) > 200*time.Millisecond {
return errors.New("requestNewMode max time expired")
}
}
}
func (d *Device) readStatus() (byte, error) {
d.cs.Low()
defer d.cs.High()
_, err := d.spi.readWrite(mcpReadStatus)
if err != nil {
return 0, err
}
err = d.spi.read(1)
if err != nil {
return 0, err
}
return d.spi.rx[0], nil
}
func (d *Device) readRxTxStatus() (byte, error) {
status, err := d.readStatus()
if err != nil {
return 0, err
}
ret := status & (mcpStatTxifMask | mcpStatRxifMask)
if (status & mcpStatTx0if) == 0x08 {
ret |= mcpTX0IF
}
if (status & mcpStatTx1if) == 0x20 {
ret |= mcpTX1IF
}
if (status & mcpStatTx2if) == 0x80 {
ret |= mcpTX2IF
}
ret |= ret & mcpStatRxifMask
return ret, nil
}
type SPI struct {
bus drivers.SPI
tx []byte
rx []byte
}
const (
tx = iota
rx
)
func (s *SPI) readWrite(w byte) (byte, error) {
return s.bus.Transfer(w)
}
func (s *SPI) read(readLength int) error {
err := s.clearBuffer(rx)
if err != nil {
return err
}
err = s.setBufferLength(readLength, rx)
if err != nil {
return err
}
return s.bus.Tx(nil, s.rx)
}
func (s *SPI) write() error {
return s.bus.Tx(s.tx, nil)
}
func (s *SPI) clearBuffer(dir int) error { return s.setBufferLength(0, dir) }
func (s *SPI) setBufferLength(length int, dir int) error {
if dir == tx {
if length > cap(s.tx) {
return fmt.Errorf("length is longer than capacity")
}
s.tx = s.tx[:length]
} else if dir == rx {
if length > cap(s.rx) {
return fmt.Errorf("length is longer than capacity")
}
s.rx = s.rx[:length]
} else {
return fmt.Errorf("invalid direction")
}
return nil
}
func (s *SPI) setTxData(data byte) error {
if len(s.tx) >= bufferSize {
return fmt.Errorf("cannot expand buffer (to avoid memory allocation)")
}
s.tx = append(s.tx, data)
return nil
}
func (d *Device) dumpMode() error {
m, err := d.getMode()
if err != nil {
return err
}
fmt.Printf("Mode: %02X\r\n", m)
return nil
}
func (d *Device) dumpRegister(addr byte) error {
r, err := d.readRegister(addr)
if err != nil {
return err
}
fmt.Printf("Register: %02X = %02X\r\n", addr, r)
return nil
}
+421
View File
@@ -0,0 +1,421 @@
// Package mcp2515 implements a driver for the MCP2515 CAN Controller.
//
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/MCP2515-Stand-Alone-CAN-Controller-with-SPI-20001801J.pdf
//
package mcp2515 // import "tinygo.org/x/drivers/mcp2515"
const DebugEn = 0
const (
// begin mt
timeoutvalue = 50
mcpSidh = 0
mcpSidl = 1
mcpEid8 = 2
mcpEid0 = 3
mcpTxbExideM = 0x08 // in txbnsidl
mcpDlcMask = 0x0f //= 4 lsbits
mcpRtrMask = 0x40 // =(1<=<6) bit= 6
mcpRxbRxAny = 0x60
mcpRxbRxExt = 0x40
mcpRxbRxStd = 0x20
mcpRxbRxStdExt = 0x00
mcpRxbRxMask = 0x60
mcpRxbBuktMask = 1 << 2
// bits in the txbnctrl registers.
mcpTxbTxbufeM = 0x80
mcpTxbAbtfM = 0x40
mcpTxbMloaM = 0x20
mcpTxbTxerrM = 0x10
mcpTxbTxreqM = 0x08
mcpTxbTxieM = 0x04
mcpTxbTxp10M = 0x03
mcpTxbRtrM = 0x40 // in txbndlc
mcpRxbIdeM = 0x08 // in rxbnsidl
mcpRxbRtrM = 0x40 // in rxbndlc
mcpStatTxPendingMask = 0x54
mcpStatTx0Pending = 0x04
mcpStatTx1Pending = 0x10
mcpStatTx2Pending = 0x40
mcpStatTxifMask = 0xa8
mcpStatTx0if = 0x08
mcpStatTx1if = 0x20
mcpStatTx2if = 0x80
mcpStatRxifMask = 0x03
mcpStatRx0if = 1 << 0
mcpStatRx1if = 1 << 1
mcpEflgRx1ovr = 1 << 7
mcpEflgRx0ovr = 1 << 6
mcpEflgTxbo = 1 << 5
mcpEflgTxep = 1 << 4
mcpEflgRxep = 1 << 3
mcpEflgTxwar = 1 << 2
mcpEflgRxwar = 1 << 1
mcpEflgEwarn = 1 << 0
mcpEflgErrormask = 0xf8 //= 5 ms-bits
// define mcp2515 register addresses
mcpRXF0SIDH = 0x00
mcpRXF0SIDL = 0x01
mcpRXF0EID8 = 0x02
mcpRXF0EID0 = 0x03
mcpRXF1SIDH = 0x04
mcpRXF1SIDL = 0x05
mcpRXF1EID8 = 0x06
mcpRXF1EID0 = 0x07
mcpRXF2SIDH = 0x08
mcpRXF2SIDL = 0x09
mcpRXF2EID8 = 0x0a
mcpRXF2EID0 = 0x0b
mcpBFPCTRL = 0x0c
mcpTXRTSCTRl = 0x0d
mcpCANSTAT = 0x0e
mcpCANCTRL = 0x0f
mcpRXF3SIDH = 0x10
mcpRXF3SIDL = 0x11
mcpRXF3EID8 = 0x12
mcpRXF3EID0 = 0x13
mcpRXF4SIDH = 0x14
mcpRXF4SIDL = 0x15
mcpRXF4EID8 = 0x16
mcpRXF4EID0 = 0x17
mcpRXF5SIDH = 0x18
mcpRXF5SIDL = 0x19
mcpRXF5EID8 = 0x1a
mcpRXF5EID0 = 0x1b
mcpTEC = 0x1c
mcpREC = 0x1d
mcpRXM0SIDH = 0x20
mcpRXM0SIDL = 0x21
mcpRXM0EID8 = 0x22
mcpRXM0EID0 = 0x23
mcpRXM1SIDH = 0x24
mcpRXM1SIDL = 0x25
mcpRXM1EID8 = 0x26
mcpRXM1EID0 = 0x27
mcpCNF3 = 0x28
mcpCNF2 = 0x29
mcpCNF1 = 0x2a
mcpCANINTE = 0x2b
mcpCANINTF = 0x2c
mcpEFLG = 0x2d
mcpTXB0CTRL = 0x30
mcpTXB0SIDH = 0x31
mcpTXB1CTRL = 0x40
mcpTXB1SIDH = 0x41
mcpTXB2CTRL = 0x50
mcpTXB2SIDH = 0x51
mcpRXB0CTRL = 0x60
mcpRXB0SIDH = 0x61
mcpRXB1CTRL = 0x70
mcpRXB1SIDH = 0x71
mcpTxInt = 0x1c // enable all transmit interrup ts
mcpTx01Int = 0x0c // enable txb0 and txb1 interru pts
mcpRxInt = 0x03 // enable receive interrupts
mcpNoInt = 0x00 // disable all interrupts
mcpTx01Mask = 0x14
mcpTxMask = 0x54
// define spi instruction set
mcpWrite = 0x02
mcpRead = 0x03
mcpBitMod = 0x05
mcpLoadTx0 = 0x40
mcpLoadTx1 = 0x42
mcpLoadTx2 = 0x44
mcpRtsTx0 = 0x81
mcpRtsTx1 = 0x82
mcpRtsTx2 = 0x84
mcpRtsAll = 0x87
mcpReadRx0 = 0x90
mcpReadRx1 = 0x94
mcpReadStatus = 0xa0
mcpRxStatus = 0xb0
mcpReset = 0xc0
// canctrl register values
modeNormal = 0x00
modeSleep = 0x20
modeLoopBack = 0x40
modeListenOnly = 0x60
modeConfig = 0x80
modePowerUp = 0xe0
modeMask = 0xe0
abortTx = 0x10
modeOneShot = 0x08
clkoutEnable = 0x04
clkoutDisable = 0x00
clkoutPs1 = 0x00
clkoutPs2 = 0x01
clkoutPs4 = 0x02
clkoutPs8 = 0x03
// cnf1 register values
sjw1 = 0x00
sjw2 = 0x40
sjw3 = 0x80
sjw4 = 0xc0
// cnf2 register values
btlmode = 0x80
sample1x = 0x00
sample3x = 0x40
// cnf3 register values
sofEnable = 0x80
sofDisable = 0x00
wakfilEnable = 0x40
wakfilDisable = 0x00
// canintf register bits
mcpRX0IF = 0x01
mcpRX1IF = 0x02
mcpTX0IF = 0x04
mcpTX1IF = 0x08
mcpTX2IF = 0x10
mcpERRIF = 0x20
mcpWAKIF = 0x40
mcpMERRF = 0x80
// bfpctrl register bits
b1bfs = 0x20
b0bfs = 0x10
b1bfe = 0x08
b0bfe = 0x04
b1bfm = 0x02
b0bfm = 0x01
// txrtctrl register bits
b2rts = 0x20
b1rts = 0x10
b0rts = 0x08
b2rtsm = 0x04
b1rtsm = 0x02
b0rtsm = 0x01
// clock
Clock16MHz = 1
Clock8MHz = 2
// speed= 16m
mcp16mHz1000kBpsCfg1 = 0x00
mcp16mHz1000kBpsCfg2 = 0xd0
mcp16mHz1000kBpsCfg3 = 0x82
mcp16mHz500kBpsCfg1 = 0x00
mcp16mHz500kBpsCfg2 = 0xf0
mcp16mHz500kBpsCfg3 = 0x86
mcp16mHz250kBpsCfg1 = 0x41
mcp16mHz250kBpsCfg2 = 0xf1
mcp16mHz250kBpsCfg3 = 0x85
mcp16mHz200kBpsCfg1 = 0x01
mcp16mHz200kBpsCfg2 = 0xfa
mcp16mHz200kBpsCfg3 = 0x87
mcp16mHz125kBpsCfg1 = 0x03
mcp16mHz125kBpsCfg2 = 0xf0
mcp16mHz125kBpsCfg3 = 0x86
mcp16mHz100kBpsCfg1 = 0x03
mcp16mHz100kBpsCfg2 = 0xfa
mcp16mHz100kBpsCfg3 = 0x87
mcp16mHz95kBpsCfg1 = 0x03
mcp16mHz95kBpsCfg2 = 0xad
mcp16mHz95kBpsCfg3 = 0x07
mcp16mHz83k3BpsCfg1 = 0x03
mcp16mHz83k3BpsCfg2 = 0xbe
mcp16mHz83k3BpsCfg3 = 0x07
mcp16mHz80kBpsCfg1 = 0x03
mcp16mHz80kBpsCfg2 = 0xff
mcp16mHz80kBpsCfg3 = 0x87
mcp16mHz50kBpsCfg1 = 0x07
mcp16mHz50kBpsCfg2 = 0xfa
mcp16mHz50kBpsCfg3 = 0x87
mcp16mHz40kBpsCfg1 = 0x07
mcp16mHz40kBpsCfg2 = 0xff
mcp16mHz40kBpsCfg3 = 0x87
mcp16mHz33kBpsCfg1 = 0x09
mcp16mHz33kBpsCfg2 = 0xbe
mcp16mHz33kBpsCfg3 = 0x07
mcp16mHz31k25BpsCfg1 = 0x0f
mcp16mHz31k25BpsCfg2 = 0xf1
mcp16mHz31k25BpsCfg3 = 0x85
mcp16mHz25kBpsCfg1 = 0x0f
mcp16mHz25kBpsCfg2 = 0xba
mcp16mHz25kBpsCfg3 = 0x07
mcp16mHz20kBpsCfg1 = 0x0f
mcp16mHz20kBpsCfg2 = 0xff
mcp16mHz20kBpsCfg3 = 0x87
mcp16mHz10kBpsCfg1 = 0x1f
mcp16mHz10kBpsCfg2 = 0xff
mcp16mHz10kBpsCfg3 = 0x87
mcp16mHz5kBpsCfg1 = 0x3f
mcp16mHz5kBpsCfg2 = 0xff
mcp16mHz5kBpsCfg3 = 0x87
mcp16mHz666kBpsCfg1 = 0x00
mcp16mHz666kBpsCfg2 = 0xa0
mcp16mHz666kBpsCfg3 = 0x04
// speed= 8m
mcp8mHz1000kBpsCfg1 = 0x00
mcp8mHz1000kBpsCfg2 = 0x80
mcp8mHz1000kBpsCfg3 = 0x00
mcp8mHz500kBpsCfg1 = 0x00
mcp8mHz500kBpsCfg2 = 0x90
mcp8mHz500kBpsCfg3 = 0x02
mcp8mHz250kBpsCfg1 = 0x00
mcp8mHz250kBpsCfg2 = 0xb1
mcp8mHz250kBpsCfg3 = 0x05
mcp8mHz200kBpsCfg1 = 0x00
mcp8mHz200kBpsCfg2 = 0xb4
mcp8mHz200kBpsCfg3 = 0x06
mcp8mHz125kBpsCfg1 = 0x01
mcp8mHz125kBpsCfg2 = 0xb1
mcp8mHz125kBpsCfg3 = 0x05
mcp8mHz100kBpsCfg1 = 0x01
mcp8mHz100kBpsCfg2 = 0xb4
mcp8mHz100kBpsCfg3 = 0x06
mcp8mHz80kBpsCfg1 = 0x01
mcp8mHz80kBpsCfg2 = 0xbf
mcp8mHz80kBpsCfg3 = 0x07
mcp8mHz50kBpsCfg1 = 0x03
mcp8mHz50kBpsCfg2 = 0xb4
mcp8mHz50kBpsCfg3 = 0x06
mcp8mHz40kBpsCfg1 = 0x03
mcp8mHz40kBpsCfg2 = 0xbf
mcp8mHz40kBpsCfg3 = 0x07
mcp8mHz31k25BpsCfg1 = 0x07
mcp8mHz31k25BpsCfg2 = 0xa4
mcp8mHz31k25BpsCfg3 = 0x04
mcp8mHz20kBpsCfg1 = 0x07
mcp8mHz20kBpsCfg2 = 0xbf
mcp8mHz20kBpsCfg3 = 0x07
mcp8mHz10kBpsCfg1 = 0x0f
mcp8mHz10kBpsCfg2 = 0xbf
mcp8mHz10kBpsCfg3 = 0x07
mcp8mHz5kBpsCfg1 = 0x1f
mcp8mHz5kBpsCfg2 = 0xbf
mcp8mHz5kBpsCfg3 = 0x07
mcp16mHz47kBpsCfg1 = 0x06
mcp16mHz47kBpsCfg2 = 0xbe
mcp16mHz47kBpsCfg3 = 0x07
mcpdebug = 0
mcpdebugTxbuf = 0
mcpNTxbuffers = 3
mcpRxbuf0 = 0x61
mcpRxbuf1 = 0x71
mcp2515Ok = 0
mcp2515Fail = 1
mcpAlltxbusy = 2
candebug = 1
canuseloop = 0
cansendtimeout = 200 // milliseconds
mcpPinHiz = 0
mcpPinInt = 1
mcpPinOut = 2
mcpPinIn = 3
mcpRx0bf = 0
mcpRx1bf = 1
mcpTx0rts = 2
mcpTx1rts = 3
mcpTx2rts = 4
// initial value of gcanautoprocess
canautoprocess = 1
canautoon = 1
canautooff = 0
canStdid = 0
canExtid = 1
candefaultident = 0x55cc
candefaultidentext = 1
CAN5kBps = 1
CAN10kBps = 2
CAN20kBps = 3
CAN25kBps = 4
CAN31k25Bps = 5
CAN33kBps = 6
CAN40kBps = 7
CAN50kBps = 8
CAN80kBps = 9
CAN83k3Bps = 10
CAN95kBps = 11
CAN100kBps = 12
CAN125kBps = 13
CAN200kBps = 14
CAN250kBps = 15
CAN500kBps = 16
CAN666kBps = 17
CAN1000kBps = 18
CAN47kBps = 19
canOk = 0
canFailinit = 1
canFailtx = 2
canMsgavail = 3
canNomsg = 4
canCtrlerror = 5
canGettxbftimeout = 6
canSendmsgtimeout = 7
canFail = 0xff
canMaxCharInMessage = 8
)
+6 -2
View File
@@ -4,6 +4,7 @@ package tls
import (
"strconv"
"strings"
"tinygo.org/x/drivers/net"
)
@@ -17,14 +18,17 @@ func Dial(network, address string, config *Config) (*net.TCPSerialConn, error) {
return nil, err
}
addr := raddr.IP.String()
hostname := strings.Split(address, ":")[0]
sendport := strconv.Itoa(raddr.Port)
if sendport == "0" {
sendport = "443"
}
// disconnect any old socket
net.ActiveDevice.DisconnectSocket()
// connect new socket
err = net.ActiveDevice.ConnectSSLSocket(addr, sendport)
err = net.ActiveDevice.ConnectSSLSocket(hostname, sendport)
if err != nil {
return nil, err
}
+157
View File
@@ -0,0 +1,157 @@
package p1am
//go:generate go run ./internal/cmd/gen_defines
type ModuleProps struct {
ModuleID uint32
DI, DO, AI, AO, Status, Config, DataSize byte
Name string
}
var modules = []ModuleProps{
//{0x000000ID,di,do,ai,ao,st,cf,ds}
{0x00000000, 0, 0, 0, 0, 0, 0, 0, "Empty"}, //Empty first entry for defaultgs
{0x04A00081, 1, 0, 0, 0, 0, 0, 1, "P1-08ND3"}, //P1-08ND3
{0x04A00085, 1, 0, 0, 0, 0, 0, 1, "P1-08NA"}, //P1-08NA
{0x04A00087, 1, 0, 0, 0, 0, 0, 1, "P1-08SIM"}, //P1-08SIM
{0x04A00088, 1, 0, 0, 0, 0, 0, 1, "P1-08NE3"}, //P1-08NE3
{0x05200082, 2, 0, 0, 0, 0, 0, 1, "P1-16ND3"}, //P1-16ND3
{0x05200089, 2, 0, 0, 0, 0, 0, 1, "P1-16NE3"}, //P1-16NE3
{0x1403F481, 0, 0, 0, 32, 4, 4, 0xA0, "P1-04PWM"}, //P1-04PWM
{0x1404008D, 0, 1, 0, 0, 0, 0, 1, "P1-08TA"}, //P1-08TA
{0x1404008F, 0, 1, 0, 0, 0, 0, 1, "P1-08TRS"}, //P1-08TRS
{0x14040091, 0, 2, 0, 0, 0, 0, 1, "P1-16TR"}, //P1-16TR
{0x14050081, 0, 1, 0, 0, 0, 0, 1, "P1-08TD1"}, //P1-08TD1
{0x14050082, 0, 1, 0, 0, 0, 0, 1, "P1-08TD2"}, //P1-08TD2
{0x14080085, 0, 2, 0, 0, 0, 0, 1, "P1-15TD1"}, //P1-15TD1
{0x14080086, 0, 2, 0, 0, 0, 0, 1, "P1-15TD2"}, //P1-15TD2
{0x24A50081, 1, 1, 0, 0, 0, 0, 1, "P1-16CDR"}, //P1-16CDR
{0x24A50082, 1, 1, 0, 0, 0, 0, 1, "P1-15CDD1"}, //P1-15CDD1
{0x24A50083, 1, 1, 0, 0, 0, 0, 1, "P1-15CDD2"}, //P1-15CDD2
{0x34605581, 0, 0, 16, 0, 12, 18, 16, "P1-04AD"}, //P1-04AD
{0x34605588, 0, 0, 16, 0, 12, 8, 16, "P1-04RTD"}, //P1-04RTD
{0x3460558F, 0, 0, 16, 0, 12, 2, 12, "P1-04ADL-1"}, //P1-04ADL-1
{0x34605590, 0, 0, 16, 0, 12, 2, 12, "P1-04ADL-2"}, //P1-04ADL-2
{0x34608C81, 0, 0, 16, 0, 12, 20, 32, "P1-04THM"}, //P1-04THM
{0x34608C8E, 0, 0, 16, 0, 12, 8, 32, "P1-04NTC"}, //P1-04NTC
{0x34A0558A, 0, 0, 32, 0, 12, 2, 12, "P1-08ADL-1"}, //P1-08ADL-1
{0x34A0558B, 0, 0, 32, 0, 12, 2, 12, "P1-08ADL-2"}, //P1-08ADL-2
{0x34A5A481, 2, 0, 36, 36, 4, 12, 0xC0, "P1-02HSC"}, //P1-02HSC
{0x44035583, 0, 0, 0, 16, 4, 0, 12, "P1-04DAL-1"}, //P1-04DAL-1
{0x44035584, 0, 0, 0, 16, 4, 0, 12, "P1-04DAL-2"}, //P1-04DAL-2
{0x44055588, 0, 0, 0, 32, 4, 0, 12, "P1-08DAL-1"}, //P1-08DAL-1
{0x44055589, 0, 0, 0, 32, 4, 0, 12, "P1-08DAL-2"}, //P1-08DAL-2
{0x5461A783, 0, 0, 16, 8, 12, 2, 12, "P1-4ADL2DAL-1"}, //P1-4ADL2DAL-1
{0x5461A784, 0, 0, 16, 8, 12, 2, 12, "P1-4ADL2DAL-2"}, //P1-4ADL2DAL-2
{0xFFFFFFFF, 0, 0, 0, 0, 0, 0, 0, "BAD SLOT"}, //empty in case no modules are defined.
{0x00000000, 0, 0, 0, 0, 0, 0, 0, "BAD SLOT"}, //empty in case no modules are defined.
}
var defaultConfig = map[uint32][]byte{
0x34605590:// P1_04ADL_2_DEFAULT_CONFIG
{0x40, 0x03},
0x34608C8E: // P1_04NTC_DEFAULT_CONFIG
{0x40, 0x03, 0x60, 0x05,
0x20, 0x00, 0x80, 0x02},
0x34608C81: // P1_04THM_DEFAULT_CONFIG
{0x40, 0x03, 0x60, 0x05,
0x21, 0x00, 0x22, 0x00,
0x23, 0x00, 0x24, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00},
0x34605588: // P1_04RTD_DEFAULT_CONFIG
{0x40, 0x03, 0x60, 0x05,
0x20, 0x01, 0x80, 0x00},
0x34605581: // P1_04AD_DEFAULT_CONFIG
{0x40, 0x03, 0x00, 0x00,
0x20, 0x03, 0x00, 0x00,
0x21, 0x03, 0x00, 0x00,
0x22, 0x03, 0x00, 0x00,
0x23, 0x03},
0x3460558F:// P1_04ADL_1_DEFAULT_CONFIG
{0x40, 0x03},
0x34A0558A:// P1_08ADL_1_DEFAULT_CONFIG
{0x40, 0x07},
0x34A0558B:// P1_08ADL_2_DEFAULT_CONFIG
{0x40, 0x07},
0x5461A783:// P1_04ADL2DAL_1_DEFAULT_CONFIG
{0x40, 0x03},
0x5461A784:// P1_04ADL2DAL_2_DEFAULT_CONFIG
{0x40, 0x03},
0x1403F481:// P1_04PWM_DEFAULT_CONFIG
{0x02, 0x02, 0x02, 0x02},
0x34A5A481: // P1_02HSC_DEFAULT_CONFIG
{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01},
}
const NUMBER_OF_MODULES = 15 //Current max 15 Modules
const SWITCH_BUILTIN = 31
const baseEnable = 33
const MOD_HDR = 0x02
const VERSION_HDR = 0x03
const ACTIVE_HDR = 0x04
const DROPOUT_HDR = 0x05
const CFG_HDR = 0x10
const READ_CFG_HDR = 0x11
const PETWD_HDR = 0x30
const STARTWD_HDR = 0x31
const STOPWD_HDR = 0x32
const CONFIGWD_HDR = 0x33
const READ_STATUS_HDR = 0x40
const READ_DISCRETE_HDR = 0x50
const READ_ANALOG_HDR = 0x51
const READ_BLOCK_HDR = 0x52
const WRITE_DISCRETE_HDR = 0x60
const WRITE_ANALOG_HDR = 0x61
const WRITE_BLOCK_HDR = 0x62
const FW_UPDATE_HDR = 0xAA
const DUMMY = 0xFF
const EMPTY_SLOT_ID = 0xFFFFFFFE
const MAX_TIMEOUT = 0xFFFFFFFF
const DISCRETE_IN_BLOCK = 0
const ANALOG_IN_BLOCK = 1
const DISCRETE_OUT_BLOCK = 2
const ANALOG_OUT_BLOCK = 3
const STATUS_IN_BLOCK = 4
const MISSING24V_STATUS = 3
const BURNOUT_STATUS = 5
const UNDER_RANGE_STATUS = 7
const OVER_RANGE_STATUS = 11
const TOGGLE = 0x01
const HOLD = 0x00
+133
View File
@@ -0,0 +1,133 @@
package main
import (
"bytes"
"go/format"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
)
var tmpl = template.Must(template.New("main").Parse(`package p1am
//go:generate go run ./internal/cmd/gen_defines
type ModuleProps struct {
ModuleID uint32
DI, DO, AI, AO, Status, Config, DataSize byte
Name string
}
var modules = []ModuleProps{
{{.MDB -}}
}
var defaultConfig = map[uint32][]byte{
{{range .Configs -}}
0x{{.ID}}: // {{.Name}}
{{index $.DefaultConfigs .Name}},
{{end}}
}
{{range .Defines}}
const {{.Name}} = {{.Value}}{{.Comment -}}
{{end}}
`))
func findLibrary() string {
home, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
for _, dir := range []string{
"Documents/Arduino",
"Arduino",
} {
dir = filepath.Join(home, dir, "libraries/P1AM/src")
if _, err := os.Stat(dir); err == nil {
return dir
}
}
return ""
}
func definitions(path string, delim string) []string {
data, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}
return strings.Split(string(data), delim)
}
var (
mdbRE = regexp.MustCompile(`(?s)mdb\[\] = \{\s*(.+)\}`)
configRE = regexp.MustCompile(`(?s)const char (.*?)\[\] = (.+)`)
caseRE = regexp.MustCompile(`(?s)case 0x([^:]+):\s+return \(char\*\)(.+)`)
defineRE = regexp.MustCompile(`(?ms)^\s*#define (\S+)\s+(\d+|0x[0-9a-fA-F]+)(\s+.*?)?\s*$`)
)
func main() {
base := findLibrary()
if base == "" {
log.Fatal("can't find Arduino library")
}
var data = struct {
MDB string
DefaultConfigs map[string]string
Configs []struct {
ID string
Name string
}
Defines []struct {
Name string
Value string
Comment string
}
}{
DefaultConfigs: make(map[string]string),
}
for _, line := range definitions(filepath.Join(base, "Module_List.h"), ";") {
if matches := mdbRE.FindStringSubmatch(line); matches != nil {
data.MDB = regexp.MustCompile(`}\s*//`).ReplaceAllString(matches[1], `}, //`)
}
if matches := configRE.FindStringSubmatch(line); matches != nil {
data.DefaultConfigs[matches[1]] = matches[2]
}
}
for _, line := range definitions(filepath.Join(base, "P1AM.cpp"), ";") {
if matches := caseRE.FindStringSubmatch(line); matches != nil {
data.Configs = append(data.Configs, struct{ ID, Name string }{
ID: matches[1],
Name: matches[2],
})
}
}
for _, line := range definitions(filepath.Join(base, "defines.h"), "\n") {
if matches := defineRE.FindStringSubmatch(line); matches != nil {
data.Defines = append(data.Defines, struct{ Name, Value, Comment string }{
Name: matches[1],
Value: matches[2],
Comment: matches[3],
})
}
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, &data); err != nil {
log.Fatal(err)
}
formatted, err := format.Source(buf.Bytes())
if err != nil {
log.Printf("failed to compile %s", buf.Bytes())
log.Fatal(err)
}
if err := ioutil.WriteFile("defines.go", formatted, 0666); err != nil {
log.Fatal(err)
}
}
+429
View File
@@ -0,0 +1,429 @@
// Driver for the P1AM-100 base controller.
//
// This is an embedded device on the P1AM-100 board.
// Based on v1.0.1 of the Arduino library: https://github.com/facts-engineering/P1AM/tree/1.0.1
package p1am
import (
"encoding/binary"
"errors"
"fmt"
"machine"
"time"
)
type P1AM struct {
bus machine.SPI
slaveSelectPin, slaveAckPin, baseEnablePin machine.Pin
// SkipAutoConfig will skip loading a default configuration into each module.
SkipAutoConfig bool
Slots int
// Access slots via Slot()
slots []Slot
}
var Controller = P1AM{
bus: machine.SPI0,
slaveSelectPin: machine.BASE_SLAVE_SELECT_PIN,
slaveAckPin: machine.BASE_SLAVE_ACK_PIN,
baseEnablePin: machine.BASE_ENABLE_PIN,
}
type baseSlotConstants struct {
DI, DO, AI, AO, Status, Config, DataSize byte
}
func (p *P1AM) Initialize() error {
p.slaveSelectPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
p.slaveAckPin.Configure(machine.PinConfig{Mode: machine.PinInput})
p.baseEnablePin.Configure(machine.PinConfig{Mode: machine.PinOutput})
if err := p.bus.Configure(machine.SPIConfig{
Frequency: 1000000,
Mode: 2,
LSBFirst: false,
}); err != nil {
return err
}
p.SetEnabled(true)
time.Sleep(100 * time.Millisecond)
if err := p.waitAck(5 * time.Second); err != nil {
return errors.New("no base controller activity; check external supply connection")
}
for i := 0; i < 5; i++ {
if err := p.handleHDR(MOD_HDR); err == nil {
time.Sleep(5 * time.Millisecond)
slots, err := p.spiSendRecvByte(0xFF)
if err == nil && slots > 0 && slots <= 15 {
p.Slots = int(slots)
break
}
}
if i > 2 {
// Try restarting the base controller
p.SetEnabled(false)
time.Sleep(10 * time.Millisecond)
p.SetEnabled(true)
time.Sleep(10 * time.Millisecond)
}
}
if p.Slots <= 0 || p.Slots > 15 {
return errors.New("zero modules in the base")
}
moduleIDs := make([]uint32, p.Slots)
p.waitAck(200 * time.Millisecond)
if err := binary.Read(p, binary.LittleEndian, &moduleIDs); err != nil {
return err
}
baseConstants := make([]baseSlotConstants, p.Slots)
p.slots = make([]Slot, p.Slots)
for i := 1; i <= p.Slots; i++ {
slot := p.Slot(i)
slot.p = p
slot.slot = byte(i)
slot.ID = moduleIDs[i-1]
// What if 0xFFFFFFFF isn't at position -2?
slot.Props = &modules[len(modules)-2]
for j := 0; j < len(modules); j++ {
if modules[j].ModuleID == slot.ID {
slot.Props = &modules[j]
}
bc := &baseConstants[i-1]
bc.DI = slot.Props.DI
bc.DO = slot.Props.DO
bc.AI = slot.Props.AI
bc.AO = slot.Props.AO
bc.Status = slot.Props.Status
bc.Config = slot.Props.Config
bc.DataSize = slot.Props.DataSize
}
}
p.waitAck(200 * time.Millisecond)
if err := binary.Write(p, binary.LittleEndian, &baseConstants); err != nil {
return err
}
if !p.SkipAutoConfig {
for i := 1; i <= p.Slots; i++ {
s := p.Slot(i)
if s.Props.Config > 0 {
cfg := defaultConfig[s.ID]
if cfg != nil {
s.Configure(cfg)
}
}
}
}
return nil
}
func (p *P1AM) Version() ([3]byte, error) {
if err := p.handleHDR(VERSION_HDR); err != nil {
return [3]byte{}, err
}
var buf [4]byte
if err := p.spiSendRecvBuf(nil, buf[:]); err != nil {
return [3]byte{}, err
}
return [3]byte{
byte(buf[1] >> 4),
byte(buf[1] & 0xF),
byte(buf[0]),
}, p.dataSync()
}
func (p *P1AM) Active() (bool, error) {
if _, err := p.spiSendRecvByte(ACTIVE_HDR); err != nil {
return false, err
}
if err := p.waitAck(200 * time.Millisecond); err != nil {
return false, err
}
buf, err := p.spiSendRecvByte(DUMMY)
defer p.dataSync()
return buf != 0, err
}
const wdToggleTime = 100 * time.Millisecond
func (p *P1AM) ConfigureWatchdog(interval time.Duration, reset bool) error {
ms := interval / time.Millisecond
toggleMs := wdToggleTime / time.Millisecond
resetB := byte(0)
if reset {
resetB = 1
}
buf := [6]byte{
CONFIGWD_HDR,
byte(ms),
byte(ms >> 8),
byte(toggleMs),
byte(toggleMs >> 8),
resetB,
}
if err := p.spiSendRecvBuf(buf[:], nil); err != nil {
return err
}
return p.dataSync()
}
func (p *P1AM) sendWatchdog(hdr byte) error {
if _, err := p.spiSendRecvByte(hdr); err != nil {
return err
}
if err := p.waitAck(200 * time.Millisecond); err != nil {
return err
}
if _, err := p.spiSendRecvByte(DUMMY); err != nil {
return err
}
return p.dataSync()
}
func (p *P1AM) StartWatchdog() error {
return p.sendWatchdog(STARTWD_HDR)
}
func (p *P1AM) StopWatchdog() error {
return p.sendWatchdog(STOPWD_HDR)
}
func (p *P1AM) PetWatchdog() error {
return p.sendWatchdog(PETWD_HDR)
}
func (p *P1AM) Slot(i int) *Slot {
if i < 1 || i > p.Slots {
return nil
}
return &p.slots[i-1]
}
type Slot struct {
p *P1AM
slot byte
ID uint32
// TODO: Embed this?
Props *ModuleProps
}
func (s *Slot) Configure(data []byte) error {
if s == nil {
return errors.New("invalid slot")
}
if len(data) != int(s.Props.Config) {
return fmt.Errorf("expected %d config bytes, got %d", s.Props.Config, len(data))
}
if len(data) == 0 {
return errors.New("no config bytes")
}
out := make([]byte, len(data)+2)
out[0] = CFG_HDR
out[1] = s.slot
copy(out[2:], data)
if err := s.p.spiSendRecvBuf(out, nil); err != nil {
return err
}
time.Sleep(100 * time.Millisecond)
s.p.dataSync()
s.p.dataSync()
return nil
}
func (s *Slot) ReadDiscrete() (uint32, error) {
if s == nil {
return 0, errors.New("invalid slot")
}
bytes := s.Props.DI
out := [2]byte{
READ_DISCRETE_HDR,
s.slot,
}
if err := s.p.spiSendRecvBuf(out[:], nil); err != nil {
return 0, err
}
if err := s.p.waitAck(200 * time.Millisecond); err != nil {
return 0, err
}
var data [4]byte
if err := s.p.spiSendRecvBuf(nil, data[:bytes]); err != nil {
return 0, err
}
err := s.p.dataSync()
return binary.LittleEndian.Uint32(data[:]), err
}
func (s *Slot) WriteDiscrete(value uint32) error {
return s.writeDiscrete(0, value)
}
func (s *Slot) writeDiscrete(channel byte, value uint32) error {
if s == nil {
return errors.New("invalid slot")
}
bytes := s.Props.DO
buf := [7]byte{
WRITE_DISCRETE_HDR,
s.slot,
channel,
}
binary.LittleEndian.PutUint32(buf[3:], value)
out := buf[:3+bytes]
if channel != 0 {
out = buf[:4]
out[3] &= 1
}
if err := s.p.spiSendRecvBuf(out, nil); err != nil {
return err
}
return s.p.dataSync()
}
type Channel struct {
s *Slot
channel int
}
func (s *Slot) Channel(channel int) Channel {
return Channel{
s: s,
channel: channel,
}
}
func (c Channel) ReadDiscrete() (bool, error) {
if c.channel < 1 || c.channel > int(c.s.Props.DI)*8 {
return false, errors.New("invalid channel")
}
data, err := c.s.ReadDiscrete()
return (data>>(c.channel-1))&1 == 1, err
}
func (c Channel) WriteDiscrete(value bool) error {
if c.channel < 1 || c.channel > int(c.s.Props.DO)*8 {
return errors.New("invalid channel")
}
data := uint32(0)
if value {
data = 1
}
return c.s.writeDiscrete(byte(c.channel), data)
}
const ackTimeout = 200 * time.Millisecond
func awaitPin(pin machine.Pin, state bool, timeout time.Duration) bool {
start := time.Now()
for pin.Get() != state {
time.Sleep(100 * time.Microsecond)
if time.Since(start) > timeout {
return false
}
}
return true
// TODO: Use channels when https://github.com/tinygo-org/tinygo/pull/1402 is merged.
// edge := machine.PinRising
// if state {
// edge = machine.PinFalling
// }
// ch := make(chan struct{}, 1)
// defer close(ch)
// pin.SetInterrupt(edge, func(machine.Pin) {
// ch <- struct{}{}
// })
// defer pin.SetInterrupt(0, nil)
// select {
// case <-ch:
// return true
// case <-time.After(timeout):
// return false
// }
}
var dataSyncErr = errors.New("base sync timeout")
func (p *P1AM) dataSync() error {
if !awaitPin(p.slaveAckPin, true, ackTimeout) {
return dataSyncErr
}
time.Sleep(time.Microsecond)
if !awaitPin(p.slaveAckPin, false, ackTimeout) {
return dataSyncErr
}
time.Sleep(time.Microsecond)
if !awaitPin(p.slaveAckPin, true, ackTimeout) {
return dataSyncErr
}
time.Sleep(time.Microsecond)
return nil
}
func (p *P1AM) handleHDR(HDR byte) error {
for !p.slaveAckPin.Get() {
}
if _, err := p.spiSendRecvByte(HDR); err != nil {
return err
}
return p.spiTimeout(MAX_TIMEOUT*time.Millisecond, HDR, 2*time.Second)
}
func (p *P1AM) Read(data []byte) (int, error) {
return len(data), p.spiSendRecvBuf(nil, data)
}
func (p *P1AM) Write(data []byte) (int, error) {
return len(data), p.spiSendRecvBuf(data, nil)
}
func (p *P1AM) spiSendRecvBuf(w, r []byte) error {
p.slaveSelectPin.Low()
defer p.slaveSelectPin.High()
return p.bus.Tx(w, r)
}
func (p *P1AM) spiSendRecvByte(data byte) (byte, error) {
p.slaveSelectPin.Low()
defer p.slaveSelectPin.High()
return p.bus.Transfer(data)
}
func (p *P1AM) waitAck(timeout time.Duration) error {
return p.spiTimeout(timeout, 0, 0)
}
var timeoutErr = errors.New("timeout")
func (p *P1AM) spiTimeout(timeout time.Duration, resendMsg byte, retryPeriod time.Duration) error {
end := time.Now().Add(timeout)
retry := time.Now().Add(retryPeriod)
for time.Now().Before(end) {
if p.slaveAckPin.Get() {
time.Sleep(50 * time.Microsecond)
return nil
}
if retryPeriod > 0 && time.Now().After(retry) {
p.spiSendRecvByte(resendMsg)
retry = retry.Add(retryPeriod)
}
}
return timeoutErr
}
func (p *P1AM) SetEnabled(enabled bool) {
p.baseEnablePin.Set(enabled)
}
+252
View File
@@ -0,0 +1,252 @@
// Package pcf8563 implements a driver for the PCF8563 CMOS Real-Time Clock (RTC)
//
// Datasheet: https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf
//
package pcf8563
import (
"time"
"tinygo.org/x/drivers"
)
// Device wraps an I2C connection to a PCF8563 device.
type Device struct {
bus drivers.I2C
Address uint16
}
// New creates a new PCF8563 connection. I2C bus must be already configured.
func New(i2c drivers.I2C) Device {
return Device{
bus: i2c,
Address: PCF8563_ADDR,
}
}
// Reset resets the `control and status registers`. When this method is
// called, it writes `0x00` to the `control and status registers`. This will
// cause `Alarm` and `Timer` to become Inactive. Please refer to the datasheet
// for details.
func (d *Device) Reset() (err error) {
return d.bus.Tx(d.Address, []byte{0x00, 0x00, 0x00}, nil)
}
// SetTime sets the time and date
func (d *Device) SetTime(t time.Time) error {
var buf [9]byte
buf[0] = 0x02
buf[1] = decToBcd(t.Second())
buf[2] = decToBcd(t.Minute())
buf[3] = decToBcd(t.Hour())
buf[4] = decToBcd(t.Day())
buf[5] = decToBcd(int(t.Weekday() + 1))
buf[6] = decToBcd(int(t.Month()))
buf[7] = decToBcd(t.Year() - 2000)
err := d.bus.Tx(d.Address, buf[:], nil)
return err
}
// ReadTime returns the date and time
func (d *Device) ReadTime() (time.Time, error) {
var buf [9]byte
err := d.bus.Tx(d.Address, []byte{0x00}, buf[:])
if err != nil {
return time.Time{}, err
}
seconds := bcdToDec(buf[2] & 0x7F)
minute := bcdToDec(buf[3] % 0x7F)
hour := bcdToDec(buf[4] & 0x3F)
day := bcdToDec(buf[5] & 0x3F)
month := time.Month(bcdToDec(buf[7] & 0x0F))
year := int(bcdToDec(buf[8])) + 2000
t := time.Date(year, month, day, hour, minute, seconds, 0, time.UTC)
return t, nil
}
// SetAlarm sets the alarm
func (d *Device) SetAlarm(t time.Time) error {
var buf [5]byte
buf[0] = 0x09
buf[1] = RTC_ALARM_ENABLE | decToBcd(t.Minute())
buf[2] = RTC_ALARM_ENABLE | decToBcd(t.Hour())
buf[3] = RTC_ALARM_ENABLE | decToBcd(t.Day())
buf[4] = RTC_ALARM_DISABLE
err := d.bus.Tx(d.Address, buf[:], nil)
if err != nil {
return err
}
// enable alarm
buf[0] = 0x01
err = d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] |= RTC_CTRL_AF
err = d.bus.Tx(d.Address, buf[:2], nil)
return err
}
// ClearAlarm disables alarm.
func (d *Device) ClearAlarm() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] &= ^uint8(RTC_CTRL_AF)
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// EnableAlarmInterrupt enables alarm interrupt. When triggered, INT pin (3)
// goes low.
func (d *Device) EnableAlarmInterrupt() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] |= RTC_CTRL_AIE
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// DisableAlarmInterrupt disable alarm interrupt.
func (d *Device) DisableAlarmInterrupt() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] &= ^uint8(RTC_CTRL_AIE)
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// AlarmTriggered returns whether or not an Alarm has been triggered.
func (d *Device) AlarmTriggered() bool {
var buf [1]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:], buf[:])
if err != nil {
return false
}
return (buf[0] & RTC_CTRL_AF) != 0
}
// SetTimer sets timer. The available durations are 1 to 127 seconds. If any
// other value is specified, it will be truncated.
func (d *Device) SetTimer(dur time.Duration) error {
var buf [3]byte
sec := dur / time.Second
if sec > 127 {
sec = 127
}
// Treat as sec timer.
buf[0] = 0x0E
buf[1] = RTC_TIMER_1S
buf[2] = byte(sec)
err := d.bus.Tx(d.Address, buf[:], nil)
if err != nil {
return err
}
// enable alarm
buf[0] = 0x01
err = d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] |= RTC_CTRL_TF
err = d.bus.Tx(d.Address, buf[:2], nil)
return err
}
// ClearTimer disables timer.
func (d *Device) ClearTimer() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] &= ^uint8(RTC_CTRL_TF)
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// EnableTimerInterrupt enables timer interrupt. When triggered, INT pin (3)
// goes low.
func (d *Device) EnableTimerInterrupt() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] |= RTC_CTRL_TIE
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// DisableTimerInterrupt disable timer interrupt.
func (d *Device) DisableTimerInterrupt() error {
var buf [2]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:1], buf[1:])
if err != nil {
return err
}
buf[1] &= ^uint8(RTC_CTRL_TIE)
err = d.bus.Tx(d.Address, buf[:], nil)
return err
}
// TimerTriggered returns whether or not an Alarm has been triggered.
func (d *Device) TimerTriggered() bool {
var buf [1]byte
buf[0] = 0x01
err := d.bus.Tx(d.Address, buf[:], buf[:])
if err != nil {
return false
}
return (buf[0] & RTC_CTRL_TF) != 0
}
// SetOscillatorFrequency sets output oscillator frequency
// Available modes: RTC_COT_DISABLE, RTC_COT_32KHZ, RTC_COT_1KHZ,
// RTC_COT_32Hz, RTC_COT_1HZ.
func (d *Device) SetOscillatorFrequency(sqw uint8) error {
var buf [2]byte
buf[0] = 0x0D
buf[1] = sqw
return d.bus.Tx(d.Address, buf[:], nil)
}
// decToBcd converts int to BCD
func decToBcd(dec int) uint8 {
return uint8(dec + 6*(dec/10))
}
// bcdToDec converts BCD to int
func bcdToDec(bcd uint8) int {
return int(bcd - 6*(bcd>>4))
}
+31
View File
@@ -0,0 +1,31 @@
package pcf8563
// Registers
const (
PCF8563_ADDR = 0x51 // R:A3 W:A2
I2C_SPEED_STANDARD = 100000
I2C_SPEED_DOUBLE = 200000
RTC_CTRL_STOP = 0x20
RTC_CTRL_TITP = 0x10
RTC_CTRL_AF = 0x08
RTC_CTRL_TF = 0x04
RTC_CTRL_AIE = 0x02
RTC_CTRL_TIE = 0x01
RTC_COT_DISABLE = 0x00
RTC_COT_32KHZ = 0x80
RTC_COT_1KHZ = 0x81
RTC_COT_32HZ = 0x82
RTC_COT_1HZ = 0x83
RTC_TIMER_DISABLE = 0x00
RTC_TIMER_4KHZ = 0x80
RTC_TIMER_64HZ = 0x81
RTC_TIMER_1S = 0x82
RTC_TIMER_60S = 0x83
RTC_ALARM_DISABLE = 0x80
RTC_ALARM_ENABLE = 0x00
)
+21
View File
@@ -0,0 +1,21 @@
# RTL8720DN Driver
This package provides a driver to use a separate connected WiFi processor `RTL8720DN` for TCP/UDP communication.
At this time, only part of TCP is supported.
## Using th RTL8720DN Driver
For now, it is only available for the `RTL8720DN` on `Wio Terminal`.
You can try the following command.
```
$ tinygo flash --target wioterminal --size short ./examples/rtl8720dn/webclient/
$ tinygo flash --target wioterminal --size short ./examples/rtl8720dn/tlsclient/
```
## RTL8720DN Firmware
Follow the steps below to update.
The firmware must be version 2.1.2 or later.
https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/
+35
View File
@@ -0,0 +1,35 @@
package rtl8720dn
// https://github.com/EmbeddedRPC/erpc/blob/develop/erpc_python/erpc/crc16.py
const (
crcStart = 0xEF4A
)
var table = [256]uint16{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0,
}
func computeCRC16(data []byte) uint16 {
crc := uint16(crcStart)
for _, d := range data {
crc = ((crc << 8) ^ table[((crc>>8)^uint16(d))&0xFF]) & 0xFFFF
}
return crc
}
+278
View File
@@ -0,0 +1,278 @@
package rtl8720dn
import (
"fmt"
"strconv"
)
// Here is the implementation of tinygo-org/x/drivers/net.DeviceDriver.
func (r *RTL8720DN) GetDNS(domain string) (string, error) {
if r.debug {
fmt.Printf("GetDNS(%q)\r\n", domain)
}
ipaddr := [4]byte{}
_, err := r.Rpc_netconn_gethostbyname(domain, ipaddr[:])
if err != nil {
return "", err
}
ret, err := fmt.Sprintf("%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]), nil
if r.debug {
fmt.Printf("-> %s\r\n", ret)
fmt.Printf("-> %02X.%02X.%02X.%02X\r\n", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3])
}
return ret, err
}
func (r *RTL8720DN) ConnectTCPSocket(addr, port string) error {
if r.debug {
fmt.Printf("ConnectTCPSocket(%q, %q)\r\n", addr, port)
}
ipaddr := [4]byte{}
_, err := r.Rpc_netconn_gethostbyname(addr, ipaddr[:])
if err != nil {
return err
}
portNum, err := strconv.ParseUint(port, 0, 0)
if err != nil {
return err
}
socket, err := r.Rpc_lwip_socket(0x02, 0x01, 0x00)
if err != nil {
return err
}
r.socket = socket
r.connectionType = ConnectionTypeTCP
_, err = r.Rpc_lwip_fcntl(socket, 0x00000003, 0x00000000)
if err != nil {
return err
}
_, err = r.Rpc_lwip_fcntl(socket, 0x00000004, 0x00000001)
if err != nil {
return err
}
name := []byte{0x00, 0x02, 0x00, 0x50, 0xC0, 0xA8, 0x01, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
name[2] = byte(portNum >> 8)
name[3] = byte(portNum)
name[4] = byte(ipaddr[0])
name[5] = byte(ipaddr[1])
name[6] = byte(ipaddr[2])
name[7] = byte(ipaddr[3])
_, err = r.Rpc_lwip_connect(socket, name, uint32(len(name)))
if err != nil {
return err
}
readset := []byte{}
writeset := []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
exceptset := []byte{}
timeout := []byte{}
_, err = r.Rpc_lwip_select(0x01, readset, writeset, exceptset, timeout)
if err != nil {
return err
}
optlen := uint32(4)
_, err = r.Rpc_lwip_getsockopt(socket, 0x00000FFF, 0x00001007, []byte{0xA5, 0xA5, 0xA5, 0xA5}, nil, optlen)
if err != nil {
return err
}
_, err = r.Rpc_lwip_fcntl(socket, 0x00000003, 0x00000000)
if err != nil {
return err
}
_, err = r.Rpc_lwip_fcntl(socket, 0x00000004, 0x00000000)
if err != nil {
return err
}
readset = []byte{}
writeset = []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
exceptset = []byte{}
timeout = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}
_, err = r.Rpc_lwip_select(0x01, readset, writeset, exceptset, timeout)
if err != nil {
return err
}
return nil
}
func (r *RTL8720DN) ConnectSSLSocket(addr, port string) error {
if r.debug {
fmt.Printf("ConnectSSLSocket(%q, %q)\r\n", addr, port)
}
client, err := r.Rpc_wifi_ssl_client_create()
if err != nil {
return err
}
r.client = client
r.connectionType = ConnectionTypeTLS
err = r.Rpc_wifi_ssl_init(client)
if err != nil {
return err
}
err = r.Rpc_wifi_ssl_set_timeout(client, 0x0001D4C0)
if err != nil {
return err
}
_, err = r.Rpc_wifi_ssl_set_rootCA(client, *r.root_ca)
if err != nil {
return err
}
// TODO: use port
_, err = r.Rpc_wifi_start_ssl_client(client, addr, 443, 0x0001D4C0)
if err != nil {
return err
}
_, err = r.Rpc_wifi_ssl_get_socket(client)
if err != nil {
return err
}
return nil
}
func (r *RTL8720DN) ConnectUDPSocket(addr, sendport, listenport string) error {
if r.debug {
fmt.Printf("ConnectUDPSocket(%q, %q, %q)\r\n", addr, sendport, listenport)
}
fmt.Printf("not implemented yet\r\n")
return nil
}
func (r *RTL8720DN) DisconnectSocket() error {
if r.debug {
fmt.Printf("DisconnectSocket()\r\n")
}
switch r.connectionType {
case ConnectionTypeTCP:
_, err := r.Rpc_lwip_close(r.socket)
if err != nil {
return err
}
case ConnectionTypeTLS:
err := r.Rpc_wifi_stop_ssl_socket(r.client)
if err != nil {
return err
}
err = r.Rpc_wifi_ssl_client_destroy(r.client)
if err != nil {
return err
}
default:
}
r.connectionType = ConnectionTypeNone
return nil
}
func (r *RTL8720DN) StartSocketSend(size int) error {
if r.debug {
fmt.Printf("StartSocketSend(%d)\r\n", size)
}
// No implementation required
return nil
}
func (r *RTL8720DN) Write(b []byte) (n int, err error) {
if r.debug {
fmt.Printf("Write(%#v)\r\n", b)
}
switch r.connectionType {
case ConnectionTypeTCP:
sn, err := r.Rpc_lwip_send(r.socket, b, 0x00000008)
if err != nil {
return 0, err
}
n = int(sn)
case ConnectionTypeTLS:
sn, err := r.Rpc_wifi_send_ssl_data(r.client, b, uint16(len(b)))
if err != nil {
return 0, err
}
n = int(sn)
default:
return 0, nil
}
return n, nil
}
func (r *RTL8720DN) ReadSocket(b []byte) (n int, err error) {
if r.debug {
//fmt.Printf("ReadSocket(b)\r\n")
}
if r.connectionType == ConnectionTypeNone {
return 0, nil
}
switch r.connectionType {
case ConnectionTypeTCP:
nn, err := r.Rpc_lwip_recv(r.socket, b, uint32(len(b)), 0x00000008, 0x00002800)
if err != nil {
return 0, err
}
if nn == -1 {
return 0, nil
} else if nn == 0 {
return 0, r.DisconnectSocket()
}
if r.length == 0 {
header := httpHeader(b[:nn])
r.length = header.ContentLength()
}
r.length -= int(nn)
if r.length == 0 {
return int(nn), r.DisconnectSocket()
}
n = int(nn)
case ConnectionTypeTLS:
nn, err := r.Rpc_wifi_get_ssl_receive(r.client, b, int32(len(b)))
if err != nil {
return 0, err
}
if nn < 0 {
return 0, fmt.Errorf("error %d", n)
} else if nn == 0 || nn == -30848 {
return 0, r.DisconnectSocket()
}
n = int(nn)
default:
}
return n, nil
}
func (r *RTL8720DN) IsSocketDataAvailable() bool {
if r.debug {
fmt.Printf("IsSocketDataAvailable()\r\n")
}
fmt.Printf("not implemented yet\r\n")
return true
}
func (r *RTL8720DN) Response(timeout int) ([]byte, error) {
if r.debug {
fmt.Printf("Response(%d))\r\n", timeout)
}
// No implementation required
return nil, nil
}
+9422
View File
File diff suppressed because it is too large Load Diff
+105
View File
@@ -0,0 +1,105 @@
package rtl8720dn
import (
"fmt"
"io"
"time"
)
var (
headerBuf [4]byte
readBuf [4]byte
startWriteMessageBuf [1024]byte
payload [1024 + 256]byte
)
const (
xVersion = 1
)
func startWriteMessage(msgType, service, requestNumber, sequence uint32) []byte {
startWriteMessageBuf[0] = byte(msgType)
startWriteMessageBuf[1] = byte(requestNumber)
startWriteMessageBuf[2] = byte(service)
startWriteMessageBuf[3] = byte(xVersion)
startWriteMessageBuf[4] = byte(sequence)
startWriteMessageBuf[5] = byte(sequence >> 8)
startWriteMessageBuf[6] = byte(sequence >> 16)
startWriteMessageBuf[7] = byte(sequence >> 24)
return startWriteMessageBuf[:8]
}
func (r *RTL8720DN) performRequest(msg []byte) error {
crc := computeCRC16(msg)
headerBuf[0] = byte(len(msg))
headerBuf[1] = byte(len(msg) >> 8)
headerBuf[2] = byte(crc)
headerBuf[3] = byte(crc >> 8)
if r.debug {
fmt.Printf("tx : %2d : ", len(headerBuf))
dumpHex(headerBuf[:])
fmt.Printf("\r\n")
}
r.port.Write(headerBuf[:])
if r.debug {
fmt.Printf("tx : %2d : ", len(msg))
dumpHex(msg)
fmt.Printf("\r\n")
}
r.port.Write(msg)
return nil
}
func dumpHex(b []byte) {
for i := range b {
if i == 0 {
fmt.Printf("%02X", b[i])
} else {
fmt.Printf(" %02X", b[i])
}
}
}
func (r *RTL8720DN) readThread() {
for {
n, _ := io.ReadFull(r.port, readBuf[:4])
if n == 0 {
continue
}
if r.debug {
fmt.Printf("rx : %2d : ", n)
dumpHex(readBuf[:n])
fmt.Printf("\r\n")
}
length := uint16(readBuf[0]) + uint16(readBuf[1])<<8
crc := uint16(readBuf[2]) + uint16(readBuf[3])<<8
n, _ = io.ReadFull(r.port, payload[:length])
if r.debug {
fmt.Printf("rx : %2d : ", length)
dumpHex(payload[0:n])
fmt.Printf("\r\n")
}
n = int(length)
crcNew := computeCRC16(payload[:n])
if g, e := crcNew, crc; g != e {
fmt.Printf("err CRC16: got %04X want %04X\n", g, e)
}
if payload[0] == 0x02 || payload[0] == 0x00 {
r.received <- true
// switch goroutine
time.Sleep(1)
}
}
}

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