1
0
mirror of https://github.com/kidoman/embd synced 2024-12-23 05:10:05 +01:00

227 lines
3.7 KiB
Go
Raw Normal View History

2013-12-31 07:56:34 +05:30
// Package matrix4x3 allows interfacing 4x3 keypad with Raspberry pi.
package matrix4x3
import (
"strconv"
"sync"
"time"
2014-03-03 00:55:20 +05:30
"github.com/kidoman/embd"
2013-12-31 07:56:34 +05:30
)
type Key int
func (k Key) String() string {
switch k {
case KStar:
return "*"
case KHash:
return "#"
default:
2014-03-02 12:09:57 +05:30
return strconv.Itoa(int(k) - 1)
2013-12-31 07:56:34 +05:30
}
}
const (
2014-03-02 12:09:57 +05:30
KNone Key = iota
K0
2013-12-31 07:56:34 +05:30
K1
K2
K3
K4
K5
K6
K7
K8
K9
KStar
KHash
debounce = 20 * time.Millisecond
pollDelay = 150
rows = 4
cols = 3
)
var keyMap [][]Key
func init() {
keyMap = make([][]Key, rows)
for i := 0; i < rows; i++ {
keyMap[i] = make([]Key, cols)
}
keyMap[0][0] = K1
keyMap[0][1] = K2
keyMap[0][2] = K3
keyMap[1][0] = K4
keyMap[1][1] = K5
keyMap[1][2] = K6
keyMap[2][0] = K7
keyMap[2][1] = K8
keyMap[2][2] = K9
keyMap[3][0] = KStar
keyMap[3][1] = K0
keyMap[3][2] = KHash
}
2014-03-02 12:09:57 +05:30
// A Matrix4x3 struct represents access to the keypad.
type Matrix4x3 struct {
2014-03-03 00:55:20 +05:30
rowPins, colPins []embd.DigitalPin
2013-12-31 07:56:34 +05:30
initialized bool
mu sync.RWMutex
poll int
keyPressed chan Key
quit chan bool
}
// New creates a new interface for matrix4x3.
2014-03-02 12:09:57 +05:30
func New(rowPins, colPins []int) (*Matrix4x3, error) {
m := &Matrix4x3{
2014-03-03 00:55:20 +05:30
rowPins: make([]embd.DigitalPin, rows),
colPins: make([]embd.DigitalPin, cols),
2014-03-02 12:09:57 +05:30
poll: pollDelay,
2013-12-31 07:56:34 +05:30
}
2014-03-02 12:09:57 +05:30
var err error
2013-12-31 07:56:34 +05:30
for i := 0; i < rows; i++ {
2014-03-03 00:55:20 +05:30
m.rowPins[i], err = embd.NewDigitalPin(rowPins[i])
2014-03-02 12:09:57 +05:30
if err != nil {
return nil, err
}
2013-12-31 07:56:34 +05:30
}
for i := 0; i < cols; i++ {
2014-03-03 00:55:20 +05:30
m.colPins[i], err = embd.NewDigitalPin(colPins[i])
2014-03-02 12:09:57 +05:30
if err != nil {
return nil, err
}
2013-12-31 07:56:34 +05:30
}
2014-03-02 12:09:57 +05:30
return m, nil
2013-12-31 07:56:34 +05:30
}
// SetPollDelay sets the delay between run of key scan acquisition loop.
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) SetPollDelay(delay int) {
2013-12-31 07:56:34 +05:30
d.poll = delay
}
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) setup() error {
2013-12-31 07:56:34 +05:30
d.mu.RLock()
if d.initialized {
d.mu.RUnlock()
2014-03-02 12:09:57 +05:30
return nil
2013-12-31 07:56:34 +05:30
}
d.mu.RUnlock()
d.mu.Lock()
defer d.mu.Unlock()
for i := 0; i < rows; i++ {
2014-03-03 00:55:20 +05:30
if err := d.rowPins[i].SetDirection(embd.In); err != nil {
2014-03-02 12:09:57 +05:30
return err
}
if err := d.rowPins[i].PullUp(); err != nil {
return err
}
2013-12-31 07:56:34 +05:30
}
for i := 0; i < cols; i++ {
2014-03-03 00:55:20 +05:30
if err := d.colPins[i].SetDirection(embd.Out); err != nil {
2014-03-02 12:09:57 +05:30
return err
}
2014-03-03 00:55:20 +05:30
if err := d.colPins[i].Write(embd.High); err != nil {
2014-03-02 12:09:57 +05:30
return err
}
2013-12-31 07:56:34 +05:30
}
d.initialized = true
2014-03-02 12:09:57 +05:30
return nil
2013-12-31 07:56:34 +05:30
}
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) findPressedKey() (Key, error) {
if err := d.setup(); err != nil {
return 0, err
2013-12-31 07:56:34 +05:30
}
for col := 0; col < cols; col++ {
2014-03-03 00:55:20 +05:30
if err := d.colPins[col].Write(embd.Low); err != nil {
2014-03-02 12:09:57 +05:30
return KNone, err
}
2013-12-31 07:56:34 +05:30
for row := 0; row < rows; row++ {
2014-03-02 12:09:57 +05:30
value, err := d.rowPins[row].Read()
if err != nil {
return KNone, err
}
2014-03-03 00:55:20 +05:30
if value == embd.Low {
2013-12-31 07:56:34 +05:30
time.Sleep(debounce)
2014-03-02 12:09:57 +05:30
value, err = d.rowPins[row].Read()
if err != nil {
return KNone, err
}
2014-03-03 00:55:20 +05:30
if value == embd.Low {
if err := d.colPins[col].Write(embd.High); err != nil {
2014-03-02 12:09:57 +05:30
return KNone, err
}
return keyMap[row][col], nil
2013-12-31 07:56:34 +05:30
}
}
}
2014-03-03 00:55:20 +05:30
if err := d.colPins[col].Write(embd.High); err != nil {
2014-03-02 12:09:57 +05:30
return KNone, err
}
2013-12-31 07:56:34 +05:30
}
2014-03-02 12:09:57 +05:30
return KNone, nil
2013-12-31 07:56:34 +05:30
}
// Pressed key returns the current key pressed on the keypad.
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) PressedKey() (key Key, err error) {
2013-12-31 07:56:34 +05:30
select {
case key = <-d.keyPressed:
return
default:
return d.findPressedKey()
}
}
// Run starts the continuous key scan loop.
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) Run() {
2013-12-31 07:56:34 +05:30
d.quit = make(chan bool)
go func() {
timer := time.Tick(time.Duration(d.poll) * time.Millisecond)
var key Key
for {
var keyUpdates chan Key
select {
case <-timer:
var err error
if key, err = d.findPressedKey(); err == nil {
keyUpdates = d.keyPressed
}
case keyUpdates <- key:
keyUpdates = nil
case <-d.quit:
d.keyPressed = nil
return
}
}
}()
}
// Close.
2014-03-02 12:09:57 +05:30
func (d *Matrix4x3) Close() {
2013-12-31 07:56:34 +05:30
if d.quit != nil {
d.quit <- true
}
}