-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added driver to decode signal from Silvan *1527 chips.
- Loading branch information
Showing
3 changed files
with
139 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |