Program Listing for File bits.hpp

Return to documentation for file (libspookyaction/include/pn532/bits.hpp)

//
// Created by Pietro Saccardi on 20/12/2020.
//

#ifndef PN532_BITS_HPP
#define PN532_BITS_HPP

#include <array>
#include <cstddef>
#include <mlab/bin_data.hpp>
#include <vector>

namespace pn532 {

    enum struct command_code : std::uint8_t {
        diagnose = 0x00,
        get_firmware_version = 0x02,
        get_general_status = 0x04,
        read_register = 0x06,
        write_register = 0x08,
        read_gpio = 0x0c,
        write_gpio = 0x0e,
        set_serial_baudrate = 0x10,
        set_parameters = 0x12,
        sam_configuration = 0x14,
        power_down = 0x16,
        rf_configuration = 0x32,
        rf_regulation_test = 0x58,
        in_jump_for_dep = 0x56,
        in_jump_for_psl = 0x46,
        in_list_passive_target = 0x4a,
        in_atr = 0x50,
        in_psl = 0x4e,
        in_data_exchange = 0x40,
        in_communicate_thru = 0x42,
        in_deselect = 0x44,
        in_release = 0x52,
        in_select = 0x54,
        in_autopoll = 0x60,
        tg_init_as_target = 0x8c,
        tg_set_general_bytes = 0x92,
        tg_get_data = 0x86,
        tg_set_data = 0x8e,
        tg_set_metadata = 0x94,
        tg_get_initiator_command = 0x88,
        tg_response_to_initiator = 0x90,
        tg_get_target_status = 0x8a
    };

    enum struct low_current_thr : std::uint8_t {
        mA_25 = 0b10 << 4,
        mA_35 = 0b11 << 4
    };

    enum struct high_current_thr : std::uint8_t {
        mA_45 = 0b000 << 1,
        mA_60 = 0b001 << 1,
        mA_75 = 0b010 << 1,
        mA_90 = 0b011 << 1,
        mA_105 = 0b100 << 1,
        mA_120 = 0b101 << 1,
        mA_130 = 0b110 << 1,
        mA_150 = 0b111 << 1
    };

    enum struct serial_baudrate : std::uint8_t {
        baud9_600 = 0x00,
        baud19_200 = 0x01,
        baud38_400 = 0x02,
        baud57_600 = 0x03,
        baud115_200 = 0x04,
        baud230_400 = 0x05,
        baud460_800 = 0x06,
        baud921_600 = 0x07,
        baud1_288_000 = 0x08
    };

    enum struct rf_test_mode : std::uint8_t {
        mifare_106kbps = 0b0000000,
        mifare_212kbps = 0b0010000,
        mifare_424kbps = 0b0100000,
        mifare_848kbps = 0b0110000,
        felica_106kbps = 0b0000010,
        felica_212kbps = 0b0010010,
        felica_424kbps = 0b0100010,
        felica_848kbps = 0b0110010
    };

    enum struct rf_timeout : std::uint8_t {
        none = 0x00,
        us_100 = 0x01,
        us_200 = 0x02,
        us_400 = 0x03,
        us_800 = 0x04,
        ms_1_6 = 0x05,
        ms_3_2 = 0x06,
        ms_6_4 = 0x07,
        ms_12_8 = 0x08,
        ms_25_6 = 0x09,
        ms_51_2 = 0x0a,
        ms_102_4 = 0x0b,
        ms_204_8 = 0x0c,
        ms_409_6 = 0x0d,
        ms_819_2 = 0x0e,
        s_1_64 = 0x0f,
        s_3_28 = 0x10
    };

    namespace reg {

        struct ciu_212_424kbps {
            std::uint8_t rf_cfg = 0x69;
            std::uint8_t gs_n_on = 0xff;
            std::uint8_t cw_gs_p = 0x3f;
            std::uint8_t mod_gs_p = 0x11;
            std::uint8_t demod_own_rf_on = 0x41;
            std::uint8_t rx_threshold = 0x85;
            std::uint8_t demod_own_rf_off = 0x61;
            std::uint8_t gs_n_off = 0x6f;
        };

        struct ciu_106kbps_typea {
            std::uint8_t rf_cfg = 0x59;
            std::uint8_t gs_n_on = 0xf4;
            std::uint8_t cw_gs_p = 0x3f;
            std::uint8_t mod_gs_p = 0x11;
            std::uint8_t demod_own_rf_on = 0x4d;
            std::uint8_t rx_threshold = 0x85;
            std::uint8_t demod_own_rf_off = 0x61;
            std::uint8_t gs_n_off = 0x6f;
            std::uint8_t mod_width = 0x26;
            std::uint8_t mif_nfc = 0x62;
            std::uint8_t tx_bit_phase = 0x87;
        };

