├── CHANGES
├── LICENSE
├── README
└── v2
├── crc.go
├── device.go
├── etc.go
├── go.mod
├── initiator.go
├── marshall.c
├── marshall.h
├── nfc.go
├── nopkgconfig.go
├── pkgconfig.go
├── smoke_test.go
└── target.go
/CHANGES:
--------------------------------------------------------------------------------
1 | Each item is prefixed with one of the following letters:
2 |
3 | B bugfix
4 | C compatible expansion without adding new symbols
5 | I incompatible change
6 | N new function, method or variable in the API
7 | R general remark
8 |
9 | Release 0.1 (2014-02-16):
10 | R initial release
11 |
12 | Release 0.2 (2014-03-03):
13 | N Add a function nfc.(*Device).LastError()
14 | N Add a function nfc.(*Device).InitiatorDeselectTarget()
15 | B Fix incorrect handling in a couple of places
16 | C Improve and unify error strings
17 | B Fix issue #2
18 |
19 | Release 1.0 (2014-04-06):
20 | R This major release is considered stable. The interface of this
21 | wrapper is stable until further notice.
22 | I Rename constants to reflect Go naming conventions
23 | I Change methods of type nfc.Device to use a value receiver
24 | B Fix an issue were copying structs of type nfc.Device could cause a
25 | pointer into unallocated memory to come into existence
26 |
27 | Release 2.0 (2014-08-30)
28 | B Make this wrapper compile under Go 1.3 and newer.
29 | I Change the layout of some Target structures. This is needed to
30 | simplify the marshalling code. The new target structures also follow
31 | the underlying C structures more closely.
32 | I Some names where changed to match Go naming conventions. This was
33 | done now as I believe it is better to lump incompatibly changes into
34 | one release as much as possible.
35 | C Error strings were converted to lower case.
36 | B Some typos where fixed in comments.
37 |
38 | Release 2.0.1 (2015-09-28)
39 | B Set device pointer to nil after calling nfc_close(), not before.
40 |
41 | Release 2.0.2 (2016-01-14)
42 | B Fix error handling in (*Device).InitiatorSelectPassiveTarget()
43 | B Fix initData handling (ibid.), these fix issue #8
44 | R Improve documentation (ibid.)
45 |
46 | Release 2.1.0 (2020-05-22)
47 | N Introduce a new function nfc.Device.SupportedBaudRatesTargetMode()
48 | wrapping the corresponding new function in the upcoming 1.7.2 release
49 | of the libnfc.
50 | C Bump libnfc dependency to version 1.7.2.
51 | C Allow nil Target parameter to
52 | function nfc.Device.InitiatorTargetIsPresent() as supported since
53 | release 1.7.1 of the libnfc.
54 | R adapt Go modules and discontinue the subdirectory scheme.
55 |
56 | Release 2.1.1 (2020-05-22)
57 | N Provide Device.InitiatorPollTarget wrapping nfc_initiator_poll_target.
58 | N Add support for Thinfilm NFC Barcode targets
59 | N Add support for NFC ISO14443BiClass, i.e. HID iClass (Picopass) targets
60 | I Due to upstream changes, the value of the modulation type enumeration
61 | constants has changed. This has been forgotton for the 2.1.0 release
62 | which is why this patch release is needed.
63 |
64 | Release 2.1.2 (2020-05-22)
65 | I Fix Go import paths (sorry, this is my first time using go mod)
66 |
67 | Release 2.1.3 (2020-05-22)
68 | I In reaction to the newly released libnfc 1.8.0 which fixes the ABI
69 | breakage, revert the enumeration order changes and retract releases
70 | 2.1.0 to 2.1.2.
71 | N Requires libnfc version >= 1.8.0.
72 |
73 | Release 2.1.4 (2020-09-14)
74 | I Following a rename of my github account, change import path. The
75 | old import path still works for now but is not recommended for new
76 | developments.
77 | I Delete 2.0 directory with old library version. It will still be
78 | available for import on old tool chains that aren't module aware.
79 | As this directory is not part of the API, removing it is not an
80 | API break.
81 |
82 | Release 2.2.0 (2024-03-09)
83 | N Add new functions Modulation.String(), Modulation.GoString()
84 | N Add new symbols ModulationTypes and BaudRates
85 | C Add a unit test for ListDevices()
86 | C Add a unit test for Device.InitiatorListPassiveTargets()
87 | C Use pkg-config to find libnfc. If this is undesirable, supply build
88 | tag nopkgconfig / no_pkgconfig to switch back to just linking with
89 | -lnfc.
90 | C Permit call to Device.Close() on uninitialised Device struct.
91 | This permits the usual dev, err := nfc.Open(...); defer dev.Close()
92 | idiom.
93 | B Fix an infinite loop in Device.InitiatorListPassiveTargets (issue #12)
94 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This is a Go wrapper for the libnfc.
2 |
3 | You need the following libnfc version to use this code:
4 |
5 | versions <= 2.0.2 need libnfc version 1.7.0 or 1.7.1
6 | version >= 2.1.0 need libnfc version 1.8.0 or later
7 |
8 | Due to an unfortunate ABI breakage, libnfc version 1.7.2 cannot be used
9 | with this wrapper.
10 |
11 | The code has not been thoroughly tested yet. Please report any errors to
12 | the project. The API is considered stable as of version 2.0 and will
13 | probably not change in incompatible ways in the near future.
14 |
15 | Version 2.0.2 and earlier of this wrapper have been developed before the
16 | advent of Go modules. For this reason, they use a weird homecooked
17 | scheme for their versioning involving the 2.0 and latest directories.
18 | These can safely be ignored for new developments. Using Go modules,
19 | only version 2.1.0 and later are available.
20 |
21 | To use this library, install libnfc version 1.8.0 or newer and import
22 |
23 | github.com/clausecker/nfc/v2
24 |
25 | into your project. Pkg-config is used to find libnfc automatically. If
26 | this does not work, you can compile with tag nopkgconfig or no_pkgconfig
27 | to instruct the package to instead simply link with -lnfc. You'll then
28 | have to manually set things up for suitable -I... and -L... options to
29 | be supplied so the header files and library are found.
30 |
31 | This project uses go modules for versioning and tries its best to follow
32 | the usual guidelines for interface stability.
33 |
34 | Copyright (c) 2014--2020, 2024 Robert Clausecker
35 |
36 | This program is free software: you can redistribute it and/or modify it
37 | under the terms of the GNU Lesser General Public License as published by
38 | the Free Software Foundation, version 3.
39 |
40 | This program is distributed in the hope that it will be useful,
41 | but WITHOUT ANY WARRANTY; without even the implied warranty of
42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
43 | See the GNU General Public License for more details.
44 |
--------------------------------------------------------------------------------
/v2/crc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | // The code in this file is a very direct translation of the code in
16 | // iso14443-subr.c of the libnfc version 1.7.0 translated to Go for performance
17 | // reasons.
18 |
19 | package nfc
20 |
21 | // Calculate an ISO 14443a CRC. Code translated from the code in
22 | // iso14443a_crc().
23 | func ISO14443aCRC(data []byte) [2]byte {
24 | crc := uint32(0x6363)
25 | for _, bt := range data {
26 | bt ^= uint8(crc & 0xff)
27 | bt ^= bt << 4
28 | bt32 := uint32(bt)
29 | crc = (crc >> 8) ^ (bt32 << 8) ^ (bt32 << 3) ^ (bt32 >> 4)
30 | }
31 |
32 | return [2]byte{byte(crc & 0xff), byte((crc >> 8) & 0xff)}
33 | }
34 |
35 | // Calculate an ISO 14443a CRC and append it to the supplied slice.
36 | func AppendISO14443aCRC(data []byte) []byte {
37 | crc := ISO14443aCRC(data)
38 | return append(data, crc[0], crc[1])
39 | }
40 |
41 | // Calculate an ISO 14443b CRC. Code translated from the code in
42 | // iso14443b_crc().
43 | func ISO14443bCRC(data []byte) [2]byte {
44 | crc := uint32(0xffff)
45 | for _, bt := range data {
46 | bt ^= uint8(crc & 0xff)
47 | bt ^= bt << 4
48 | bt32 := uint32(bt)
49 | crc = (crc >> 8) ^ (bt32 << 8) ^ (bt32 << 3) ^ (bt32 >> 4)
50 | }
51 |
52 | return [2]byte{byte(crc & 0xff), byte((crc >> 8) & 0xff)}
53 | }
54 |
55 | // Calculate an ISO 14443b CRC and append it to the supplied slice.
56 | func AppendISO14443bCRC(data []byte) []byte {
57 | crc := ISO14443bCRC(data)
58 | return append(data, crc[0], crc[1])
59 | }
60 |
61 | // Locate historical bytes according to ISO/IEC 14443-4 sec. 5.2.7. Return nil
62 | // if that fails.
63 | func ISO14443aLocateHistoricalBytes(ats []byte) []byte {
64 | if len(ats) > 0 {
65 | offset := 1
66 | if ats[0]&0x10 != 0 {
67 | offset++
68 | }
69 |
70 | if ats[1]&0x20 != 0 {
71 | offset++
72 | }
73 |
74 | if ats[2]&0x40 != 0 {
75 | offset++
76 | }
77 |
78 | if len(ats) > offset {
79 | return ats[offset:]
80 | }
81 | }
82 |
83 | return nil
84 | }
85 |
86 | // Add cascade tags (0x88) in UID. See ISO/IEC 14443-3 sec. 6.4.4.
87 | func ISO14443CascadeUID(uid []byte) (cascadedUID []byte) {
88 | switch len(uid) {
89 | case 7:
90 | cascadedUID = make([]byte, 8)
91 | cascadedUID[0] = 0x88
92 | copy(cascadedUID[1:], uid)
93 | case 10:
94 | cascadedUID = make([]byte, 12)
95 | cascadedUID[0] = 0x88
96 | copy(cascadedUID[1:4], uid)
97 | cascadedUID[4] = 0x88
98 | copy(cascadedUID[5:], uid[3:])
99 | case 4:
100 | fallthrough
101 | default:
102 | cascadedUID = append(cascadedUID, uid...)
103 | }
104 |
105 | return
106 | }
107 |
--------------------------------------------------------------------------------
/v2/device.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, 2015, 2019, 2020 Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | package nfc
16 |
17 | // #include
18 | // #include
19 | import "C"
20 | import "unsafe"
21 | import "errors"
22 | import "fmt"
23 | import "time"
24 |
25 | // NFC device
26 | type Device struct {
27 | d **C.nfc_device
28 | }
29 |
30 | // Return a pointer to the wrapped nfc_device. This is useful if you try to use
31 | // this wrapper to wrap other C code that builds onto the libnfc.
32 | func (d Device) Pointer() uintptr {
33 | return uintptr(unsafe.Pointer(*d.d))
34 | }
35 |
36 | // Open an NFC device. See documentation of Open() for more details
37 | func (c *context) open(conn string) (d Device, err error) {
38 | c.m.Lock()
39 | defer c.m.Unlock()
40 | c.initContext()
41 |
42 | cs, err := newConnstring(conn)
43 | if err != nil {
44 | return
45 | }
46 |
47 | defer cs.Free()
48 |
49 | dev := C.nfc_open(c.c, cs.ptr)
50 |
51 | if dev == nil {
52 | err = errors.New("cannot open NFC device")
53 | return
54 | }
55 |
56 | d = Device{&dev}
57 | return
58 | }
59 |
60 | // open a connection to an NFC device. If conn is "", the first available device
61 | // will be used. If this operation fails, check the log on stderr for more
62 | // details as the libnfc is not particulary verbose to us.
63 | //
64 | // Depending on the desired operation mode, the device needs to be configured
65 | // by using InitiatorInit() or TargetInit(), optionally followed by manual
66 | // tuning of the parameters if the default parameters are not suiting your
67 | // goals.
68 | func Open(conn string) (Device, error) {
69 | return theContext.open(conn)
70 | }
71 |
72 | // the error returned by the last operation on d. Every function that wraps some
73 | // functions operating on an nfc_device should call this function and return the
74 | // result. This wraps nfc_device_get_last_error.
75 | func (d Device) LastError() error {
76 | if *d.d == nil {
77 | return errors.New("device closed")
78 | }
79 |
80 | err := Error(C.nfc_device_get_last_error(*d.d))
81 |
82 | if err == 0 {
83 | return nil
84 | }
85 |
86 | return err
87 | }
88 |
89 | // Close an NFC device.
90 | func (d Device) Close() error {
91 | if d.d == nil || *d.d == nil {
92 | // closing a closed device is a nop
93 | return nil
94 | }
95 |
96 | C.nfc_close(*d.d)
97 | *d.d = nil
98 |
99 | return nil
100 | }
101 |
102 | // Abort current running command. Some commands (ie. TargetInit()) are blocking
103 | // functions and will return only in particular conditions (ie. external
104 | // initiator request). This function attempt to abort the current running
105 | // command.
106 | func (d Device) AbortCommand() error {
107 | if *d.d == nil {
108 | return errors.New("device closed")
109 | }
110 |
111 | return Error(C.nfc_abort_command(*d.d))
112 | }
113 |
114 | // Turn NFC device in idle mode. In initiator mode, the RF field is turned off
115 | // and the device is set to low power mode (if avaible); In target mode, the
116 | // emulation is stoped (no target available from external initiator) and the
117 | // device is set to low power mode (if avaible).
118 | func (d Device) Idle() error {
119 | if *d.d == nil {
120 | return errors.New("device closed")
121 | }
122 |
123 | return Error(C.nfc_idle(*d.d))
124 | }
125 |
126 | // Print information about an NFC device.
127 | func (d Device) Information() (string, error) {
128 | if *d.d == nil {
129 | return "", errors.New("device closed")
130 | }
131 |
132 | var ptr *C.char
133 | buflen := C.nfc_device_get_information_about(*d.d, &ptr)
134 |
135 | if buflen < 0 {
136 | return "", Error(buflen)
137 | }
138 |
139 | // documentation for nfc_device_get_information_about says that buflen
140 | // contains the length of the string that is returned. Apparently, for
141 | // some drivers, buflen is always 0 so we disregard it.
142 | str := C.GoString(ptr)
143 | C.nfc_free(unsafe.Pointer(ptr))
144 |
145 | return str, nil
146 | }
147 |
148 | // Returns the device's connection string. If the device has been closed before,
149 | // this function returns the empty string.
150 | func (d Device) Connection() string {
151 | if *d.d == nil {
152 | return ""
153 | }
154 |
155 | cptr := C.nfc_device_get_connstring(*d.d)
156 | return C.GoString(cptr)
157 | }
158 |
159 | // Returns the device's name. This information is not enough to uniquely
160 | // determine the device.
161 | func (d Device) String() string {
162 | if *d.d == nil {
163 | return ""
164 | }
165 |
166 | cptr := C.nfc_device_get_name(*d.d)
167 | return C.GoString(cptr)
168 | }
169 |
170 | // Return Go code that could be used to reproduce this device.
171 | func (d Device) GoString() string {
172 | if *d.d == nil {
173 | return "nil"
174 | }
175 |
176 | return fmt.Sprintf("nfc.Open(%q)", d.Connection())
177 | }
178 |
179 | // Set a device's integer-property value. Returns nil on success, otherwise an
180 | // error. See integer constants in this package for possible properties.
181 | func (d Device) SetPropertyInt(property, value int) error {
182 | if *d.d == nil {
183 | return errors.New("device closed")
184 | }
185 |
186 | err := C.nfc_device_set_property_int(*d.d, C.nfc_property(property), C.int(value))
187 |
188 | if err != 0 {
189 | return Error(err)
190 | }
191 |
192 | return nil
193 | }
194 |
195 | // Set a device's boolean-property value. Returns nil on success, otherwise an
196 | // error. See integer constants in this package for possible properties.
197 | func (d Device) SetPropertyBool(property int, value bool) error {
198 | if *d.d == nil {
199 | return errors.New("device closed")
200 | }
201 |
202 | err := C.nfc_device_set_property_bool(*d.d, C.nfc_property(property), C.bool(value))
203 |
204 | if err != 0 {
205 | return Error(err)
206 | }
207 |
208 | return nil
209 | }
210 |
211 | // Get supported modulations. Returns a slice of supported modulations or an
212 | // error. Pass either TARGET or INITIATOR as mode. This function wraps
213 | // nfc_device_get_supported_modulation()
214 | func (d Device) SupportedModulations(mode int) ([]int, error) {
215 | if *d.d == nil {
216 | return nil, errors.New("device closed")
217 | }
218 |
219 | // The documentation inside the libnfc is a bit unclear on how the
220 | // array returned through supported_mt is to be threated. The code
221 | // itself suggest that it points to an array of entries terminated with
222 | // UNDEFINED = 0.
223 | var mt_arr *C.nfc_modulation_type
224 | ret := C.nfc_device_get_supported_modulation(*d.d, C.nfc_mode(mode), &mt_arr)
225 | if ret != 0 {
226 | return nil, Error(ret)
227 | }
228 |
229 | mods := []int{}
230 | type mod C.nfc_modulation_type
231 | ptr := unsafe.Pointer(mt_arr)
232 |
233 | for *(*mod)(ptr) != 0 {
234 | mods = append(mods, int(*(*mod)(ptr)))
235 | ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*mt_arr))
236 | }
237 |
238 | return mods, nil
239 | }
240 |
241 | // Get the supported baud rates for target or iniator mode. This function
242 | // returns either a slice of supported baud rates for the provided mode and
243 | // modulation type or an error. This function calls either
244 | // nfc_device_get_supported_baud_rate() or
245 | // nfc_device_get_supported_baud_rate_target_mode() depending on the mode
246 | // argument.
247 | func (d Device) supportedBaudRatesForMode(mode int, modulationType int) ([]int, error) {
248 | if *d.d == nil {
249 | return nil, errors.New("device closed")
250 | }
251 |
252 | // The documentation inside the libnfc is a bit unclear on how the
253 | // array returned through supported_mt is to be threated. The code
254 | // itself suggest that it points to an array of entries terminated with
255 | // UNDEFINED = 0.
256 | var br_arr *C.nfc_baud_rate
257 | var ret int
258 | if mode == InitiatorMode {
259 | ret = int(C.nfc_device_get_supported_baud_rate(*d.d, C.nfc_modulation_type(modulationType), &br_arr))
260 | } else { // mode == TargetMode
261 | ret = int(C.nfc_device_get_supported_baud_rate_target_mode(*d.d, C.nfc_modulation_type(modulationType), &br_arr))
262 | }
263 |
264 | if ret != 0 {
265 | return nil, Error(ret)
266 | }
267 |
268 | brs := []int{}
269 | type br C.nfc_baud_rate
270 | ptr := unsafe.Pointer(br_arr)
271 |
272 | for *(*br)(ptr) != 0 {
273 | brs = append(brs, int(*(*br)(ptr)))
274 | ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*br_arr))
275 | }
276 |
277 | return brs, nil
278 | }
279 |
280 | // Get the suported baud rates for initiator mode. Returns either a
281 | // slice of supported baud rates or an error. This function wraps
282 | // nfc_device_get_supported_baud_rate().
283 | func (d Device) SupportedBaudRates(modulationType int) ([]int, error) {
284 | return d.supportedBaudRatesForMode(InitiatorMode, modulationType)
285 | }
286 |
287 | // Get the suported baud rates for target mode. Returns either a
288 | // slice of supported baud rates or an error. This function wraps
289 | // nfc_device_get_supported_baud_rate_target_mode().
290 | func (d Device) SupportedBaudRatesTargetMode(modulationType int) ([]int, error) {
291 | return d.supportedBaudRatesForMode(TargetMode, modulationType)
292 | }
293 |
294 | // Initialize NFC device as an emulated tag. n contains the received byte count
295 | // on success, or is meaningless on error. The current implementation will
296 | // return the libnfc error code in case of error, but this is subject to change.
297 | // The returned target tt will be the result of the modifications
298 | // nfc_target_init() applies to t. Such modifications might happen if you set
299 | // an Baud or DepMode to UNDEFINED. The fields will be updated with concrete
300 | // values. timeout contains a timeout in milliseconds.
301 | //
302 | // This function initializes NFC device in target mode in order to emulate a tag
303 | // as the specified target t.
304 | // - Crc is handled by the device (HANDLE_CRC = true)
305 | // - Parity is handled the device (HANDLE_PARITY = true)
306 | // - Cryto1 cipher is disabled (ACTIVATE_CRYPTO1 = false)
307 | // - Auto-switching in ISO14443-4 mode is enabled (AUTO_ISO14443_4 = true)
308 | // - Easy framing is disabled (EASY_FRAMING = false)
309 | // - Invalid frames are not accepted (ACCEPT_INVALID_FRAMES = false)
310 | // - Multiple frames are not accepted (ACCEPT_MULTIPLE_FRAMES = false)
311 | // - RF field is dropped
312 | //
313 | // Warning: Be aware that this function will wait (hang) until a command is
314 | // received that is not part of the anti-collision. The RATS command for example
315 | // would wake up the emulator. After this is received, the send and receive
316 | // functions can be used.
317 | //
318 | // If timeout equals to 0, the function blocks indefinitely (until an error is
319 | // raised or function is completed). If timeout equals to -1, the default
320 | // timeout will be used.
321 | func (d Device) TargetInit(t Target, rx []byte, timeout int) (n int, tt Target, err error) {
322 | if *d.d == nil {
323 | return ESOFT, t, errors.New("device closed")
324 | }
325 |
326 | tar := (*C.nfc_target)(unsafe.Pointer(t.Marshall()))
327 | defer C.free(unsafe.Pointer(tar))
328 |
329 | n = int(C.nfc_target_init(
330 | *d.d, tar,
331 | (*C.uint8_t)(&rx[0]), C.size_t(len(rx)),
332 | C.int(timeout),
333 | ))
334 |
335 | if n < 0 {
336 | err = Error(n)
337 | }
338 |
339 | tt = unmarshallTarget(tar)
340 | return
341 | }
342 |
343 | // Send bytes and APDU frames. n contains the sent byte count on success, or is
344 | // meaningless on error. The current implementation will return the libnfc
345 | // error code in case of error, but this is subject to change. timeout contains
346 | // a timeout in milliseconds.
347 | //
348 | // This function make the NFC device (configured as target) send byte frames
349 | // (e.g. APDU responses) to the initiator.
350 | //
351 | // If timeout equals to 0, the function blocks indefinitely (until an error is
352 | // raised or function is completed). If timeout equals to -1, the default
353 | // timeout will be used.
354 | func (d Device) TargetSendBytes(tx []byte, timeout int) (n int, err error) {
355 | if *d.d == nil {
356 | return ESOFT, errors.New("device closed")
357 | }
358 |
359 | n = int(C.nfc_target_send_bytes(
360 | *d.d,
361 | (*C.uint8_t)(&tx[0]), C.size_t(len(tx)),
362 | C.int(timeout),
363 | ))
364 |
365 | if n < 0 {
366 | err = Error(n)
367 | }
368 |
369 | return
370 | }
371 |
372 | // Receive bytes and APDU frames. n contains the received byte count on success,
373 | // or is meaningless on error. The current implementation will return the libnfc
374 | // error code in case of error, but this is subject to change. timeout contains
375 | // a timeout in milliseconds.
376 | //
377 | // This function retrieves bytes frames (e.g. ADPU) sent by the initiator to the
378 | // NFC device (configured as target).
379 | //
380 | // If timeout equals to 0, the function blocks indefinitely (until an error is
381 | // raised or function is completed). If timeout equals to -1, the default
382 | // timeout will be used.
383 | func (d Device) TargetReceiveBytes(rx []byte, timeout int) (n int, err error) {
384 | if *d.d == nil {
385 | return ESOFT, errors.New("device closed")
386 | }
387 |
388 | n = int(C.nfc_target_receive_bytes(
389 | *d.d,
390 | (*C.uint8_t)(&rx[0]), C.size_t(len(rx)),
391 | C.int(timeout),
392 | ))
393 |
394 | if n < 0 {
395 | err = Error(n)
396 | }
397 |
398 | return
399 | }
400 |
401 | // Send raw bit-frames. Returns sent bits count on success, n contains the sent
402 | // bit count on success, or is meaningless on error. The current implementation
403 | // will return the libnfc error code in case of error, but this is subject to
404 | // change. txPar has to have the same length as tx, an error will occur if this
405 | // invariant does not hold.
406 | //
407 | // tx contains a byte slice of the frame that needs to be transmitted. txLength
408 | // contains its length in bits. txPar contains a byte slice of the corresponding
409 | // parity bits needed to send per byte.
410 | //
411 | // his function can be used to transmit (raw) bit-frames to the initiator using
412 | // the specified NFC device (configured as target).
413 | func (d Device) TargetSendBits(tx []byte, txPar []byte, txLength uint) (n int, err error) {
414 | if *d.d == nil {
415 | return ESOFT, errors.New("device closed")
416 | }
417 |
418 | if len(tx) != len(txPar) {
419 | return ESOFT, errors.New("invariant doesn't hold")
420 | }
421 |
422 | if uint(len(tx))*8 < txLength {
423 | return ESOFT, errors.New("slice shorter than specified bit count")
424 | }
425 |
426 | n = int(C.nfc_target_send_bits(
427 | *d.d,
428 | (*C.uint8_t)(&tx[0]),
429 | C.size_t(txLength),
430 | (*C.uint8_t)(&txPar[0]),
431 | ))
432 |
433 | if n < 0 {
434 | err = Error(n)
435 | }
436 |
437 | return
438 | }
439 |
440 | // Receive bit-frames. Returns received bits count on success, n contains the
441 | // received bit count on success, or is meaningless on error. The current
442 | // implementation will return the libnfc error code in case of error, but this
443 | // is subject to change. rxPar has to have the same length as rx, an error will
444 | // occur if this invariant does not hold.
445 | //
446 | // rx contains a byte slice of the frame that you want to receive. rxLength
447 | // contains its length in bits. rxPar contains a byte slice of the corresponding
448 | // parity bits received per byte.
449 | //
450 | // This function makes it possible to receive (raw) bit-frames. It returns all
451 | // the messages that are stored in the FIFO buffer of the PN53x chip. It
452 | // does not require to send any frame and thereby could be used to snoop frames
453 | // that are transmitted by a nearby initiator. Check out the
454 | // ACCEPT_MULTIPLE_FRAMES configuration option to avoid losing transmitted
455 | // frames.
456 | func (d Device) TargetTransceiveBits(rx []byte, rxPar []byte, rxLength uint) (n int, err error) {
457 | if *d.d == nil {
458 | return ESOFT, errors.New("device closed")
459 | }
460 |
461 | if len(rx) != len(rxPar) {
462 | return ESOFT, errors.New("invariant doesn't hold")
463 | }
464 |
465 | if uint(len(rx))*8 < rxLength {
466 | return ESOFT, errors.New("slice shorter than specified bit count")
467 | }
468 |
469 | n = int(C.nfc_target_receive_bits(
470 | *d.d,
471 | (*C.uint8_t)(&rx[0]),
472 | C.size_t(rxLength),
473 | (*C.uint8_t)(&rxPar[0]),
474 | ))
475 |
476 | if n < 0 {
477 | err = Error(n)
478 | }
479 |
480 | return
481 | }
482 |
483 | // Poll for NFC targets. Returns polled target count or 0 and an error.
484 | // modulations is a slice of all modulation types to poll for. times is the
485 | // number of times we desire to poll (indefinite polling is not supported).
486 | // period is the time to wait between polls. It is rounded up to the next
487 | // 150 ms and must be between 150 ms and 2.25 s. If targets are
488 | // found, one is selected and returned.
489 | //
490 | // This function wraps nfc_initiator_poll_target but is extended to lack
491 | // its limitation to 255 polls.
492 | func (d Device) InitiatorPollTarget(modulations []Modulation, times int, period time.Duration) (n int, t Target, err error) {
493 | ms := period.Milliseconds()
494 | if ms <= 0 || ms > 2250 || times < 0 {
495 | err = Error(EINVARG)
496 | return
497 | }
498 |
499 | uiPeriod := C.uchar((ms + 149) / 150)
500 |
501 | if modulations == nil {
502 | modulations = make([]Modulation, 0)
503 | }
504 |
505 | m := make([]C.nfc_modulation, len(modulations))
506 | for i := range modulations {
507 | m[i].nmt = C.nfc_modulation_type(modulations[i].Type)
508 | m[i].nbr = C.nfc_baud_rate(modulations[i].BaudRate)
509 | }
510 |
511 | var ctarget C.nfc_target
512 |
513 | for times > 0 {
514 | uiPollNr := C.uchar(times)
515 | if times >= 255 {
516 | uiPollNr = 254
517 | }
518 |
519 | ret := C.nfc_initiator_poll_target(*d.d, &m[0], C.size_t(len(m)), uiPollNr, uiPeriod, &ctarget)
520 | if ret < 0 {
521 | err = Error(ret)
522 | return
523 | } else if ret > 0 {
524 | n = int(ret)
525 | t = unmarshallTarget(&ctarget)
526 | return
527 | }
528 |
529 | times -= int(uiPollNr)
530 | }
531 |
532 | // nothing found
533 | return
534 | }
535 |
--------------------------------------------------------------------------------
/v2/etc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | package nfc
16 |
17 | /*
18 | #include
19 | #include
20 |
21 | struct device_listing {
22 | int count; // is an error code if negative
23 | char *entries;
24 |
25 | };
26 |
27 | struct device_listing list_devices_wrapper(nfc_context *context) {
28 | size_t cstr_len = 16, actual_count;
29 | nfc_connstring *cstr = NULL, *cstr_tmp;
30 | struct device_listing dev;
31 |
32 | // call nfc_list_devices as long as our array might be too short
33 | for (;;) {
34 | cstr_tmp = realloc(cstr, cstr_len * sizeof *cstr);
35 | if (cstr_tmp == NULL) {
36 | actual_count = NFC_ESOFT;
37 | break;
38 | }
39 |
40 | cstr = cstr_tmp;
41 | actual_count = nfc_list_devices(context, cstr, cstr_len);
42 |
43 | // also covers the case where actual_count is an error
44 | if (actual_count < cstr_len) break;
45 |
46 | cstr_len += 16;
47 | }
48 |
49 | dev.count = actual_count;
50 | dev.entries = (char*)cstr;
51 |
52 | return dev;
53 | }
54 | */
55 | import "C"
56 | import "errors"
57 | import "sync"
58 | import "unsafe"
59 |
60 | // Get library version. This function returns the version of the libnfc wrapped
61 | // by this package as returned by nfc_version().
62 | func Version() string {
63 | cstr := C.nfc_version()
64 | return C.GoString(cstr)
65 | }
66 |
67 | // NFC context
68 | type context struct {
69 | c *C.nfc_context
70 | m sync.Mutex
71 | }
72 |
73 | // Initialize the library. This is an internal function that assumes that the
74 | // appropriate lock is held by the surrounding function. This function is a nop
75 | // if the library is already initialized. This function panics if the library
76 | // cannot be initialized for any reason.
77 | func (c *context) initContext() {
78 | if c.c != nil {
79 | return
80 | }
81 |
82 | C.nfc_init(&c.c)
83 |
84 | if c.c == nil {
85 | panic(errors.New("cannot initialize libnfc"))
86 | }
87 |
88 | return
89 | }
90 |
91 | // deinitialize the library
92 | func (c *context) deinitContext() {
93 | c.m.Lock()
94 | defer c.m.Unlock()
95 |
96 | if c.c != nil {
97 | C.nfc_exit(c.c)
98 | }
99 | }
100 |
101 | // Scan for discoverable supported devices (ie. only available for some drivers.
102 | // Returns a slice of strings that can be passed to Open() to open the devices
103 | // found.
104 | func ListDevices() ([]string, error) {
105 | return theContext.listDevices()
106 | }
107 |
108 | // See ListDevices() for documentation
109 | func (c *context) listDevices() ([]string, error) {
110 | c.m.Lock()
111 | defer c.m.Unlock()
112 | c.initContext()
113 |
114 | dev := C.list_devices_wrapper(c.c)
115 | defer C.free(unsafe.Pointer(dev.entries))
116 | if dev.count < 0 {
117 | return nil, Error(dev.count)
118 | }
119 |
120 | dev_entries := C.GoBytes(unsafe.Pointer(dev.entries), dev.count*BufsizeConnstring)
121 |
122 | devices := make([]string, dev.count)
123 | for i := range devices {
124 | charptr := (*C.char)(unsafe.Pointer(&dev_entries[i*BufsizeConnstring]))
125 | devices[i] = connstring{charptr}.String()
126 | }
127 |
128 | return devices, nil
129 | }
130 |
131 | // Connection string
132 | type connstring struct {
133 | ptr *C.char
134 | }
135 |
136 | func (c connstring) String() string {
137 | str := C.GoStringN(c.ptr, BufsizeConnstring)
138 | i := 0
139 |
140 | for ; i < len(str) && str[i] != '\000'; i++ {
141 | }
142 |
143 | return str[:i+1]
144 | }
145 |
146 | // Makes a connstring. Notice that the string must not be longer than
147 | // 1023 characters. If "" is passed, return nil instead. Call Free() when the
148 | // string is no longer in use.
149 | func newConnstring(s string) (connstring, error) {
150 | if s == "" {
151 | return connstring{nil}, nil
152 | }
153 |
154 | if len(s) >= BufsizeConnstring {
155 | return connstring{nil}, errors.New("string too long for Connstring")
156 | }
157 |
158 | return connstring{C.CString(s)}, nil
159 | }
160 |
161 | // Frees a connstring. Do not dereference afterwards. Free can be called on
162 | // connstrings that contain a nil pointer.
163 | func (c connstring) Free() {
164 | if c.ptr != nil {
165 | C.free(unsafe.Pointer(c.ptr))
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/v2/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/clausecker/nfc/v2
2 |
3 | go 1.12
4 |
--------------------------------------------------------------------------------
/v2/initiator.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014--2016, 2024 Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | package nfc
16 |
17 | /*
18 | #include
19 | #include
20 |
21 | struct target_listing {
22 | int count; // is an error code if negative
23 | nfc_target *entries;
24 | };
25 |
26 | // this function works analoguous to list_devices_wrapper but for the function
27 | // nfc_initiator_list_passive_targets.
28 | struct target_listing list_targets_wrapper(nfc_device *device, const nfc_modulation nm) {
29 | size_t targets_len = 16;
30 | int actual_count;
31 | nfc_target *targets = NULL, *targets_tmp;
32 | struct target_listing tar;
33 |
34 | // call nfc_list_devices as long as our array might be too short
35 | for (;;) {
36 | targets_tmp = realloc(targets, targets_len * sizeof *targets);
37 | if (targets_tmp == NULL) {
38 | actual_count = NFC_ESOFT;
39 | break;
40 | }
41 |
42 | targets = targets_tmp;
43 | actual_count = nfc_initiator_list_passive_targets(device, nm, targets, targets_len);
44 |
45 | if (actual_count < 0 || actual_count < targets_len)
46 | break;
47 |
48 | // array was full, retry with some more space
49 | targets_len += 16;
50 | }
51 |
52 | tar.count = actual_count;
53 | tar.entries = targets;
54 |
55 | return tar;
56 | }
57 | */
58 | import "C"
59 | import "errors"
60 | import "unsafe"
61 |
62 | // Send data to target then retrieve data from target. n contains received bytes
63 | // count on success, or is meaningless on error. The current implementation will
64 | // return the libnfc error code in case of error, but this is subject to change.
65 | // This function will return EOVFLOW if more bytes are being received than the
66 | // length of rx.
67 | //
68 | // The NFC device (configured as initiator) will transmit the supplied bytes
69 | // (tx) to the target. It waits for the response and stores the received bytes
70 | // in rx. If the received bytes exceed rx, the error status will be NFC_EOVFLOW
71 | // and rx will contain len(rx) received bytes.
72 | //
73 | // If EASY_FRAMING option is disabled the frames will sent and received in raw
74 | // mode: PN53x will not handle input neither output data.
75 | //
76 | // The parity bits are handled by the PN53x chip. The CRC can be generated
77 | // automatically or handled manually. Using this function, frames can be
78 | // communicated very fast via the NFC initiator to the tag.
79 | //
80 | // Tests show that on average this way of communicating is much faster than
81 | // using the regular driver/middle-ware (often supplied by manufacturers).
82 | //
83 | // Warning: The configuration option HANDLE_PARITY must be set to true (the
84 | // default value).
85 | //
86 | // If timeout equals to 0, the function blocks indefinitely (until an error is
87 | // raised or function is completed). If timeout equals to -1, the default
88 | // timeout will be used.
89 | func (d Device) InitiatorTransceiveBytes(tx, rx []byte, timeout int) (n int, err error) {
90 | if *d.d == nil {
91 | return ESOFT, errors.New("device closed")
92 | }
93 |
94 | txptr := (*C.uint8_t)(&tx[0])
95 | rxptr := (*C.uint8_t)(&rx[0])
96 |
97 | n = int(C.nfc_initiator_transceive_bytes(
98 | *d.d,
99 | txptr, C.size_t(len(tx)),
100 | rxptr, C.size_t(len(rx)),
101 | C.int(timeout),
102 | ))
103 |
104 | if n < 0 {
105 | err = Error(n)
106 | }
107 |
108 | return
109 | }
110 |
111 | // Transceive raw bit-frame to a target. n contains the received byte count on
112 | // success, or is meaningless on error. The current implementation will return
113 | // the libnfc error code in case of error, but this is subject to change. If
114 | // txLength is longer than the supplied slice, an error will occur. txPar has to
115 | // have the same length as tx, dito for rxPar and rx. An error will occur if any
116 | // of these invariants do not hold.
117 | //
118 | // tx contains a byte slice of the frame that needs to be transmitted. txLength
119 | // contains its length in bits.
120 | //
121 | // For example the REQA (0x26) command (the first anti-collision command of
122 | // ISO14443-A) must be precise 7 bits long. This is not possible using
123 | // Device.InitiatorTransceiveBytes(). With that function you can only
124 | // communicate frames that consist of full bytes. When you send a full byte (8
125 | // bits + 1 parity) with the value of REQA (0x26), a tag will simply not
126 | // respond.
127 | //
128 | // txPar contains a byte slice of the corresponding parity bits needed to send
129 | // per byte.
130 | //
131 | // For example if you send the SELECT_ALL (0x93, 0x20) = [ 10010011, 00100000 ]
132 | // command, you have to supply the following parity bytes (0x01, 0x00) to define
133 | // the correct odd parity bits. This is only an example to explain how it works,
134 | // if you just are sending two bytes with ISO14443-A compliant parity bits you
135 | // better can use the Device.InitiatorTransceiveBytes() method.
136 | //
137 | // rx will contain the response from the target. This function will return
138 | // EOVFLOW if more bytes are received than the length of rx. rxPar contains a
139 | // byte slice of the corresponding parity bits.
140 | //
141 | // The NFC device (configured as initiator) will transmit low-level messages
142 | // where only the modulation is handled by the PN53x chip. Construction of the
143 | // frame (data, CRC and parity) is completely done by libnfc. This can be very
144 | // useful for testing purposes. Some protocols (e.g. MIFARE Classic) require to
145 | // violate the ISO14443-A standard by sending incorrect parity and CRC bytes.
146 | // Using this feature you are able to simulate these frames.
147 | func (d Device) InitiatorTransceiveBits(tx, txPar []byte, txLength uint, rx, rxPar []byte) (n int, err error) {
148 | if *d.d == nil {
149 | return ESOFT, errors.New("device closed")
150 | }
151 |
152 | if len(tx) != len(txPar) || len(rx) != len(rxPar) {
153 | return ESOFT, errors.New("invariant doesn't hold")
154 | }
155 |
156 | if uint(len(tx))*8 < txLength {
157 | return ESOFT, errors.New("slice shorter than specified bit count")
158 | }
159 |
160 | txptr := (*C.uint8_t)(&tx[0])
161 | txparptr := (*C.uint8_t)(&txPar[0])
162 | rxptr := (*C.uint8_t)(&rx[0])
163 | rxparptr := (*C.uint8_t)(&rxPar[0])
164 |
165 | n = int(C.nfc_initiator_transceive_bits(
166 | *d.d,
167 | txptr, C.size_t(txLength), txparptr,
168 | rxptr, C.size_t(len(rx)), rxparptr,
169 | ))
170 |
171 | if n < 0 {
172 | err = Error(n)
173 | }
174 |
175 | return
176 | }
177 |
178 | // Send data to target then retrieve data from target with timing control. n
179 | // contains the received byte count on success, or is meaningless on error. c
180 | // will contain the actual number of cycles waited. The current implementation
181 | // will return the libnfc error code in case of error, but this is subject to
182 | // change. This function will return EOVFLOW if more bytes are being received
183 | // than the length of rx.
184 | //
185 | // This function is similar to Device.InitiatorTransceiveBytes() with the
186 | // following differences:
187 | //
188 | // - A precise cycles counter will indicate the number of cycles between emission & reception of frames.
189 | // - Only modes with EASY_FRAMING option disabled are supported.
190 | // - Overall communication with the host is heavier and slower.
191 | //
192 | // By default, the timer configuration tries to maximize the precision, which
193 | // also limits the maximum cycle count before saturation / timeout. E.g. with
194 | // PN53x it can count up to 65535 cycles, avout 4.8ms with a precision of about
195 | // 73ns. If you're ok with the defaults, call this function with cycles = 0. If
196 | // you need to count more cycles, set cycles to the maximum you exprect, but
197 | // don't forget you'll loose in precision and it'll take more time before
198 | // timeout, so don't abuse!
199 | //
200 | // Warning: The configuration option EASY_FRAMING must be set to false; the
201 | // configuration option HANDLE_PARITY must be set to true (default value).
202 | func (d Device) InitiatorTransceiveBytesTimed(tx, rx []byte, cycles uint32) (n int, c uint32, err error) {
203 | if *d.d == nil {
204 | return ESOFT, 0, errors.New("device closed")
205 | }
206 |
207 | var cptr *C.uint32_t
208 | *cptr = C.uint32_t(cycles)
209 |
210 | txptr := (*C.uint8_t)(&tx[0])
211 | rxptr := (*C.uint8_t)(&rx[0])
212 |
213 | n = int(C.nfc_initiator_transceive_bytes_timed(
214 | *d.d,
215 | txptr, C.size_t(len(tx)),
216 | rxptr, C.size_t(len(rx)),
217 | cptr,
218 | ))
219 |
220 | if n < 0 {
221 | err = Error(n)
222 | }
223 |
224 | c = uint32(*cptr)
225 |
226 | return
227 | }
228 |
229 | // Transceive raw bit-frames to a target. n contains the received byte count on
230 | // success, or is meaningless on error. c will contain the actual number of
231 | // cycles waited. The current implementation will return the libnfc error code
232 | // in case of error, but this is subject to change. If txLength is longer than
233 | // the supplied slice, an error will occur. txPar has to have the same length as
234 | // tx, dito for rxPar and rx. An error will occur if any of these invariants do
235 | // not hold.
236 | //
237 | // This function is similar to Device.InitiatorTransceiveBits() with the
238 | // following differences:
239 | //
240 | // - A precise cycles counter will indicate the number of cycles between emission & reception of frames.
241 | // - Only modes with EASY_FRAMING option disabled are supported and CRC must be handled manually.
242 | // - Overall communication with the host is heavier and slower.
243 | //
244 | // By default the timer configuration tries to maximize the precision, which
245 | // also limits the maximum cycle count before saturation / timeout. E.g. with
246 | // PN53x it can count up to 65535 cycles, avout 4.8ms with a precision of about
247 | // 73ns. If you're ok with the defaults, call this function with cycles = 0. If
248 | // you need to count more cycles, set cycles to the maximum you exprect, but
249 | // don't forget you'll loose in precision and it'll take more time before
250 | // timeout, so don't abuse!
251 | //
252 | // Warning: The configuration option EASY_FRAMING must be set to false; the
253 | // configuration option HANDLE_CRC must be set to false; the configuration
254 | // option HANDLE_PARITY must be set to true (the default value).
255 | func (d Device) InitiatorTransceiveBitsTimed(tx, txPar []byte, txLength uint, rx, rxPar []byte, cycles uint32) (n int, c uint32, err error) {
256 | if *d.d == nil {
257 | return ESOFT, 0, errors.New("device closed")
258 | }
259 |
260 | if len(tx) != len(txPar) || len(rx) != len(rxPar) {
261 | return ESOFT, 0, errors.New("invariant doesn't hold")
262 | }
263 |
264 | if uint(len(tx))*8 < txLength {
265 | return ESOFT, 0, errors.New("slice shorter than specified bit count")
266 | }
267 |
268 | var cptr *C.uint32_t
269 | *cptr = C.uint32_t(cycles)
270 |
271 | txptr := (*C.uint8_t)(&tx[0])
272 | txparptr := (*C.uint8_t)(&txPar[0])
273 | rxptr := (*C.uint8_t)(&rx[0])
274 | rxparptr := (*C.uint8_t)(&rxPar[0])
275 |
276 | n = int(C.nfc_initiator_transceive_bits_timed(
277 | *d.d,
278 | txptr, C.size_t(txLength), txparptr,
279 | rxptr, C.size_t(len(rx)), rxparptr,
280 | cptr,
281 | ))
282 |
283 | c = uint32(*cptr)
284 |
285 | if n < 0 {
286 | err = Error(n)
287 | }
288 |
289 | return
290 | }
291 |
292 | // Check target presence. Returns nil on success, an error otherwise. The
293 | // target has to be selected before you can check its presence. To run the test,
294 | // one or more commands will be sent to the target. The t argument can be nil,
295 | // in this case presence will be tested for the last selected tag.
296 | func (d Device) InitiatorTargetIsPresent(t Target) error {
297 | if *d.d == nil {
298 | return errors.New("device closed")
299 | }
300 |
301 | var ctarget *C.nfc_target
302 | if t != nil {
303 | ctarget = (*C.nfc_target)(unsafe.Pointer(t.Marshall()))
304 | defer C.free(unsafe.Pointer(ctarget))
305 | } else {
306 | ctarget = nil
307 | }
308 |
309 | n := C.nfc_initiator_target_is_present(*d.d, ctarget)
310 | if n != 0 {
311 | return Error(n)
312 | }
313 |
314 | return nil
315 | }
316 |
317 | // Initialize NFC device as initiator (reader). After initialization it can be
318 | // used to communicate to passive RFID tags and active NFC devices. The reader
319 | // will act as initiator to communicate peer 2 peer (NFCIP) to other active NFC
320 | // devices. The NFC device will be initialized with the following properties:
321 | // - CRC is handled by the device (NP_HANDLE_CRC = true)
322 | // - Parity is handled the device (NP_HANDLE_PARITY = true)
323 | // - Cryto1 cipher is disabled (NP_ACTIVATE_CRYPTO1 = false)
324 | // - Easy framing is enabled (NP_EASY_FRAMING = true)
325 | // - Auto-switching in ISO14443-4 mode is enabled (NP_AUTO_ISO14443_4 = true)
326 | // - Invalid frames are not accepted (NP_ACCEPT_INVALID_FRAMES = false)
327 | // - Multiple frames are not accepted (NP_ACCEPT_MULTIPLE_FRAMES = false)
328 | // - 14443-A mode is activated (NP_FORCE_ISO14443_A = true)
329 | // - speed is set to 106 kbps (NP_FORCE_SPEED_106 = true)
330 | // - Let the device try forever to find a target (NP_INFINITE_SELECT = true)
331 | // - RF field is shortly dropped (if it was enabled) then activated again
332 | func (d Device) InitiatorInit() error {
333 | if *d.d == nil {
334 | return errors.New("device closed")
335 | }
336 |
337 | n := C.nfc_initiator_init(*d.d)
338 | if n != 0 {
339 | return Error(n)
340 | }
341 |
342 | return nil
343 | }
344 |
345 | // Initialize NFC device as initiator with its secure element initiator
346 | // (reader). After initialization it can be used to communicate with the secure
347 | // element. The RF field is deactivated in order to save power.
348 | func (d Device) InitiatorInitSecureElement() error {
349 | if *d.d == nil {
350 | return errors.New("device closed")
351 | }
352 |
353 | return Error(C.nfc_initiator_init_secure_element(*d.d))
354 | }
355 |
356 | // Select a passive or emulated tag. initData is used with different kind of
357 | // data depending on modulation type:
358 | // - for an ISO/IEC 14443 type A modulation, initData contains the UID you want to select;
359 | // - for an ISO/IEC 14443 type B modulation, initData contains Application Family Identifier (AFI) (see ISO/IEC 14443-3) and optionally a second byte = 0x01 if you want to use probabilistic approach instead of timeslot approach;
360 | // - for a FeliCa modulation, initData contains a 5-byte polling payload (see ISO/IEC 18092 11.2.2.5).
361 | // - for ISO14443B', ASK CTx and ST SRx, see corresponding standards
362 | //
363 | // if nil, default values adequate for the chosen modulation will be used.
364 | func (d Device) InitiatorSelectPassiveTarget(m Modulation, initData []byte) (Target, error) {
365 | if *d.d == nil {
366 | return nil, errors.New("device closed")
367 | }
368 |
369 | var pnt C.nfc_target
370 | var initDataPtr *C.uint8_t = nil
371 | var initDataLen C.size_t = 0
372 |
373 | if initData != nil {
374 | initDataPtr = (*C.uint8_t)(&initData[0])
375 | initDataLen = C.size_t(len(initData))
376 | }
377 |
378 | n := C.nfc_initiator_select_passive_target(
379 | *d.d,
380 | C.nfc_modulation{C.nfc_modulation_type(m.Type), C.nfc_baud_rate(m.BaudRate)},
381 | initDataPtr, initDataLen, &pnt)
382 | if n < 0 {
383 | return nil, Error(n)
384 | }
385 |
386 | return unmarshallTarget(&pnt), nil
387 | }
388 |
389 | // List passive or emulated tags. The NFC device will try to find the available
390 | // passive tags. Some NFC devices are capable to emulate passive tags. The
391 | // standards (ISO18092 and ECMA-340) describe the modulation that can be used
392 | // for reader to passive communications. The chip needs to know with what kind
393 | // of tag it is dealing with, therefore the initial modulation and speed (106,
394 | // 212 or 424 kbps) should be supplied.
395 | func (d Device) InitiatorListPassiveTargets(m Modulation) ([]Target, error) {
396 | if *d.d == nil {
397 | return nil, errors.New("device closed")
398 | }
399 |
400 | mod := C.nfc_modulation{
401 | nmt: C.nfc_modulation_type(m.Type),
402 | nbr: C.nfc_baud_rate(m.BaudRate),
403 | }
404 |
405 | tar := C.list_targets_wrapper(*d.d, mod)
406 | defer C.free(unsafe.Pointer(tar.entries))
407 | if tar.count < 0 {
408 | return nil, Error(tar.count)
409 | }
410 |
411 | targets := make([]Target, tar.count)
412 | for i := range targets {
413 | // index the C array using pointer arithmetic
414 | ptr := uintptr(unsafe.Pointer(tar.entries)) + uintptr(i)*unsafe.Sizeof(*tar.entries)
415 | targets[i] = unmarshallTarget((*C.nfc_target)(unsafe.Pointer(ptr)))
416 | }
417 |
418 | return targets, nil
419 | }
420 |
421 | // Deselect a selected passive or emulated tag. After selecting and
422 | // communicating with a passive tag, this function could be used to deactivate
423 | // and release the tag. This is very useful when there are multiple tags
424 | // available in the field. It is possible to use the
425 | // InitiatorSelectPassiveTarget() method to select the first available tag, test
426 | // it for the available features and support, deselect it and skip to the next
427 | // tag until the correct tag is found.
428 | func (d Device) InitiatorDeselectTarget() error {
429 | if *d.d == nil {
430 | return errors.New("device closed")
431 | }
432 |
433 | n := C.nfc_initiator_deselect_target(*d.d)
434 | if n != 0 {
435 | return Error(n)
436 | }
437 |
438 | return nil
439 | }
440 |
--------------------------------------------------------------------------------
/v2/marshall.c:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 2014, 2020, Robert Clausecker
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published by the
6 | * Free Software Foundation, version 3.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 | * more details.
12 | *
13 | * You should have received a copy of the GNU Lesser General Public License
14 | * along with this program. If not, see
15 | */
16 | #include
17 | #include "marshall.h"
18 |
19 | /* see marshall.h for what this code does */
20 |
21 | extern int
22 | getModulationType(const nfc_target *nt)
23 | {
24 | return (nt->nm.nmt);
25 | }
26 |
27 | extern void
28 | unmarshallDEPTarget(struct DEPTarget *dt, const nfc_target *nt)
29 | {
30 | const nfc_dep_info *di = &nt->nti.ndi;
31 |
32 | memcpy(dt->NFCID3, di->abtNFCID3, sizeof(dt->NFCID3));
33 | dt->DID = di->btDID;
34 | dt->BS = di->btBS;
35 | dt->BR = di->btBR;
36 | dt->TO = di->btTO;
37 | dt->PP = di->btPP;
38 | memcpy(dt->GB, di->abtGB, sizeof(dt->GB));
39 | dt->GBLen = di->szGB;
40 | dt->DepMode = di->ndm;
41 |
42 | dt->Baud = nt->nm.nbr;
43 | }
44 |
45 | extern void
46 | marshallDEPTarget(nfc_target *nt, const struct DEPTarget *dt)
47 | {
48 | nfc_dep_info *di = &nt->nti.ndi;
49 |
50 | memcpy(di->abtNFCID3, dt->NFCID3, sizeof(dt->NFCID3));
51 | di->btDID = dt->DID;
52 | di->btBS = dt->BS;
53 | di->btBR = dt->BR;
54 | di->btTO = dt->TO;
55 | di->btPP = dt->PP;
56 | memcpy(di->abtGB, dt->GB, sizeof(dt->GB));
57 | di->szGB = dt->GBLen;
58 | di->ndm = dt->DepMode;
59 |
60 | nt->nm.nbr = dt->Baud;
61 | nt->nm.nmt = NMT_DEP;
62 | }
63 |
64 | extern void
65 | unmarshallISO14443aTarget(struct ISO14443aTarget *it, const nfc_target *nt)
66 | {
67 | const nfc_iso14443a_info *ii = &nt->nti.nai;
68 |
69 | memcpy(it->Atqa, ii->abtAtqa, sizeof(it->Atqa));
70 | it->Sak = ii->btSak;
71 | it->UIDLen = ii->szUidLen;
72 | memcpy(it->UID, ii->abtUid, sizeof(it->UID));
73 | it->AtsLen = ii->szAtsLen;
74 | memcpy(it->Ats, ii->abtAts, sizeof(it->Ats));
75 |
76 | it->Baud = nt->nm.nbr;
77 | }
78 |
79 | extern void
80 | marshallISO14443aTarget(nfc_target *nt, const struct ISO14443aTarget *it)
81 | {
82 | nfc_iso14443a_info *ii = &nt->nti.nai;
83 |
84 | memcpy(ii->abtAtqa, it->Atqa, sizeof(it->Atqa));
85 | ii->btSak = it->Sak;
86 | ii->szUidLen = it->UIDLen;
87 | memcpy(ii->abtUid, it->UID, sizeof(it->UID));
88 | ii->szAtsLen = it->AtsLen;
89 | memcpy(ii->abtAts, it->Ats, sizeof(it->Ats));
90 |
91 | nt->nm.nbr = it->Baud;
92 | nt->nm.nmt = NMT_ISO14443A;
93 | }
94 |
95 | extern void
96 | unmarshallFelicaTarget(struct FelicaTarget *ft, const nfc_target *nt)
97 | {
98 | const nfc_felica_info *fi = &nt->nti.nfi;
99 |
100 | ft->Len = fi->szLen;
101 | ft->ResCode = fi->btResCode;
102 | memcpy(ft->ID, fi->abtId, sizeof(ft->ID));
103 | memcpy(ft->Pad, fi->abtPad, sizeof(ft->Pad));
104 | memcpy(ft->SysCode, fi->abtSysCode, sizeof(ft->SysCode));
105 |
106 | ft->Baud = nt->nm.nbr;
107 | }
108 |
109 | extern void
110 | marshallFelicaTarget(nfc_target *nt, const struct FelicaTarget *ft)
111 | {
112 | nfc_felica_info *fi = &nt->nti.nfi;
113 |
114 | fi->szLen = ft->Len;
115 | fi->btResCode = ft->ResCode;
116 | memcpy(fi->abtId, ft->ID, sizeof(ft->ID));
117 | memcpy(fi->abtPad, ft->Pad, sizeof(ft->Pad));
118 | memcpy(fi->abtSysCode, ft->SysCode, sizeof(ft->SysCode));
119 |
120 | nt->nm.nbr = ft->Baud;
121 | nt->nm.nmt = NMT_FELICA;
122 | }
123 |
124 | extern void
125 | unmarshallISO14443bTarget(struct ISO14443bTarget *it, const nfc_target *nt)
126 | {
127 | const nfc_iso14443b_info *ii = &nt->nti.nbi;
128 |
129 | memcpy(it->Pupi, ii->abtPupi, sizeof(it->Pupi));
130 | memcpy(it->ApplicationData, ii->abtApplicationData, sizeof(it->ApplicationData));
131 | memcpy(it->ProtocolInfo, ii->abtProtocolInfo, sizeof(it->ProtocolInfo));
132 | it->CardIdentifier = ii->ui8CardIdentifier;
133 |
134 | it->Baud = nt->nm.nbr;
135 | }
136 |
137 | extern void
138 | marshallISO14443bTarget(nfc_target *nt, const struct ISO14443bTarget *it)
139 | {
140 | nfc_iso14443b_info *ii = &nt->nti.nbi;
141 |
142 | memcpy(ii->abtPupi, it->Pupi, sizeof(it->Pupi));
143 | memcpy(ii->abtApplicationData, it->ApplicationData, sizeof(it->ApplicationData));
144 | memcpy(ii->abtProtocolInfo, it->ProtocolInfo, sizeof(it->ProtocolInfo));
145 | ii->ui8CardIdentifier = it->CardIdentifier;
146 |
147 | nt->nm.nbr = it->Baud;
148 | nt->nm.nmt = NMT_ISO14443B;
149 | }
150 |
151 | extern void
152 | unmarshallISO14443biTarget(struct ISO14443biTarget *it, const nfc_target *nt)
153 | {
154 | const nfc_iso14443bi_info *ii = &nt->nti.nii;
155 |
156 | memcpy(it->DIV, ii->abtDIV, sizeof(it->DIV));
157 | it->VerLog = ii->btVerLog;
158 | it->Config = ii->btConfig;
159 | it->AtrLen = ii->szAtrLen;
160 | memcpy(it->Atr, ii->abtAtr, sizeof(it->Atr));
161 |
162 | it->Baud = nt->nm.nbr;
163 | }
164 |
165 | extern void
166 | marshallISO14443biTarget(nfc_target *nt, const struct ISO14443biTarget *it)
167 | {
168 | nfc_iso14443bi_info *ii = &nt->nti.nii;
169 |
170 | memcpy(ii->abtDIV, it->DIV, sizeof(it->DIV));
171 | ii->btVerLog = it->VerLog;
172 | ii->btConfig = it->Config;
173 | ii->szAtrLen = it->AtrLen;
174 | memcpy(ii->abtAtr, it->Atr, sizeof(it->Atr));
175 |
176 | nt->nm.nbr = it->Baud;
177 | nt->nm.nmt = NMT_ISO14443BI;
178 | }
179 |
180 | extern void
181 | unmarshallISO14443b2srTarget(struct ISO14443b2srTarget *it, const nfc_target *nt)
182 | {
183 | const nfc_iso14443b2sr_info *ii = &nt->nti.nsi;
184 |
185 | memcpy(it->UID, ii->abtUID, sizeof(it->UID));
186 |
187 | it->Baud = nt->nm.nbr;
188 | }
189 |
190 | extern void
191 | marshallISO14443b2srTarget(nfc_target *nt, const struct ISO14443b2srTarget *it)
192 | {
193 | nfc_iso14443b2sr_info *ii = &nt->nti.nsi;
194 |
195 | memcpy(ii->abtUID, it->UID, sizeof(it->UID));
196 |
197 | nt->nm.nbr = it->Baud;
198 | nt->nm.nmt = NMT_ISO14443B2SR;
199 | }
200 |
201 | extern void
202 | unmarshallISO14443b2ctTarget(struct ISO14443b2ctTarget *it, const nfc_target *nt)
203 | {
204 | const nfc_iso14443b2ct_info *ii = &nt->nti.nci;
205 |
206 | memcpy(it->UID, ii->abtUID, sizeof(it->UID));
207 | it->ProdCode = ii->btProdCode;
208 | it->FabCode = ii->btFabCode;
209 |
210 | it->Baud = nt->nm.nbr;
211 | }
212 |
213 | extern void
214 | marshallISO14443b2ctTarget(nfc_target *nt, const struct ISO14443b2ctTarget *it)
215 | {
216 | nfc_iso14443b2ct_info *ii = &nt->nti.nci;
217 |
218 | memcpy(ii->abtUID, it->UID, sizeof(it->UID));
219 | ii->btProdCode = it->ProdCode;
220 | ii->btFabCode = it->FabCode;
221 |
222 | nt->nm.nbr = it->Baud;
223 | nt->nm.nmt = NMT_ISO14443B2CT;
224 | }
225 |
226 | extern void
227 | unmarshallJewelTarget(struct JewelTarget *jt, const nfc_target *nt)
228 | {
229 | const nfc_jewel_info *ji = &nt->nti.nji;
230 |
231 | memcpy(jt->SensRes, ji->btSensRes, sizeof(jt->SensRes));
232 | memcpy(jt->ID, ji->btId, sizeof(jt->ID));
233 |
234 | jt->Baud = nt->nm.nbr;
235 | }
236 |
237 | extern void
238 | marshallJewelTarget(nfc_target *nt, const struct JewelTarget *jt)
239 | {
240 | nfc_jewel_info *ji = &nt->nti.nji;
241 |
242 | memcpy(ji->btSensRes, jt->SensRes, sizeof(jt->SensRes));
243 | memcpy(ji->btId, jt->ID, sizeof(jt->ID));
244 |
245 | nt->nm.nbr = jt->Baud;
246 | nt->nm.nmt = NMT_JEWEL;
247 | }
248 |
249 | extern void
250 | unmarshallBarcodeTarget(struct BarcodeTarget *bt, const nfc_target *nt)
251 | {
252 | const nfc_barcode_info *bi = &nt->nti.nti;
253 |
254 | bt->DataLen = bi->szDataLen;
255 | memcpy(bt->Data, bi->abtData, sizeof(bt->Data));
256 |
257 | bt->Baud = nt->nm.nbr;
258 | }
259 |
260 | extern void
261 | marshallBarcodeTarget(nfc_target *nt, const struct BarcodeTarget *bt)
262 | {
263 | nfc_barcode_info *bi = &nt->nti.nti;
264 |
265 | bi->szDataLen = bt->DataLen;
266 | memcpy(bi->abtData, bt->Data, sizeof(bt->Data));
267 |
268 | nt->nm.nbr = bt->Baud;
269 | nt->nm.nmt = NMT_BARCODE;
270 | }
271 |
272 | extern void
273 | unmarshallISO14443biClassTarget(struct ISO14443biClassTarget *it, const nfc_target *nt)
274 | {
275 | const nfc_iso14443biclass_info *ii = &nt->nti.nhi;
276 |
277 | memcpy(it->UID, ii->abtUID, sizeof(it->UID));
278 |
279 | it->Baud = nt->nm.nbr;
280 | }
281 |
282 | extern void
283 | marshallISO14443biClassTarget(nfc_target *nt, const struct ISO14443biClassTarget *it)
284 | {
285 | nfc_iso14443biclass_info *ii = &nt->nti.nhi;
286 |
287 | memcpy(ii->abtUID, it->UID, sizeof(it->UID));
288 |
289 | nt->nm.nbr = it->Baud;
290 | nt->nm.nmt = NMT_ISO14443BICLASS;
291 | }
292 |
--------------------------------------------------------------------------------
/v2/marshall.h:
--------------------------------------------------------------------------------
1 | /*-
2 | * Copyright (c) 2014, 2020, Robert Clausecker
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published by the
6 | * Free Software Foundation, version 3.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 | * more details.
12 | *
13 | * You should have received a copy of the GNU Lesser General Public License
14 | * along with this program. If not, see
15 | */
16 | #ifndef MARSHALL_H
17 | #define MARSHALL_H
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | /*
24 | * Marshalling code. The code in this translation unit marshalls between the
25 | * nfc_xxx_info and the XxxTarget types.
26 | *
27 | * The marshalling code cannot easily be written in Go as the libnfc uses
28 | * #pragma pack to change the alignment of some structures from something
29 | * perfectly usably to something cgo cannot work with. Writing the marshalling
30 | * code in straight C is also not possible as there is no easy way to refer to
31 | * Go types from within C code.
32 | *
33 | * The following code uses a somewhat hacky approach: For each Go structure we
34 | * create an equal C structure and hope that they match. Then we marshall the
35 | * data in C and cast the pointers to corresponding Go type.
36 | */
37 |
38 | /*
39 | * On all platforms where a Go port exists, the Go type int has the same
40 | * attributes as the C type ptrdiff_t.
41 | */
42 | typedef ptrdiff_t GoInt;
43 |
44 | /* return field nfc_target.nm.nmt */
45 | extern int getModulationType(const nfc_target*);
46 |
47 | /* functions to deal with specific targets */
48 |
49 | struct DEPTarget {
50 | uint8_t NFCID3[10];
51 | uint8_t DID;
52 | uint8_t BS;
53 | uint8_t BR;
54 | uint8_t TO;
55 | uint8_t PP;
56 | uint8_t GB[48];
57 | GoInt GBLen;
58 | GoInt DepMode;
59 | GoInt Baud;
60 | };
61 |
62 | extern void unmarshallDEPTarget(struct DEPTarget*, const nfc_target*);
63 | extern void marshallDEPTarget(nfc_target*, const struct DEPTarget*);
64 |
65 | struct ISO14443aTarget {
66 | uint8_t Atqa[2];
67 | uint8_t Sak;
68 | GoInt UIDLen;
69 | uint8_t UID[10];
70 | GoInt AtsLen;
71 | uint8_t Ats[254];
72 | GoInt Baud;
73 | };
74 |
75 | extern void unmarshallISO14443aTarget(struct ISO14443aTarget*, const nfc_target*);
76 | extern void marshallISO14443aTarget(nfc_target*, const struct ISO14443aTarget*);
77 |
78 | struct FelicaTarget {
79 | GoInt Len;
80 | uint8_t ResCode;
81 | uint8_t ID[8];
82 | uint8_t Pad[8];
83 | uint8_t SysCode[2];
84 | GoInt Baud;
85 | };
86 |
87 | extern void unmarshallFelicaTarget(struct FelicaTarget*, const nfc_target*);
88 | extern void marshallFelicaTarget(nfc_target*, const struct FelicaTarget*);
89 |
90 | struct ISO14443bTarget {
91 | uint8_t Pupi[4];
92 | uint8_t ApplicationData[4];
93 | uint8_t ProtocolInfo[3];
94 | uint8_t CardIdentifier;
95 | GoInt Baud;
96 | };
97 |
98 | extern void unmarshallISO14443bTarget(struct ISO14443bTarget*, const nfc_target*);
99 | extern void marshallISO14443bTarget(nfc_target*, const struct ISO14443bTarget*);
100 |
101 | struct ISO14443biTarget {
102 | uint8_t DIV[4];
103 | uint8_t VerLog;
104 | uint8_t Config;
105 | GoInt AtrLen;
106 | uint8_t Atr[33];
107 | GoInt Baud;
108 | };
109 |
110 | extern void unmarshallISO14443biTarget(struct ISO14443biTarget*, const nfc_target*);
111 | extern void marshallISO14443biTarget(nfc_target*, const struct ISO14443biTarget*);
112 |
113 | struct ISO14443b2srTarget {
114 | uint8_t UID[8];
115 | GoInt Baud;
116 | };
117 |
118 | extern void unmarshallISO14443b2srTarget(struct ISO14443b2srTarget*, const nfc_target*);
119 | extern void marshallISO14443b2srTarget(nfc_target*, const struct ISO14443b2srTarget*);
120 |
121 | struct ISO14443b2ctTarget {
122 | uint8_t UID[4];
123 | uint8_t ProdCode;
124 | uint8_t FabCode;
125 | GoInt Baud;
126 | };
127 |
128 | extern void unmarshallISO14443b2ctTarget(struct ISO14443b2ctTarget*, const nfc_target*);
129 | extern void marshallISO14443b2ctTarget(nfc_target*, const struct ISO14443b2ctTarget*);
130 |
131 | struct JewelTarget {
132 | uint8_t SensRes[2];
133 | uint8_t ID[4];
134 | GoInt Baud;
135 | };
136 |
137 | extern void unmarshallJewelTarget(struct JewelTarget*, const nfc_target*);
138 | extern void marshallJewelTarget(nfc_target*, const struct JewelTarget*);
139 |
140 | struct BarcodeTarget {
141 | GoInt DataLen;
142 | uint8_t Data[32];
143 | GoInt Baud;
144 | };
145 |
146 | extern void unmarshallBarcodeTarget(struct BarcodeTarget*, const nfc_target*);
147 | extern void marshallBarcodeTarget(nfc_target*, const struct BarcodeTarget*);
148 |
149 | struct ISO14443biClassTarget {
150 | uint8_t UID[8];
151 | GoInt Baud;
152 | };
153 |
154 | extern void unmarshallISO14443biClassTarget(struct ISO14443biClassTarget*, const nfc_target*);
155 | extern void marshallISO14443biClassTarget(nfc_target*, const struct ISO14443biClassTarget*);
156 |
157 | #endif /* MARSHALL_H */
158 |
--------------------------------------------------------------------------------
/v2/nfc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, 2020, 2024 Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | // Package nfc wraps the libnfc to provide an API for Go. Most documentation
16 | // was taken unchanged from the documentation inside the libnfc. Some functions
17 | // and names have been altered to fit the conventions and idioms used in Go.
18 | //
19 | // To use this package, obtain and install libnfc. By default, pkg-config is
20 | // used to find and link libnfc. If you cannot use pkg-config, you can compile
21 | // with build-tag nopkgconfig or no_pkgconfig to instead link with -lnfc.
22 | package nfc
23 |
24 | import "fmt"
25 | import "strconv"
26 |
27 | // Maximum length for an NFC connection string
28 | const BufsizeConnstring = 1024
29 |
30 | // Properties for (*Device).SetPropertyInt() and (*Device).SetPropertyBool().
31 | const (
32 | // Default command processing timeout
33 | // Property value's (duration) unit is ms and 0 means no timeout (infinite).
34 | // Default value is set by driver layer
35 | TimeoutCommand = iota
36 |
37 | // Timeout between ATR_REQ and ATR_RES
38 | // When the device is in initiator mode, a target is considered as mute
39 | // if no valid ATR_RES is received within this timeout value.
40 | // Default value for this property is 103 ms on PN53x based devices.
41 | TimeoutATR
42 |
43 | // Timeout value to give up reception from the target in case of no answer.
44 | // Default value for this property is 52 ms).
45 | TimeoutCom
46 |
47 | // Let the PN53X chip handle the CRC bytes. This means that the chip
48 | // appends the CRC bytes to the frames that are transmitted. It will
49 | // parse the last bytes from received frames as incoming CRC bytes. They
50 | // will be verified against the used modulation and protocol. If a frame
51 | // is expected with incorrect CRC bytes this option should be disabled.
52 | // Example frames where this is useful are the ATQA and UID+BCC that are
53 | // transmitted without CRC bytes during the anti-collision phase of the
54 | // ISO14443-A protocol.
55 | HandleCRC
56 |
57 | // Parity bits in the network layer of ISO14443-A are by default
58 | // generated and validated in the PN53X chip. This is a very convenient
59 | // feature. On certain times though it is useful to get full control of
60 | // the transmitted data. The proprietary MIFARE Classic protocol uses
61 | // for example custom (encrypted) parity bits. For interoperability it
62 | // is required to be completely compatible, including the arbitrary
63 | // parity bits. When this option is disabled, the functions to
64 | // communicating bits should be used.
65 | HandleParity
66 |
67 | // This option can be used to enable or disable the electronic field of
68 | // the NFC device.
69 | ActivateField
70 |
71 | // The internal CRYPTO1 co-processor can be used to transmit messages
72 | // encrypted. This option is automatically activated after a successful
73 | // MIFARE Classic authentication.
74 | ActivateCrypto1
75 |
76 | // The default configuration defines that the PN53X chip will try
77 | // indefinitely to invite a tag in the field to respond. This could be
78 | // desired when it is certain a tag will enter the field. On the other
79 | // hand, when this is uncertain, it will block the application. This
80 | // option could best be compared to the (NON)BLOCKING option used by
81 | // (socket)network programming.
82 | InfiniteSelect
83 |
84 | // If this option is enabled, frames that carry less than 4 bits are
85 | // allowed. According to the standards these frames should normally be
86 | // handles as invalid frames.
87 | AcceptInvalidFrames
88 |
89 | // If the NFC device should only listen to frames, it could be useful to
90 | // let it gather multiple frames in a sequence. They will be stored in
91 | // the internal FIFO of the PN53X chip. This could be retrieved by using
92 | // the receive data functions. Note that if the chip runs out of bytes
93 | // (FIFO = 64 bytes long), it will overwrite the first received frames,
94 | // so quick retrieving of the received data is desirable.
95 | AcceptMultipleFrames
96 |
97 | // This option can be used to enable or disable the auto-switching mode
98 | // to ISO14443-4 is device is compliant.
99 | // In initiator mode, it means that NFC chip will send RATS
100 | // automatically when select and it will automatically poll for
101 | // ISO14443-4 card when ISO14443A is requested.
102 | // In target mode, with a NFC chip compliant (ie. PN532), the chip will
103 | // emulate a 14443-4 PICC using hardware capability.
104 | AutoISO14443_4
105 |
106 | // Use automatic frames encapsulation and chaining.
107 | EasyFraming
108 |
109 | // Force the chip to switch in ISO14443-A
110 | ForceISO14443a
111 |
112 | // Force the chip to switch in ISO14443-B
113 | ForceISO14443b
114 |
115 | // Force the chip to run at 106 kbps
116 | ForceSpeed106
117 | )
118 |
119 | // NFC modulation types
120 | const (
121 | ISO14443a = iota + 1
122 | Jewel
123 | ISO14443b
124 | ISO14443bi // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
125 | ISO14443b2sr // ISO14443-2B ST SRx
126 | ISO14443b2ct // ISO14443-2B ASK CTx
127 | Felica
128 | DEP
129 | Barcode // Thinfilm NFC Barcode
130 | ISO14443biClass // HID iClass 14443B mode
131 | )
132 |
133 | // NFC baud rates. UNDEFINED is also a valid baud rate, albeit defined
134 | // further below.
135 | const (
136 | Nbr106 = iota + 1
137 | Nbr212
138 | Nbr424
139 | Nbr847
140 | )
141 |
142 | // NFC modes. An NFC device can either be a target or an initiator.
143 | const (
144 | TargetMode = iota
145 | InitiatorMode
146 | )
147 |
148 | // Names corresponding to the NFC modulation types
149 | var ModulationTypes = [...]string{
150 | 0: "0",
151 | ISO14443a: "ISO14443a",
152 | Jewel: "Jewel",
153 | ISO14443b: "ISO14443b",
154 | ISO14443bi: "ISO14443bi",
155 | ISO14443b2sr: "ISO14443b2sr",
156 | ISO14443b2ct: "ISO14443b2ct",
157 | Felica: "Felica",
158 | DEP: "DEP",
159 | Barcode: "Barcode",
160 | ISO14443biClass: "ISO14443biClass",
161 | }
162 |
163 | // Baud rates corresponding to the baud rate enumeration constants
164 | var BaudRates = [...]string{
165 | Undefined: "Undefined",
166 | Nbr106: "106",
167 | Nbr212: "212",
168 | Nbr424: "424",
169 | Nbr847: "847",
170 | }
171 |
172 | // NFC modulation structure. Use the supplied constants.
173 | type Modulation struct {
174 | Type int
175 | BaudRate int
176 | }
177 |
178 | // Print a modulation in a human readable manner.
179 | func (m Modulation) String() string {
180 | var typeStr, brStr string
181 |
182 | if 0 <= m.Type && m.Type < len(ModulationTypes) {
183 | typeStr = ModulationTypes[m.Type]
184 | } else {
185 | typeStr = strconv.Itoa(m.Type)
186 | }
187 |
188 | if 0 <= m.BaudRate && m.BaudRate < len(BaudRates) {
189 | brStr = BaudRates[m.BaudRate] + " kbps"
190 | } else {
191 | brStr = strconv.Itoa(m.BaudRate)
192 | }
193 |
194 | return typeStr + " (" + brStr + ")"
195 | }
196 |
197 | // Print a modulation in Go syntax.
198 | func (m Modulation) GoString() string {
199 | var typeStr, brStr string
200 |
201 | if 0 <= m.Type && m.Type < len(ModulationTypes) {
202 | typeStr = "nfc." + ModulationTypes[m.Type]
203 | } else {
204 | typeStr = strconv.Itoa(m.Type)
205 | }
206 |
207 | if m.BaudRate == 0 {
208 | brStr = "nfc.Undefined"
209 | } else if 0 < m.BaudRate && m.BaudRate < len(BaudRates) {
210 | brStr = "nfc.Nbr" + BaudRates[m.BaudRate]
211 | } else {
212 | brStr = strconv.Itoa(m.BaudRate)
213 | }
214 |
215 | return "nfc.Modulation{Type: " + typeStr + ", BaudRate: " + brStr + "}"
216 | }
217 |
218 | // An error as reported by various methods of Device. If device returns an error
219 | // that is not castable to Error, something outside on the Go side went wrong.
220 | type Error int
221 |
222 | // Returns the same strings as nfc_errstr except if the error is not among the
223 | // known errors. Instead of reporting an "Unknown error", Error() will return
224 | // something like "Error -123".
225 | func (e Error) Error() string {
226 | if errorMessages[int(e)] == "" {
227 | return fmt.Sprintf("Error %d", int(e))
228 | }
229 |
230 | return errorMessages[int(e)]
231 | }
232 |
233 | // Error codes. Casted to Error, these yield all possible errors this package
234 | // provides. Use nfc.Error(errorcode).Error() to get a descriptive string for an
235 | // error code.
236 | const (
237 | SUCCESS = 0 // Success (no error)
238 | EIO = -1 // Input / output error, device may not be usable anymore without re-open it
239 | EINVARG = -2 // Invalid argument(s)
240 | EDEVNOTSUPP = -3 // Operation not supported by device
241 | ENOTSUCHDEV = -4 // No such device
242 | EOVFLOW = -5 // Buffer overflow
243 | ETIMEOUT = -6 // Operation timed out
244 | EOPABORTED = -7 // Operation aborted (by user)
245 | ENOTIMPL = -8 // Not (yet) implemented
246 | ETGRELEASED = -10 // Target released
247 | ERFTRANS = -20 // Error during RF transmission
248 | EMFCAUTHFAIL = -30 // MIFARE Classic: authentication failed
249 | ESOFT = -80 // Software error (allocation, file/pipe creation, etc.)
250 | ECHIP = -90 // Device's internal chip error
251 | )
252 |
253 | // replicate error messages here because the libnfc is incapable of giving
254 | // direct access to the error strings. Stupidly, only the error string for the
255 | // error code of an nfc_device can be read out.
256 | var errorMessages = map[int]string{
257 | SUCCESS: "success",
258 | EIO: "input / output error",
259 | EINVARG: "invalid argument(s)",
260 | EDEVNOTSUPP: "not supported by device",
261 | ENOTSUCHDEV: "no such device",
262 | EOVFLOW: "buffer overflow",
263 | ETIMEOUT: "timeout",
264 | EOPABORTED: "operation aborted",
265 | ENOTIMPL: "not (yet) implemented",
266 | ETGRELEASED: "target released",
267 | EMFCAUTHFAIL: "Mifare Classic authentication failed",
268 | ERFTRANS: "RF transmission error",
269 | ESOFT: "software error",
270 | ECHIP: "device's internal chip error",
271 | }
272 |
273 | // the global library context
274 | var theContext *context = &context{}
275 |
--------------------------------------------------------------------------------
/v2/nopkgconfig.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | //go:build no_pkgconfig || nopkgconfig
16 | // +build no_pkgconfig nopkgconfig
17 |
18 | package nfc
19 |
20 | // #cgo LDFLAGS: -lnfc
21 | import "C"
22 |
--------------------------------------------------------------------------------
/v2/pkgconfig.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | //go:build !no_pkgconfig && !nopkgconfig
16 | // +build !no_pkgconfig,!nopkgconfig
17 |
18 | package nfc
19 |
20 | // #cgo pkg-config: libnfc
21 | import "C"
22 |
--------------------------------------------------------------------------------
/v2/smoke_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024 Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | package nfc
16 |
17 | import "testing"
18 |
19 | // Verify that the devices can be listed without crashing.
20 | func TestListDevices(t *testing.T) {
21 | devs, err := ListDevices()
22 | if err != nil {
23 | t.Log("ListDevices() failed:", err)
24 | } else {
25 | t.Log("ListDevices():", devs)
26 | }
27 | }
28 |
29 | var testModulations []Modulation = []Modulation{
30 | {Type: ISO14443a, BaudRate: Nbr106},
31 | {Type: Felica, BaudRate: Nbr212},
32 | {Type: Felica, BaudRate: Nbr424},
33 | {Type: ISO14443b, BaudRate: Nbr106},
34 | {Type: ISO14443bi, BaudRate: Nbr106},
35 | {Type: ISO14443b2sr, BaudRate: Nbr106},
36 | {Type: ISO14443b2ct, BaudRate: Nbr106},
37 | {Type: ISO14443biClass, BaudRate: Nbr106},
38 | {Type: Jewel, BaudRate: Nbr106},
39 | {Type: Barcode, BaudRate: Nbr106},
40 | }
41 |
42 | // Open the first device and list all tags
43 | func TestInitiatorListPassiveTargets(t *testing.T) {
44 | dev, err := Open("")
45 | defer dev.Close()
46 | if err != nil {
47 | t.Skip("Cannot open device:", err)
48 | }
49 |
50 | for i := range testModulations {
51 | targets, err := dev.InitiatorListPassiveTargets(testModulations[i])
52 | if err != nil {
53 | t.Log(dev.GoString(), ".InitiatorListPassiveTargets:", err)
54 | t.FailNow()
55 | }
56 |
57 | t.Log(dev.Connection(), "/", testModulations[i], ":", targets)
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/v2/target.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, 2020, Robert Clausecker
2 | //
3 | // This program is free software: you can redistribute it and/or modify it
4 | // under the terms of the GNU Lesser General Public License as published by the
5 | // Free Software Foundation, version 3.
6 | //
7 | // This program is distributed in the hope that it will be useful, but WITHOUT
8 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
10 | // more details.
11 | //
12 | // You should have received a copy of the GNU Lesser General Public License
13 | // along with this program. If not, see
14 |
15 | package nfc
16 |
17 | // #include
18 | // #include "marshall.h"
19 | import "C"
20 | import "unsafe"
21 | import "errors"
22 |
23 | // allocate space using C.malloc() for a C.nfc_target.
24 | func mallocTarget() *C.nfc_target {
25 | targetSize := C.size_t(unsafe.Sizeof(C.nfc_target{}))
26 | return (*C.nfc_target)(C.malloc(targetSize))
27 | }
28 |
29 | // generic implementation for the String() functions of the Target interface.
30 | // Notice that this panics when TargetString returns an error.
31 | func tString(t Target) string {
32 | str, err := TargetString(t, true)
33 |
34 | if err != nil {
35 | panic(err)
36 | }
37 |
38 | return str
39 | }
40 |
41 | // Go wrapper for nfc_target. Since the nfc_target structure contains a union,
42 | // we cannot directly map it to a Go type. Modulation() can be used to figure
43 | // out what kind of modulation was used for this Target and what type an
44 | // interface can be casted into.
45 | //
46 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
47 | // contains the same data as the Target. Don't forget to C.free() the result of
48 | // Marshall() afterwards.
49 | type Target interface {
50 | Modulation() Modulation
51 | Marshall() uintptr
52 | String() string // uses TargetString() with verbose = true
53 | }
54 |
55 | // Make a string from a target with proper error reporting. This is a wrapper
56 | // around str_nfc_target.
57 | func TargetString(t Target, verbose bool) (string, error) {
58 | ptr := unsafe.Pointer(t.Marshall())
59 |
60 | var result *C.char = nil
61 |
62 | length := C.str_nfc_target(&result, (*C.nfc_target)(ptr), C.bool(verbose))
63 | defer C.nfc_free(unsafe.Pointer(result))
64 |
65 | if length < 0 {
66 | return "", Error(length)
67 | }
68 |
69 | return C.GoStringN(result, C.int(length)), nil
70 | }
71 |
72 | // Make a target from a pointer to an nfc_target. If the object you pass it not
73 | // an nfc_target, undefined behavior occurs and your program is likely to blow
74 | // up.
75 | func UnmarshallTarget(ptr unsafe.Pointer) Target {
76 | return unmarshallTarget((*C.nfc_target)(ptr))
77 | }
78 |
79 | // internal wrapper with C types for convenience
80 | func unmarshallTarget(t *C.nfc_target) Target {
81 | switch C.getModulationType(t) {
82 | case ISO14443a:
83 | r := unmarshallISO14443aTarget(t)
84 | return &r
85 | case Jewel:
86 | r := unmarshallJewelTarget(t)
87 | return &r
88 | case Barcode:
89 | r := unmarshallBarcodeTarget(t)
90 | return &r
91 | case ISO14443b:
92 | r := unmarshallISO14443bTarget(t)
93 | return &r
94 | case ISO14443bi:
95 | r := unmarshallISO14443biTarget(t)
96 | return &r
97 | case ISO14443b2sr:
98 | r := unmarshallISO14443b2srTarget(t)
99 | return &r
100 | case ISO14443b2ct:
101 | r := unmarshallISO14443b2ctTarget(t)
102 | return &r
103 | case Felica:
104 | r := unmarshallFelicaTarget(t)
105 | return &r
106 | case DEP:
107 | r := unmarshallDEPTarget(t)
108 | return &r
109 | case ISO14443biClass:
110 | r := unmarshallISO14443biClassTarget(t)
111 | return &r
112 | default:
113 | panic(errors.New("cannot determine target type"))
114 | }
115 | }
116 |
117 | // NFC D.E.P. (Data Exchange Protocol) active/passive mode
118 | const (
119 | Undefined = iota
120 | Passive
121 | Active
122 | )
123 |
124 | // NFC target information in D.E.P. (Data Exchange Protocol) see ISO/IEC 18092
125 | // (NFCIP-1). DEPTarget mirrors nfc_dep_info.
126 | type DEPTarget struct {
127 | NFCID3 [10]byte // NFCID3
128 | DID byte // DID
129 | BS byte // supported send-bit rate
130 | BR byte // supported receive-bit rate
131 | TO byte // timeout value
132 | PP byte // PP parameters
133 | GB [48]byte // general bytes
134 | GBLen int // length of the GB field
135 | DepMode int // DEP mode
136 | Baud int // Baud rate
137 | }
138 |
139 | func (t *DEPTarget) String() string {
140 | return tString(t)
141 | }
142 |
143 | // Type is always DEP
144 | func (t *DEPTarget) Modulation() Modulation {
145 | return Modulation{DEP, t.Baud}
146 | }
147 |
148 | // Make a DEPTarget from an nfc_dep_info
149 | func unmarshallDEPTarget(c *C.nfc_target) DEPTarget {
150 | var dt DEPTarget
151 |
152 | C.unmarshallDEPTarget((*C.struct_DEPTarget)(unsafe.Pointer(&dt)), c)
153 |
154 | return dt
155 | }
156 |
157 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
158 | // contains the same data as the Target. Don't forget to C.free() the result of
159 | // Marshall() afterwards.
160 | func (d *DEPTarget) Marshall() uintptr {
161 | nt := mallocTarget()
162 | dt := (*C.struct_DEPTarget)(unsafe.Pointer(d))
163 |
164 | C.marshallDEPTarget(nt, dt)
165 |
166 | return uintptr(unsafe.Pointer(nt))
167 | }
168 |
169 | // NFC ISO14443A tag (MIFARE) information. ISO14443aTarget mirrors
170 | // nfc_iso14443a_info.
171 | type ISO14443aTarget struct {
172 | Atqa [2]byte
173 | Sak byte
174 | UIDLen int // length of the Uid field
175 | UID [10]byte
176 | AtsLen int // length of the ATS field
177 | // Maximal theoretical ATS is FSD-2, FSD=256 for FSDI=8 in RATS
178 | Ats [254]byte // up to 254 bytes
179 | Baud int // Baud rate
180 | }
181 |
182 | func (t *ISO14443aTarget) String() string {
183 | return tString(t)
184 | }
185 |
186 | // Type is always ISO14443A
187 | func (t *ISO14443aTarget) Modulation() Modulation {
188 | return Modulation{ISO14443a, t.Baud}
189 | }
190 |
191 | // Make an ISO14443aTarget from an nfc_iso14443a_info
192 | func unmarshallISO14443aTarget(c *C.nfc_target) ISO14443aTarget {
193 | var it ISO14443aTarget
194 |
195 | C.unmarshallISO14443aTarget((*C.struct_ISO14443aTarget)(unsafe.Pointer(&it)), c)
196 |
197 | return it
198 | }
199 |
200 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
201 | // contains the same data as the Target. Don't forget to C.free() the result of
202 | // Marshall() afterwards. A runtime panic may occur if any slice referenced by a
203 | // Target has been made larger than the maximum length mentioned in the
204 | // respective comments.
205 | func (d *ISO14443aTarget) Marshall() uintptr {
206 | nt := mallocTarget()
207 | it := (*C.struct_ISO14443aTarget)(unsafe.Pointer(d))
208 |
209 | C.marshallISO14443aTarget(nt, it)
210 |
211 | return uintptr(unsafe.Pointer(nt))
212 | }
213 |
214 | // NFC FeLiCa tag information
215 | type FelicaTarget struct {
216 | Len uint
217 | ResCode byte
218 | ID [8]byte
219 | Pad [8]byte
220 | SysCode [2]byte
221 | Baud int
222 | }
223 |
224 | func (t *FelicaTarget) String() string {
225 | return tString(t)
226 | }
227 |
228 | // Type is always FELICA
229 | func (t *FelicaTarget) Modulation() Modulation {
230 | return Modulation{Felica, t.Baud}
231 | }
232 |
233 | // Make an FelicaTarget from an nfc_felica_info
234 | func unmarshallFelicaTarget(c *C.nfc_target) FelicaTarget {
235 | var ft FelicaTarget
236 |
237 | C.unmarshallFelicaTarget((*C.struct_FelicaTarget)(unsafe.Pointer(&ft)), c)
238 |
239 | return ft
240 | }
241 |
242 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
243 | // contains the same data as the Target. Don't forget to C.free() the result of
244 | // Marshall() afterwards.
245 | func (d *FelicaTarget) Marshall() uintptr {
246 | nt := mallocTarget()
247 | ft := (*C.struct_FelicaTarget)(unsafe.Pointer(d))
248 |
249 | C.marshallFelicaTarget(nt, ft)
250 |
251 | return uintptr(unsafe.Pointer(nt))
252 | }
253 |
254 | // NFC ISO14443B tag information. See ISO14443-3 for more details.
255 | type ISO14443bTarget struct {
256 | Pupi [4]byte // stores PUPI contained in ATQB (Answer To reQuest of type B)
257 | ApplicationData [4]byte // stores Application Data contained in ATQB
258 | ProtocolInfo [3]byte // stores Protocol Info contained in ATQB
259 | CardIdentifier byte // store CID (Card Identifier) attributted by PCD to the PICC
260 | Baud int
261 | }
262 |
263 | func (t *ISO14443bTarget) String() string {
264 | return tString(t)
265 | }
266 |
267 | // Type is always ISO14443B
268 | func (t *ISO14443bTarget) Modulation() Modulation {
269 | return Modulation{ISO14443b, t.Baud}
270 | }
271 |
272 | // Make an ISO14443bTarget from an nfc_iso14443b_info
273 | func unmarshallISO14443bTarget(c *C.nfc_target) ISO14443bTarget {
274 | var it ISO14443bTarget
275 |
276 | C.unmarshallISO14443bTarget((*C.struct_ISO14443bTarget)(unsafe.Pointer(&it)), c)
277 |
278 | return it
279 | }
280 |
281 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
282 | // contains the same data as the Target. Don't forget to C.free() the result of
283 | // Marshall() afterwards.
284 | func (d *ISO14443bTarget) Marshall() uintptr {
285 | nt := mallocTarget()
286 | it := (*C.struct_ISO14443bTarget)(unsafe.Pointer(d))
287 |
288 | C.marshallISO14443bTarget(nt, it)
289 |
290 | return uintptr(unsafe.Pointer(nt))
291 | }
292 |
293 | // NFC ISO14443B' tag information
294 | type ISO14443biTarget struct {
295 | DIV [4]byte // 4 LSBytes of tag serial number
296 | VerLog byte // Software version & type of REPGEN
297 | Config byte // Config Byte, present if long REPGEN
298 | AtrLen int // length of the Atr field
299 | Atr [33]byte // ATR, if any. At most 33 bytes
300 | Baud int
301 | }
302 |
303 | func (t *ISO14443biTarget) String() string {
304 | return tString(t)
305 | }
306 |
307 | // Type is always ISO14443BI
308 | func (t *ISO14443biTarget) Modulation() Modulation {
309 | return Modulation{ISO14443bi, t.Baud}
310 | }
311 |
312 | // Make an ISO14443biTarget from an nfc_iso14443bi_info
313 | func unmarshallISO14443biTarget(c *C.nfc_target) ISO14443biTarget {
314 | var it ISO14443biTarget
315 |
316 | C.unmarshallISO14443biTarget((*C.struct_ISO14443biTarget)(unsafe.Pointer(&it)), c)
317 |
318 | return it
319 | }
320 |
321 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
322 | // contains the same data as the Target. Don't forget to C.free() the result of
323 | // Marshall() afterwards.
324 | func (d *ISO14443biTarget) Marshall() uintptr {
325 | nt := mallocTarget()
326 | it := (*C.struct_ISO14443biTarget)(unsafe.Pointer(d))
327 |
328 | C.marshallISO14443biTarget(nt, it)
329 |
330 | return uintptr(unsafe.Pointer(nt))
331 | }
332 |
333 | // NFC ISO14443-2B ST SRx tag information
334 | type ISO14443b2srTarget struct {
335 | UID [8]byte
336 | Baud int
337 | }
338 |
339 | func (t *ISO14443b2srTarget) String() string {
340 | return tString(t)
341 | }
342 |
343 | // Type is always ISO14443B2SR
344 | func (t *ISO14443b2srTarget) Modulation() Modulation {
345 | return Modulation{ISO14443b2sr, t.Baud}
346 | }
347 |
348 | // Make an ISO14443b2srTarget from an nfc_iso14443b2sr_info
349 | func unmarshallISO14443b2srTarget(c *C.nfc_target) ISO14443b2srTarget {
350 | var it ISO14443b2srTarget
351 |
352 | C.unmarshallISO14443b2srTarget((*C.struct_ISO14443b2srTarget)(unsafe.Pointer(&it)), c)
353 |
354 | return it
355 | }
356 |
357 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
358 | // contains the same data as the Target. Don't forget to C.free() the result of
359 | // Marshall() afterwards. A runtime panic may occur if any slice referenced by a
360 | // Target has been made larger than the maximum length mentioned in the
361 | // respective comments.
362 | func (d *ISO14443b2srTarget) Marshall() uintptr {
363 | nt := mallocTarget()
364 | it := (*C.struct_ISO14443b2srTarget)(unsafe.Pointer(d))
365 |
366 | C.marshallISO14443b2srTarget(nt, it)
367 |
368 | return uintptr(unsafe.Pointer(nt))
369 | }
370 |
371 | // NFC ISO14443-2B ASK CTx tag information
372 | type ISO14443b2ctTarget struct {
373 | UID [4]byte
374 | ProdCode byte
375 | FabCode byte
376 | Baud int
377 | }
378 |
379 | func (t *ISO14443b2ctTarget) String() string {
380 | return tString(t)
381 | }
382 |
383 | // Type is always ISO1444B2CT
384 | func (t *ISO14443b2ctTarget) Modulation() Modulation {
385 | return Modulation{ISO14443b2ct, t.Baud}
386 | }
387 |
388 | // Make an ISO14443b2ctTarget from an nfc_iso14443b2ct_info
389 | func unmarshallISO14443b2ctTarget(c *C.nfc_target) ISO14443b2ctTarget {
390 | var it ISO14443b2ctTarget
391 |
392 | C.unmarshallISO14443b2ctTarget((*C.struct_ISO14443b2ctTarget)(unsafe.Pointer(&it)), c)
393 |
394 | return it
395 | }
396 |
397 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
398 | // contains the same data as the Target. Don't forget to C.free() the result of
399 | // Marshall() afterwards.
400 | func (d *ISO14443b2ctTarget) Marshall() uintptr {
401 | nt := mallocTarget()
402 | it := (*C.struct_ISO14443b2ctTarget)(unsafe.Pointer(d))
403 |
404 | C.marshallISO14443b2ctTarget(nt, it)
405 |
406 | return uintptr(unsafe.Pointer(nt))
407 | }
408 |
409 | // NFC Jewel tag information
410 | type JewelTarget struct {
411 | SensRes [2]byte
412 | ID [4]byte
413 | Baud int
414 | }
415 |
416 | func (t *JewelTarget) String() string {
417 | return tString(t)
418 | }
419 |
420 | // Type is always Jewel
421 | func (t *JewelTarget) Modulation() Modulation {
422 | return Modulation{Jewel, t.Baud}
423 | }
424 |
425 | // Make a JewelTarget from an nfc_jewel_info
426 | func unmarshallJewelTarget(c *C.nfc_target) JewelTarget {
427 | var jt JewelTarget
428 |
429 | C.unmarshallJewelTarget((*C.struct_JewelTarget)(unsafe.Pointer(&jt)), c)
430 |
431 | return jt
432 | }
433 |
434 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
435 | // contains the same data as the Target. Don't forget to C.free() the result of
436 | // Marshall() afterwards.
437 | func (d *JewelTarget) Marshall() uintptr {
438 | nt := mallocTarget()
439 | jt := (*C.struct_JewelTarget)(unsafe.Pointer(d))
440 |
441 | C.marshallJewelTarget(nt, jt)
442 |
443 | return uintptr(unsafe.Pointer(nt))
444 | }
445 |
446 | // Thinfilm NFC barcode tag information
447 | type BarcodeTarget struct {
448 | DataLen int
449 | Data [32]byte
450 | Baud int
451 | }
452 |
453 | func (t *BarcodeTarget) String() string {
454 | return tString(t)
455 | }
456 |
457 | // Type is always Barcode
458 | func (t *BarcodeTarget) Modulation() Modulation {
459 | return Modulation{Barcode, t.Baud}
460 | }
461 |
462 | // Make a BarcodeTarget from an nfc_barcode_info
463 | func unmarshallBarcodeTarget(c *C.nfc_target) BarcodeTarget {
464 | var bt BarcodeTarget
465 |
466 | C.unmarshallBarcodeTarget((*C.struct_BarcodeTarget)(unsafe.Pointer(&bt)), c)
467 |
468 | return bt
469 | }
470 |
471 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
472 | // contains the same data as the Target. Don't forget to C.free() the result of
473 | // Marshall() afterwards.
474 | func (d *BarcodeTarget) Marshall() uintptr {
475 | nt := mallocTarget()
476 | bt := (*C.struct_BarcodeTarget)(unsafe.Pointer(d))
477 |
478 | C.marshallBarcodeTarget(nt, bt)
479 |
480 | return uintptr(unsafe.Pointer(nt))
481 | }
482 |
483 | // NFC ISO14443BiClass, i.e. HID iClass (Picopass) tag information
484 | type ISO14443biClassTarget struct {
485 | UID [8]byte
486 | Baud int
487 | }
488 |
489 | func (t *ISO14443biClassTarget) String() string {
490 | return tString(t)
491 | }
492 |
493 | // Type is always ISO14443biClass
494 | func (t *ISO14443biClassTarget) Modulation() Modulation {
495 | return Modulation{ISO14443biClass, t.Baud}
496 | }
497 |
498 | // Make an ISO14443biClassTarget from an nfc_iso14443biclass_info
499 | func unmarshallISO14443biClassTarget(c *C.nfc_target) ISO14443biClassTarget {
500 | var it ISO14443biClassTarget
501 |
502 | C.unmarshallISO14443biClassTarget((*C.struct_ISO14443biClassTarget)(unsafe.Pointer(&it)), c)
503 |
504 | return it
505 | }
506 |
507 | // Marshall() returns a pointer to an nfc_target allocated with C.malloc() that
508 | // contains the same data as the Target. Don't forget to C.free() the result of
509 | // Marshall() afterwards. A runtime panic may occur if any slice referenced by a
510 | // Target has been made larger than the maximum length mentioned in the
511 | // respective comments.
512 | func (d *ISO14443biClassTarget) Marshall() uintptr {
513 | nt := mallocTarget()
514 | it := (*C.struct_ISO14443biClassTarget)(unsafe.Pointer(d))
515 |
516 | C.marshallISO14443biClassTarget(nt, it)
517 |
518 | return uintptr(unsafe.Pointer(nt))
519 | }
520 |
--------------------------------------------------------------------------------