Skip to content

Commit

Permalink
Added driver to decode signal from Silvan *1527 chips.
Browse files Browse the repository at this point in the history
  • Loading branch information
zdima committed Feb 20, 2022
1 parent 45dce18 commit f7c9a12
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 1 deletion.
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
}

0 comments on commit f7c9a12

Please sign in to comment.