        struct ciu_typeb {
            std::uint8_t gs_n_on = 0xff;
            std::uint8_t mod_gs_p = 0x17;
            std::uint8_t rx_threshold = 0x85;
        };

        struct ciu_iso_iec_14443_4_at_baudrate {
            std::uint8_t rx_threshold;
            std::uint8_t mod_width;
            std::uint8_t mif_nfc;
        };

        struct ciu_iso_iec_14443_4 {
            ciu_iso_iec_14443_4_at_baudrate kbps212{0x85, 0x15, 0x8a};
            ciu_iso_iec_14443_4_at_baudrate kbps424{0x85, 0x08, 0xb2};
            ciu_iso_iec_14443_4_at_baudrate kbps848{0x85, 0x01, 0xda};
        };

        enum struct sfr_register : std::uint8_t {
            pcon = 0x87,
            rwl = 0x9a,
            twl = 0x9b,
            fifofs = 0x9c,
            fifoff = 0x9d,
            sff = 0x9e,
            fit = 0x9f,
            fiten = 0xa1,
            fdata = 0xa2,
            fsize = 0xa3,
            ie0 = 0xa8,
            spicontrol = 0xa9,
            spistatus = 0xaa,
            hsu_sta = 0xab,
            hsu_ctr = 0xac,
            hsu_pre = 0xad,
            hsu_cnt = 0xae,
            p3 = 0xb0,
            ip0 = 0xb8,
            ciu_command = 0xd1,
            ien1 = 0xe8,
            p7cfga = 0xf4,
            p7cfgb = 0xf5,
            p7 = 0xf7,
            ip1 = 0xf8,
            p3cfga = 0xfc,
            p3cfgb = 0xfd
        };

        struct addr : public std::array<std::uint8_t, 2> {
            inline addr(sfr_register sfr_reg);
            explicit inline addr(std::uint16_t xram_mmap_reg);
        };
    }// namespace reg

    enum struct baudrate : std::uint8_t {
        kbps106 = 0x0,
        kbps212 = 0x1,
        kbps424 = 0x2
    };

    enum struct modulation : std::uint8_t {
        mifare_iso_iec_14443_3_type_ab_iso_iec_18092_passive_kbps106 = 0x00,
        felica_iso_iec_18092_kbps212_424 = 0x10,
        iso_iec_18092_active = 0x01,
        innovision_jewel_tag = 0x02
    };

    enum struct sam_mode : std::uint8_t {
        normal = 0x01,
        virtual_card = 0x02,
        wired_card = 0x03,
        dual_card = 0x04
    };

    enum struct wakeup_source : std::uint8_t {
        i2c = 1 << 7,
        gpio = 1 << 6,
        spi = 1 << 5,
        hsu = 1 << 4,
        rf = 1 << 3,
        int1 = 1 << 1,
        int0 = 1 << 0
    };

    enum struct nfcip1_picc_status : std::uint8_t {
        nfcip1_idle = 0x00,
        nfcip1_activated = 0x01,
        nfcip1_deselected = 0x02,
        picc_released = 0x80,
        picc_activated = 0x81,
        picc_deselected = 0x82
    };

    enum struct internal_error_code : std::uint8_t {
        none = 0x00,
        timeout = 0x01,
        crc_error = 0x02,
        parity_error = 0x3,
        erroneous_bit_count = 0x04,
        framing_error = 0x05,
        bit_collision = 0x06,
        buffer_size_insufficient = 0x07,
        rf_buffer_overflow = 0x09,
        counterpart_rf_off = 0x0a,
        rf_protocol_error = 0x0b,
        temperature_error = 0x0d,
        buffer_overflow = 0x0e,
        invalid_parameter = 0x10,
        dep_unsupported_command = 0x12,
        specification_mismatch = 0x13,
        mifare_auth_error = 0x14,
        wrong_uid_check_byte = 0x23,
        dep_invalid_device_state = 0x25,
        operation_not_allowed = 0x26,
        command_not_acceptable = 0x27,
        released_by_initiator = 0x29,
        card_exchanged = 0x2a,
        card_disappeared = 0x2b,
        nfcid3_initiator_target_mismatch = 0x2c,
        overcurrent = 0x2d,
        nad_missing_in_dep_frame = 0x2e
    };

