From f7c9a128d69a06d6fbad0a520121ca72826e78f6 Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Wed, 16 Feb 2022 22:56:31 -0500 Subject: [PATCH] Added driver to decode signal from Silvan *1527 chips. --- Makefile | 4 +- examples/otp1527/main.go | 16 ++++++ otp1527/otp1527.go | 120 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 examples/otp1527/main.go create mode 100644 otp1527/otp1527.go diff --git a/Makefile b/Makefile index 6f14e8f2b..e63435d98 100644 --- a/Makefile +++ b/Makefile @@ -227,13 +227,15 @@ endif @md5sum ./build/test.hex tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/ssd1289/main.go @md5sum ./build/test.uf2 + tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/otp1527 + @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 keypad4x4 max72xx p1am tone tm1637 \ pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 xpt2046 \ - ft6336 sx126x ssd1289 + ft6336 sx126x ssd1289 otp1527 TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS)) unit-test: diff --git a/examples/otp1527/main.go b/examples/otp1527/main.go new file mode 100644 index 000000000..bcf65a15a --- /dev/null +++ b/examples/otp1527/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "machine" + + "tinygo.org/x/drivers/otp1527" +) + +func main() { + d := otp1527.NewDecoder(machine.Pin(3), -1) + for { + v := <-d.Out() + println(fmt.Sprintf("RECV: 0x%06x", v.Data)) + } +} diff --git a/otp1527/otp1527.go b/otp1527/otp1527.go new file mode 100644 index 000000000..320a55456 --- /dev/null +++ b/otp1527/otp1527.go @@ -0,0 +1,120 @@ +// Package otp1527 implements a driver to decode signal transmitted over 433MHz +// by various key fob, leak detectors, etc., which are based on Silvan OTP +// Encoder chips HS1527, EV1527, RT1527, or FP1527. +// See http://sc-tech.cn/en/hs1527.pdf for details. +// This package works with microcontrollers that support GPIO PinToggle interrupt. +// Check example under examples/otp1527 +// + +package otp1527 + +import ( + "machine" + "time" +) + +type Value struct { + Data uint32 // Received code + Period uint32 // Data clock (preamble time / 31) +} + +type OTP1527 struct { + Filter int // number of cycles to run signal debouncing (default 65) + PreambleClkMin int64 // data preamble minimal length (ns) to limit false positives (default 200000) + PreambleClkMax int64 // data preamble maximal length (ns) to limit false positives (default 600000) + pin machine.Pin + ch chan Value + time int64 + preambleClk int64 + timeHigh int64 + data uint32 + bits int + last bool +} + +// NewDecoder create driver to decode stream generated by HS1527 compatible source +// and deliver decoded data into output buffered channel of channelSize size. +// When channelSize set to -1, the size default to 32. +func NewDecoder(p machine.Pin, channelSize int) *OTP1527 { + if channelSize < 0 { + channelSize = 32 + } + d := OTP1527{pin: p, ch: make(chan Value, channelSize), Filter: 65, PreambleClkMin: 200000, PreambleClkMax: 600000} + d.pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) + if err := d.pin.SetInterrupt(machine.PinToggle, func(p machine.Pin) { + d.interrupt() + }); err != nil { + println("error:", err.Error()) + } + return &d +} + +// Out return output channel for decoded data. +func (d *OTP1527) Out() <-chan Value { + return d.ch +} + +func (d *OTP1527) interrupt() { + now := time.Now().UnixNano() + // filter signal + highCnt := 0 + for n := 0; n < d.Filter; n++ { + v := d.pin.Get() + if v { + highCnt++ + } else { + highCnt-- + } + } + pin := highCnt > 0 + // decode + if d.last != pin { + interval := now - d.time + if pin == true { + d.timeHigh = interval + } else { + if d.timeHigh > 0 && (d.preambleClk == 0 || (d.preambleClk > d.PreambleClkMin && d.preambleClk < d.PreambleClkMax)) { + switch { + case interval/d.timeHigh > 20: + // this is end of preamble + d.resetData() + d.preambleClk = interval / 31 + + case (interval+d.timeHigh) < d.preambleClk*5 && interval/d.timeHigh > 0: + // this is 0 + d.data = d.data << 1 + d.bits++ + // check for last data + if d.bits == 24 { + d.ch <- Value{Data: d.data, Period: uint32(d.preambleClk)} + d.resetData() + } + + case (interval+d.timeHigh) < d.preambleClk*5 && interval/d.timeHigh == 0: + // this is 1 + d.data = d.data<<1 | 1 + d.bits++ + // check for last data + if d.bits == 24 { + d.ch <- Value{Data: d.data, Period: uint32(d.preambleClk)} + d.resetData() + } + + default: + d.resetData() + } + } else { + d.resetData() + } + } + d.time = now + d.last = pin + } +} + +//go:inline +func (d *OTP1527) resetData() { + d.data = 0 + d.bits = 0 + d.preambleClk = 0 +}