forked from nnev/kasse
-
Notifications
You must be signed in to change notification settings - Fork 2
/
reader.go
161 lines (136 loc) · 3.4 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package main
import (
"errors"
"fmt"
"log"
"time"
"github.com/fuzxxl/nfc/2.0/nfc"
)
// NFCEvent contains an event at the NFC reader. Either UID or Err is nil.
type NFCEvent struct {
UID []byte
Err error
}
// DefaultModulation gives defaults for the modulation type and Baudrate.
// Currently, only nfc.ISO14443a is supported for the type. If the default
// BaudRate is not supported by the reader, the fallback is the lowest
// supported value.
var DefaultModulation = nfc.Modulation{
Type: nfc.ISO14443a,
BaudRate: nfc.Nbr106,
}
// PollingInterval gives the interval of polling for new cards.
var PollingInterval = 100 * time.Millisecond
func contains(haystack []int, needle int) bool {
for _, v := range haystack {
if v == needle {
return true
}
}
return false
}
var modulationStrings = map[int]string{
nfc.ISO14443a: "ISO 14443-A",
nfc.Jewel: "Jewel",
nfc.ISO14443b: "ISO 14443-B",
nfc.ISO14443bi: "ISO 14443-B'",
nfc.ISO14443b2sr: "ISO 14443-2B ST SRx",
nfc.ISO14443b2ct: "ISO 14443-2B ASK CTx",
nfc.Felica: "Felica",
nfc.DEP: "DEP",
}
func modulationString(m int) string {
if s, ok := modulationStrings[m]; ok {
return s
}
return fmt.Sprintf("<unknown: %d>", m)
}
var bitrateStrings = map[int]string{
nfc.Nbr106: "Nbr106",
nfc.Nbr212: "Nbr212",
nfc.Nbr424: "Nbr424",
nfc.Nbr847: "Nbr847",
}
func bitrateString(n int) string {
if s, ok := bitrateStrings[n]; ok {
return s
}
return fmt.Sprintf("<unknown: %d>", n)
}
func pollNFC(d nfc.Device, m nfc.Modulation) (uid []byte, err error) {
targets, err := d.InitiatorListPassiveTargets(m)
if err != nil {
return nil, err
}
if len(targets) == 0 {
return nil, nil
}
// We assume, that clash-prevention in the reader gives us always
// exactly one target.
if len(targets) != 1 {
log.Printf("Card-clash! Only using first target")
}
t := targets[0]
// TODO: Handle other target types
tt, ok := t.(*nfc.ISO14443aTarget)
if !ok {
return nil, fmt.Errorf("unsupported card type %T", t)
}
return tt.UID[:tt.UIDLen], nil
}
// ConnectAndPollNFCReader connects to a physical NFC Reader and pools for new
// cards. conn is the reader to connect to - if empty, the first available
// reader will be used.
func ConnectAndPollNFCReader(conn string, ch chan NFCEvent) error {
if DefaultModulation.Type != nfc.ISO14443a {
return errors.New("only ISO 14443-A readers are supported for now")
}
d, err := nfc.Open(conn)
if err != nil {
return err
}
defer d.Close()
log.Printf("NFC reader information:\n%s\n", d)
ms, err := d.SupportedModulations(nfc.InitiatorMode)
if err != nil {
return err
}
for _, m := range ms {
log.Println("Supported modulation type:", modulationString(m))
}
if len(ms) == 0 {
return errors.New("no modulation types supported")
}
var m int
if contains(ms, DefaultModulation.Type) {
m = DefaultModulation.Type
} else {
m = ms[0]
}
bs, err := d.SupportedBaudRates(m)
if err != nil {
return err
}
if len(bs) == 0 {
return errors.New("no baudrates supported at used modulation")
}
var b int
if contains(bs, DefaultModulation.BaudRate) {
b = DefaultModulation.BaudRate
} else {
b = bs[0]
}
if err = d.InitiatorInit(); err != nil {
return err
}
mod := nfc.Modulation{Type: m, BaudRate: b}
// start polling
for {
uid, err := pollNFC(d, mod)
if uid == nil && err == nil {
time.Sleep(PollingInterval)
continue
}
ch <- NFCEvent{uid, err}
}
}