├── 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 | --------------------------------------------------------------------------------