    enum struct polling_method : std::uint8_t {
        timeslot = 0x00,
        probabilistic = 0x01
    };
    enum struct baudrate_modulation : std::uint8_t {
        kbps106_iso_iec_14443_typea = 0x00,
        kbps212_felica = 0x01,
        kbps424_felica = 0x02,
        kbps106_iso_iec_14443_3_typeb = 0x03,
        kbps106_innovision_jewel_tag = 0x04
    };

    enum struct poll_period : std::uint8_t {
        ms_150 = 0x1,
        ms_300 = 0x2,
        ms_450 = 0x3,
        ms_600 = 0x4,
        ms_750 = 0x5,
        ms_900 = 0x6,
        ms_1050 = 0x7,
        ms_1200 = 0x8,
        ms_1350 = 0x9,
        ms_1500 = 0xa,
        ms_1650 = 0xb,
        ms_1800 = 0xc,
        ms_1950 = 0xd,
        ms_2100 = 0xe,
        ms_2250 = 0xf
    };

    enum struct target_type : std::uint8_t {
        generic_passive_106kbps = 0x00,
        generic_passive_212kbps = 0x01,
        generic_passive_424kbps = 0x02,
        passive_106kbps_iso_iec_14443_4_typeb = 0x03,
        innovision_jewel_tag = 0x04,
        mifare_classic_ultralight = 0x10,
        felica_212kbps_card = 0x11,
        felica_424kbps_card = 0x12,
        passive_106kbps_iso_iec_14443_4_typea = 0x20,
        passive_106kbps_iso_iec_14443_4_typeb_alt = 0x23,
        dep_passive_106kbps = 0x40,
        dep_passive_212kbps = 0x41,
        dep_passive_424kbps = 0x42,
        dep_active_106kbps = 0x80,
        dep_active_212kbps = 0x81,
        dep_active_424kbps = 0x82
    };

    [[nodiscard]] constexpr baudrate_modulation baudrate_modulation_of(target_type target);

    [[nodiscard]] constexpr baudrate baudrate_of(target_type target);

    [[nodiscard]] constexpr modulation modulation_of(target_type target);

    template <std::size_t Length>
    struct nfcid_cascade_tag {};

    using nfcid_1t = mlab::tagged_array<nfcid_cascade_tag<4>, 4>;

    using nfcid_2t = mlab::tagged_array<nfcid_cascade_tag<7>, 7>;

    using nfcid_3t = mlab::tagged_array<nfcid_cascade_tag<10>, 10>;

    struct atr_res_info {
        nfcid_3t nfcid;
        std::uint8_t did_t;
        std::uint8_t b_st;
        std::uint8_t b_rt;
        std::uint8_t to;
        std::uint8_t pp_t;
        std::vector<std::uint8_t> g_t;
    };

    enum struct framing_as_target : std::uint8_t {
        mifare = 0b00,
        active_mode = 0b01,
        felica = 0b10
    };

    template <baudrate_modulation>
    struct target {
    };

    struct target_logical_index {
        std::uint8_t logical_index;
    };

    template <>
    struct target<baudrate_modulation::kbps106_iso_iec_14443_typea> : public target_logical_index {
        using target_logical_index::logical_index;
        std::array<std::uint8_t, 2> sens_res;
        std::uint8_t sel_res;
        std::vector<std::uint8_t> nfcid;
        std::vector<std::uint8_t> ats;
    };

    template <>
    struct target<baudrate_modulation::kbps212_felica> : public target_logical_index {
        using target_logical_index::logical_index;
        std::array<std::uint8_t, 8> nfcid_2t;
        std::array<std::uint8_t, 8> pad;
        std::array<std::uint8_t, 2> syst_code;
    };

    template <>
    struct target<baudrate_modulation::kbps424_felica> : public target_logical_index {
        using target_logical_index::logical_index;
        std::array<std::uint8_t, 8> nfcid_2t;
        std::array<std::uint8_t, 8> pad;
        std::array<std::uint8_t, 2> syst_code;
    };

    template <>
    struct target<baudrate_modulation::kbps106_iso_iec_14443_3_typeb> : public target_logical_index {
        using target_logical_index::logical_index;
        std::array<std::uint8_t, 12> atqb_response;
        std::vector<std::uint8_t> attrib_res;
    };

