Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added driver to decode signal from Silvan *1527 OTP encoder chips. #377

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
16 changes: 16 additions & 0 deletions examples/otp1527/main.go
Original file line number Diff line number Diff line change
@@ -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))
}
}
120 changes: 120 additions & 0 deletions otp1527/otp1527.go
Original file line number Diff line number Diff line change
@@ -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
}