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 17, 2022
1 parent 0ced126 commit 6df4abf
Showing 1 changed file with 128 additions and 0 deletions.
128 changes: 128 additions & 0 deletions otp1527/otp1527.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// 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.
//
// Example:
//
// package main
//
// import (
// "fmt"
// "machine"
//
// "tinygo.org/x/drivers/otp1527"
// )
//
// func main() {
// d := otp1527.NewDecoder(machine.Pin(3), 24, 0)
// for {
// select {
// case v := <-d.Out():
// println("RECV:", fmt.Sprintf("0x%02x", v))
// }
// }
// }
//

package otp1527

import "machine"

type OTP1527 struct {
pin machine.Pin
ch chan uint32
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 100.
func NewDecoder(p machine.Pin, channelSize int) *OTP1527 {
if channelSize < 0 {
channelSize = 100
}
d := OTP1527{pin: p, ch: make(chan uint32, channelSize)}
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 uint32 {
return d.ch
}

func (d *OTP1527) interrupt() {
now := machine.GetNano()
// filter signal
highCnt := 0
for n := 0; n < 65; 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 {
switch {
case interval/d.timeHigh > 20:
// this is end of preamble
d.preambleClk = interval / 31
d.resetData()

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 <- d.data
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 <- d.data
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
}

0 comments on commit 6df4abf

Please sign in to comment.