Packages

Elixir library to work with the NXP PN532 RFID module.

Current section

Files

Jump to
pn532 lib connection frames.ex
Raw

lib/connection/frames.ex

defmodule PN532.Connection.Frames do
use Bitwise
require Logger
defmacro iso_14443_type_a_target(target_number, sens_res, sel_res, identifier) do
quote do
<<
unquote(target_number)::integer-signed,
unquote(sens_res)::binary-size(2),
unquote(sel_res)::binary-size(1),
id_length::integer-signed,
unquote(identifier)::binary-size(id_length)
>>
end
end
defmacro iso_14443_type_b_target(target_number, atqb, attrib_res) do
quote do
<<
unquote(target_number)::integer-signed,
unquote(atqb)::binary-size(12),
id_length::integer-signed,
unquote(attrib_res)::binary-size(id_length)
>>
end
end
defmacro feliCa_18_target(target_number, response_code, nfcid2t, pad) do
quote do
<<
unquote(target_number)::integer-signed,
18,
unquote(response_code)::binary-size(1),
unquote(nfcid2t)::binary-size(8),
unquote(pad)::binary-size(8),
>>
end
end
defmacro feliCa_20_target(target_number, response_code, nfcid2t, pad, syst_code) do
quote do
<<
unquote(target_number)::integer-signed,
20,
unquote(response_code)::binary-size(1),
unquote(nfcid2t)::binary-size(8),
unquote(pad)::binary-size(8),
unquote(syst_code)::binary-size(2)
>>
end
end
defmacro jewel_target(target_number, sens_res, jewelid) do
quote do
<<
unquote(target_number)::integer-signed,
unquote(sens_res)::binary-size(2),
unquote(jewelid)::binary-size(4),
>>
end
end
def in_auto_poll_request_frame(poll_nr, period, type) do
<<
0x60,
poll_nr,
period,
type
>>
end
defmacro in_auto_poll_response(type, message) do
quote do
<<
unquote(type)::binary-size(1),
length::integer,
unquote(message)::binary-size(length)
>>
end
end
def in_jump_for_dep_request_frame(act_pass, baud_rate, next, frames) do
<<
0x56,
act_pass,
baud_rate,
next,
frames
>>
end
def generate_nfcid3i() do
:crypto.strong_rand_bytes(10)
end
defmacro dep_target(target_number, nfcid3i, didt, bst, brt, time_out, ppt, geneal_info) do
quote do
<<
unquote(target_number)::integer-signed,
unquote(nfcid3i)::binary-size(10),
unquote(didt)::binary-size(1),
unquote(bst)::binary-size(1),
unquote(brt)::binary-size(1),
unquote(time_out)::binary-size(1),
unquote(ppt)::binary-size(1),
unquote(geneal_info)::bitstring,
>>
end
end
defmacro dep_target_short(target_number, nfcid3i, didt, bst, brt) do
quote do
<<
unquote(target_number)::integer-signed,
unquote(nfcid3i)::binary-size(10),
unquote(didt)::binary-size(1),
unquote(bst)::binary-size(1),
unquote(brt)::binary-size(1)
>>
end
end
defmacro firmware_version_response(ic_version, version, revision, support) do
quote do
<<
0xD5, 0x03,
unquote(ic_version)::binary-size(1),
unquote(version)::integer-signed,
unquote(revision)::integer-signed,
unquote(support)::integer-signed
>>
end
end
defmacro get_general_status_response(err, field, number_of_targets, targets) do
quote do
<<
0xD5, 0x05,
unquote(err)::binary-size(1),
unquote(field)::binary-size(1),
unquote(number_of_targets)::integer,
unquote(targets)
>>
end
end
def get_target_type(target) do
case target do
:iso_14443_type_a -> {:ok, 0x00}
:felica_212 -> {:ok, 0x01}
:felica_424 -> {:ok, 0x02}
:iso_14443_type_b -> {:ok, 0x03}
:jewel -> {:ok, 0x04}
_ -> {:error, :invalid_target_type}
end
end
def get_bitrate(<<0x00>>), do: "106 kbps"
def get_bitrate(<<0x01>>), do: "212 kbps"
def get_bitrate(<<0x02>>), do: "424 kbps"
def get_modulation_type(<<0x00>>), do: "Mifare"
def get_modulation_type(<<0x10>>), do: "FeliCa"
def get_modulation_type(<<0x01>>), do: "ISO/IEC18092 Active mode"
def get_modulation_type(<<0x02>>), do: "Innovision Jewel tag"
def get_error(error_byte) do
case error_byte do
<<0>> -> {:success, "No error"}
0x01 -> {:target_timeout, "The target has not answered"}
0x02 -> {:crc_error, "A CRC error has been detected by the CIU"}
0x03 -> {:parity_error, "A Parity error has been detected by the CIU"}
0x04 -> {:bit_count_error, "During an anti-collision/select operation (ISO/IEC14443-3 Type A and ISO/IEC18092 106 kbps passive mode), an erroneous Bit Count has been detected"}
0x05 -> {:mifare_framing_error, "Framing error during Mifare operation"}
0x06 -> {:abnormal_bit_collision, "An abnormal bit-collision has been detected during bit wise anti-collision at 106 kbps"}
0x07 -> {:buffer_size_insufficient, "Communication buffer size insufficient"}
0x09 -> {:rf_buffer_overflow, "RF Buffer overflow has been detected by the CIU (bit BufferOvfl of the register CIU_Error)"}
0x0A -> {:rf_field_not_on_in_time, "In active communication mode, the RF field has not been switched on in time by the counterpart (as defined in NFCIP-1 standard)"}
0x0B -> {:rf_protocol_error, "RF Protocol error"}
0x0D -> {:temperature_error, "Temperature error: the internal temperature sensor has detected overheating, and therefore has automatically switched off the antenna drivers"}
0x0E -> {:internal_buffer_overflow, "Internal buffer overflow"}
0x10 -> {:invalid_parameter, "Invalid parameter (range, format, ...)"}
0x12 -> {:dep_command_received_invalid, "The PN532 configured in target mode does not support the command received from the initiator (the command received is not one of the following: ATR_REQ, WUP_REQ, PSL_REQ, DEP_REQ, DSL_REQ, RLS_REQ"}
0x13 -> {:dep_data_format_not_match_spec, "Mifare or ISO/IEC14443-4: The data format does not match to the specification. Depending on the RF protocol used, it can be: Bad length of RF received frame, Incorrect value of PCB or PFB, Incorrect value of PCB or PFB, NAD or DID incoherence."}
0x14 -> {:mifare_authentication_error, "Mifare: Authentication error"}
0x23 -> {:uid_check_byte_wrong, "ISO/IEC14443-3: UID Check byte is wrong"}
0x25 -> {:dep_invalid_device_state, "Invalid device state, the system is in a state which does not allow the operation"}
0x26 -> {:op_not_allowed, "Operation not allowed in this configuration (host controller interface)"}
0x27 -> {:command_invalid_in_context, "This command is not acceptable due to the current context of the PN532 (Initiator vs. Target, unknown target number, Target not in the good state, ...)"}
0x29 -> {:target_released_by_initiator, "The PN532 configured as target has been released by its initiator"}
0x2A -> {:card_id_does_not_match, "PN532 and ISO/IEC14443-3B only: the ID of the card does not match, meaning that the expected card has been exchanged with another one."}
0x2B -> {:card_disappeared, "PN532 and ISO/IEC14443-3B only: the card previously activated has disappeared."}
0x2C -> {:target_initiator_nfcid3_mismatch, "Mismatch between the NFCID3 initiator and the NFCID3 target in DEP 212/424 kbps passive."}
0x2D -> {:over_current_event, "An over-current event has been detected"}
0x2E -> {:dep_nad_missing, "NAD missing in DEP frame"}
error -> {:unknown_error, "Unknown error: #{inspect error}"}
end
end
def build_command_frame(tfi, command) do
length = byte_size(command)
combined_length = length + 1
lcs = ~~~combined_length + 1
dsc_checksum = checksum(tfi <> command)
dsc = ~~~dsc_checksum + 1
command_frame(<<0x00>>, <<0x00>>, <<0xFF>>, length, combined_length, lcs, tfi, command, dsc, <<0x00>>)
end
def command_frame(preamble, startcode1, startcode2, length, combined_length, lcs, tfi, command, dsc, postamble) do
<<
preamble::binary-size(1),
startcode1::binary-size(1),
startcode2::binary-size(1),
combined_length::integer-signed,
lcs::integer-unsigned,
tfi::binary-size(1),
command::binary-size(length),
dsc::integer-unsigned,
postamble::binary-size(1)
>>
end
def checksum(data), do: checksum(data, 0)
def checksum(<<head, rest::bitstring>>, acc), do: checksum(rest, head + acc)
def checksum(<<>>, acc), do: acc
end