| 1 | local cmds = require('commands') |
| 2 | local getopt = require('getopt') |
| 3 | local lib14a = require('read14a') |
| 4 | |
| 5 | example = "script run 14araw -x 6000F57b" |
| 6 | author = "Martin Holst Swende" |
| 7 | |
| 8 | |
| 9 | desc = |
| 10 | [[ |
| 11 | This is a script to allow raw 1444a commands to be sent and received. |
| 12 | |
| 13 | Arguments: |
| 14 | -o do not connect - use this only if you previously used -p to stay connected |
| 15 | -r do not read response |
| 16 | -c calculate and append CRC |
| 17 | -p stay connected - dont inactivate the field |
| 18 | -x <payload> Data to send (NO SPACES!) |
| 19 | -d Debug flag |
| 20 | -t Topaz mode |
| 21 | -3 Skip ISO14443-4 select |
| 22 | |
| 23 | Examples : |
| 24 | |
| 25 | # 1. Connect and don't disconnect |
| 26 | script run 14araw -p |
| 27 | # 2. Send mf auth, read response (nonce) |
| 28 | script run 14araw -o -x 6000F57b -p |
| 29 | # 3. disconnect |
| 30 | script run 14araw -o |
| 31 | |
| 32 | # All three steps in one go: |
| 33 | script run 14araw -x 6000F57b |
| 34 | ]] |
| 35 | |
| 36 | --[[ |
| 37 | |
| 38 | This script communicates with |
| 39 | /armsrc/iso14443a.c, specifically ReaderIso14443a() at around line 1779 and onwards. |
| 40 | |
| 41 | Check there for details about data format and how commands are interpreted on the |
| 42 | device-side. |
| 43 | ]] |
| 44 | |
| 45 | -- Some globals |
| 46 | local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds |
| 47 | local DEBUG = false -- the debug flag |
| 48 | |
| 49 | ------------------------------- |
| 50 | -- Some utilities |
| 51 | ------------------------------- |
| 52 | |
| 53 | --- |
| 54 | -- A debug printout-function |
| 55 | function dbg(args) |
| 56 | if DEBUG then |
| 57 | print("###", args) |
| 58 | end |
| 59 | end |
| 60 | --- |
| 61 | -- This is only meant to be used when errors occur |
| 62 | function oops(err) |
| 63 | print("ERROR: ",err) |
| 64 | end |
| 65 | |
| 66 | |
| 67 | --- |
| 68 | -- Usage help |
| 69 | function help() |
| 70 | print(desc) |
| 71 | print("Example usage") |
| 72 | print(example) |
| 73 | end |
| 74 | |
| 75 | |
| 76 | --- |
| 77 | -- The main entry point |
| 78 | function main(args) |
| 79 | |
| 80 | if args == nil or #args == 0 then |
| 81 | return help() |
| 82 | end |
| 83 | |
| 84 | local ignore_response = false |
| 85 | local appendcrc = false |
| 86 | local stayconnected = false |
| 87 | local payload = nil |
| 88 | local doconnect = true |
| 89 | local topaz_mode = false |
| 90 | local no_rats = false |
| 91 | |
| 92 | -- Read the parameters |
| 93 | for o, a in getopt.getopt(args, 'orcpx:dt3') do |
| 94 | if o == "o" then doconnect = false end |
| 95 | if o == "r" then ignore_response = true end |
| 96 | if o == "c" then appendcrc = true end |
| 97 | if o == "p" then stayconnected = true end |
| 98 | if o == "x" then payload = a end |
| 99 | if o == "d" then DEBUG = true end |
| 100 | if o == "t" then topaz_mode = true end |
| 101 | if o == "3" then no_rats = true end |
| 102 | end |
| 103 | |
| 104 | -- First of all, connect |
| 105 | if doconnect then |
| 106 | dbg("doconnect") |
| 107 | -- We reuse the connect functionality from a |
| 108 | -- common library |
| 109 | info, err = lib14a.read14443a(true, no_rats) |
| 110 | |
| 111 | if err then return oops(err) end |
| 112 | print(("Connected to card, uid = %s"):format(info.uid)) |
| 113 | end |
| 114 | |
| 115 | -- The actual raw payload, if any |
| 116 | if payload then |
| 117 | res,err = sendRaw(payload,{ignore_response = ignore_response, topaz_mode = topaz_mode}) |
| 118 | if err then return oops(err) end |
| 119 | |
| 120 | if not ignoreresponse then |
| 121 | -- Display the returned data |
| 122 | showdata(res) |
| 123 | end |
| 124 | end |
| 125 | -- And, perhaps disconnect? |
| 126 | if not stayconnected then |
| 127 | disconnect() |
| 128 | end |
| 129 | end |
| 130 | |
| 131 | --- Picks out and displays the data read from a tag |
| 132 | -- Specifically, takes a usb packet, converts to a Command |
| 133 | -- (as in commands.lua), takes the data-array and |
| 134 | -- reads the number of bytes specified in arg1 (arg0 in c-struct) |
| 135 | -- and displays the data |
| 136 | -- @param usbpacket the data received from the device |
| 137 | function showdata(usbpacket) |
| 138 | local cmd_response = Command.parse(usbpacket) |
| 139 | local len = tonumber(cmd_response.arg1) *2 |
| 140 | --print("data length:",len) |
| 141 | local data = string.sub(tostring(cmd_response.data), 0, len); |
| 142 | print("<< ",data) |
| 143 | --print("----------------") |
| 144 | end |
| 145 | |
| 146 | |
| 147 | function sendRaw(rawdata, options) |
| 148 | print(">> ", rawdata) |
| 149 | |
| 150 | local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW |
| 151 | if options.topaz_mode == true then flags = flags + lib14a.ISO14A_COMMAND.ISO14A_TOPAZMODE end |
| 152 | |
| 153 | local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, |
| 154 | arg1 = flags, -- Send raw |
| 155 | -- arg2 contains the length, which is half the length |
| 156 | -- of the ASCII-string rawdata |
| 157 | arg2 = string.len(rawdata)/2, |
| 158 | data = rawdata} |
| 159 | return lib14a.sendToDevice(command, options.ignore_response) |
| 160 | end |
| 161 | |
| 162 | -- Sends an instruction to do nothing, only disconnect |
| 163 | function disconnect() |
| 164 | |
| 165 | local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, |
| 166 | arg1 = 0, -- Nothing |
| 167 | } |
| 168 | -- We can ignore the response here, no ACK is returned for this command |
| 169 | -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details |
| 170 | return lib14a.sendToDevice(command,true) |
| 171 | end |
| 172 | |
| 173 | |
| 174 | ------------------------- |
| 175 | -- Testing |
| 176 | ------------------------- |
| 177 | function selftest() |
| 178 | DEBUG = true |
| 179 | dbg("Performing test") |
| 180 | main() |
| 181 | main("-p") |
| 182 | main(" -o -x 6000F57b -p") |
| 183 | main("-o") |
| 184 | main("-x 6000F57b") |
| 185 | dbg("Tests done") |
| 186 | end |
| 187 | -- Flip the switch here to perform a sanity check. |
| 188 | -- It read a nonce in two different ways, as specified in the usage-section |
| 189 | if "--test"==args then |
| 190 | selftest() |
| 191 | else |
| 192 | -- Call the main |
| 193 | main(args) |
| 194 | end |