    template <>
    struct target<baudrate_modulation::kbps106_innovision_jewel_tag> : public target_logical_index {
        using target_logical_index::logical_index;
        std::array<std::uint8_t, 2> sens_res;
        nfcid_1t jewel_id;
    };

#ifndef DOXYGEN_SHOULD_SKIP_THIS
    namespace bits {

        template <std::uint8_t MinIdx, std::uint8_t MaxIdx>
        static constexpr std::uint8_t bitmask_window = (0xff >> (7 + MinIdx - MaxIdx)) << MinIdx;

        static constexpr std::uint8_t preamble = 0x00;
        static constexpr std::uint8_t postamble = 0x00;

        enum struct transport : std::uint8_t {
            host_to_pn532 = 0xd4,
            pn532_to_host = 0xd5
        };

        static constexpr std::uint8_t specific_app_level_err_code = 0x7f;
        static constexpr std::array<std::uint8_t, 2> start_of_packet_code = {0x00, 0xff};
        static constexpr std::array<std::uint8_t, 2> ack_packet_code = {0x00, 0xff};
        static constexpr std::array<std::uint8_t, 2> nack_packet_code = {0xff, 0x00};
        static constexpr std::array<std::uint8_t, 2> fixed_extended_packet_length = {0xff, 0xff};

        static constexpr std::size_t max_firmware_data_length = 263;

        static constexpr std::uint8_t firmware_iso_iec_14443_typea_mask = 0b0001;
        static constexpr std::uint8_t firmware_iso_iec_14443_typeb_mask = 0b0010;
        static constexpr std::uint8_t firmware_iso_18092_mask = 0b0100;

        static constexpr unsigned echo_back_reply_delay_steps_per_ms = 2;

        enum struct test : std::uint8_t {
            comm_line = 0x0,
            rom = 0x1,
            ram = 0x2,
            poll_target = 0x4,
            echo_back = 0x5,
            attention_req_or_card_presence = 0x6,
            self_antenna = 0x7
        };

        static constexpr std::uint8_t reg_andet_control_low_current_mask = bitmask_window<4, 5>;
        static constexpr std::uint8_t reg_andet_control_high_current_mask = bitmask_window<1, 3>;

        static constexpr std::uint8_t reg_andet_control_too_low_power_mask = 1 << 7;
        static constexpr std::uint8_t reg_andet_control_too_high_power_mask = 1 << 6;
        static constexpr std::uint8_t reg_andet_control_antenna_detect_mask = 1 << 0;

        static constexpr std::uint8_t rf_configuration_field_auto_rfca_mask = 0b10;
        static constexpr std::uint8_t rf_configuration_field_auto_rf_on_mask = 0b01;


        enum struct rf_config_item : std::uint8_t {
            rf_field = 0x01,
            timings = 0x02,
            max_rty_com = 0x04,
            max_retries = 0x05,
            analog_106kbps_typea = 0x0a,
            analog_212_424kbps = 0x0b,
            analog_typeb = 0x0c,
            analog_iso_iec_14443_4 = 0x0d
        };

        static constexpr unsigned status_as_target_initiator_speed_shift = 4;
        static constexpr unsigned status_as_target_target_speed_shift = 0;
        static constexpr std::uint8_t baudrate_mask = 0b111;

        static constexpr unsigned sam_timeout_unit_ms = 50;

        static constexpr std::uint8_t status_nad_mask = 0x1 << 7;
        static constexpr std::uint8_t status_more_info_mask = 0x1 << 6;
        static constexpr std::uint8_t status_error_mask = 0b00111111;

        static constexpr std::uint8_t sam_status_neg_pulse_on_clad_line_bit = 1 << 0;
        static constexpr std::uint8_t sam_status_detected_rf_field_off_bit = 1 << 1;
        static constexpr std::uint8_t sam_status_timeout_after_sig_act_irq_bit = 1 << 2;
        static constexpr std::uint8_t sam_status_clad_line_high_bit = 1 << 7;

        static constexpr std::uint8_t parameters_use_nad_data_bit = 1 << 0;
        static constexpr std::uint8_t parameters_use_did_data_bit = 1 << 1;
        static constexpr std::uint8_t parameters_auto_generate_atr_res_bit = 1 << 2;
        static constexpr std::uint8_t parameters_auto_generate_rats_bit = 1 << 4;
        static constexpr std::uint8_t parameters_enable_iso_14443_4_picc_emulation_bit = 1 << 5;
        static constexpr std::uint8_t parameters_remove_pre_post_amble_bit = 1 << 6;

        static constexpr std::uint8_t max_num_targets = 2;


        static constexpr std::uint8_t uid_cascade_tag = 0x88;


        static constexpr unsigned autopoll_max_types = 15;

        static constexpr std::uint8_t target_type_baudrate_modulation_mask = 0b111;

        static constexpr unsigned init_as_target_res_baudrate_shift = 4;
        static constexpr std::uint8_t init_as_target_res_picc_bit = 1 << 3;
        static constexpr std::uint8_t init_as_target_res_dep_bit = 1 << 2;

        static constexpr std::uint8_t framing_mask = 0b11;

        static constexpr std::uint8_t init_as_target_picc_only_bit = 1 << 2;
        static constexpr std::uint8_t init_as_target_dep_only_bit = 1 << 1;
        static constexpr std::uint8_t init_as_target_passive_only_bit = 1 << 0;

        [[maybe_unused]] static constexpr std::uint8_t sel_res_dep_mask = 0x40;
        [[maybe_unused]] static constexpr std::uint8_t sel_res_picc_mask = 0x60;
        static constexpr std::size_t init_as_target_general_info_max_length = 47;
        static constexpr std::size_t init_as_target_historical_bytes_max_length = 48;

        static constexpr std::uint8_t in_atr_nfcid_3t_present_mask = 0b01;
        static constexpr std::uint8_t in_atr_general_info_present_mask = 0b10;

        static constexpr std::uint8_t in_jump_for_dep_passive_init_data_present_mask = 0b001;
        static constexpr std::uint8_t in_jump_for_dep_nfcid_3t_present_mask = 0b010;
        static constexpr std::uint8_t in_jump_for_dep_general_info_present_mask = 0b100;

        static constexpr std::size_t general_info_max_length = 48;

        static constexpr std::uint8_t gpio_p3_pin_mask = bitmask_window<0, 5>;
        static constexpr std::uint8_t gpio_p7_pin_mask = bitmask_window<1, 2>;
        static constexpr std::uint8_t gpio_i0i1_pin_mask = 0x00;// Cannot set i0i1

        static constexpr std::uint8_t gpio_write_validate_max = 1 << 7;

        static constexpr std::uint8_t sfr_registers_high = 0xff;

        struct reg_antenna_detector {
            bool detected_low_pwr;
            bool detected_high_pwr;
            pn532::low_current_thr low_current_threshold;
            pn532::high_current_thr high_current_threshold;
            bool enable_detection;
        };

    }// namespace bits
#endif
}// namespace pn532


namespace pn532 {
    constexpr baudrate_modulation baudrate_modulation_of(target_type target) {
        return static_cast<baudrate_modulation>(static_cast<std::uint8_t>(target) & bits::target_type_baudrate_modulation_mask);
    }

    constexpr baudrate baudrate_of(target_type target) {
        switch (baudrate_modulation_of(target)) {
            case baudrate_modulation::kbps212_felica:
                return baudrate::kbps212;
            case baudrate_modulation::kbps424_felica:
                return baudrate::kbps424;
            default:
                return baudrate::kbps106;
        }
    }

    constexpr modulation modulation_of(target_type target) {
        switch (baudrate_modulation_of(target)) {
            case baudrate_modulation::kbps106_iso_iec_14443_typea:
                [[fallthrough]];
            case baudrate_modulation::kbps106_iso_iec_14443_3_typeb:
                return modulation::mifare_iso_iec_14443_3_type_ab_iso_iec_18092_passive_kbps106;
            case baudrate_modulation::kbps212_felica:
                [[fallthrough]];
            case baudrate_modulation::kbps424_felica:
                return modulation::felica_iso_iec_18092_kbps212_424;
            case baudrate_modulation::kbps106_innovision_jewel_tag:
                return modulation::innovision_jewel_tag;
        }
        return modulation::iso_iec_18092_active;
    }

    namespace reg {
        addr::addr(reg::sfr_register sfr_reg)
            : std::array<std::uint8_t, 2>{{bits::sfr_registers_high, static_cast<std::uint8_t>(sfr_reg)}} {}

        addr::addr(std::uint16_t xram_mmap_reg)
            : std::array<std::uint8_t, 2>{{std::uint8_t(xram_mmap_reg >> 8),
                                           std::uint8_t(xram_mmap_reg & 0xff)}} {}
    }// namespace reg
}// namespace pn532

#endif//PN532_BITS_HPP