Program Listing for File scanner.hpp

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

//
// Created by spak on 1/18/23.
//

#ifndef PN532_SCANNER_HPP
#define PN532_SCANNER_HPP

#include <pn532/controller.hpp>

namespace pn532 {
    class scanner;

    enum struct post_interaction {
        reject,
        release,
        retain,
        abort
    };

    struct scanned_target {
        std::uint8_t index = std::numeric_limits<std::uint8_t>::max();

        target_type type = target_type::generic_passive_106kbps;

        std::vector<std::uint8_t> nfcid{};

        scanned_target() = default;

        template <target_type Type>
        scanned_target(std::uint8_t index_, poll_target<Type> const &entry);

        scanned_target(std::uint8_t index_, any_poll_target const &entry);

        [[nodiscard]] bool operator==(scanned_target const &other) const;
        [[nodiscard]] bool operator!=(scanned_target const &other) const;
        [[nodiscard]] bool operator<(scanned_target const &other) const;
        [[nodiscard]] bool operator>(scanned_target const &other) const;
        [[nodiscard]] bool operator<=(scanned_target const &other) const;
        [[nodiscard]] bool operator>=(scanned_target const &other) const;
    };

    struct scanner_responder {
        virtual void on_activation(scanner &scanner, scanned_target const &target) {}

        virtual void on_release(scanner &scanner, scanned_target const &target) {}

        virtual void on_leaving_rf(scanner &scanner, scanned_target const &target) {}

        virtual void on_failed_scan(scanner &scanner, channel_error err) {}

        [[nodiscard]] virtual std::vector<target_type> get_scan_target_types(scanner &scanner) const {
            return controller::poll_all_targets;
        }

        [[nodiscard]] virtual bool should_interact(scanner &scanner, scanned_target const &target) const {
            return true;
        }

        [[nodiscard]] virtual post_interaction interact(scanner &scanner, scanned_target const &target) {
            return post_interaction::reject;
        }

        virtual ~scanner_responder() = default;
    };

    class scanner {
        std::shared_ptr<controller> _ctrl = nullptr;
        ms _timeout = 5s;
        bool _stop = false;
        std::vector<scanned_target> _rejection_list{};
        std::vector<scanned_target> _in_rf{};

        void update_rejection_list(scanner_responder &responder);

        void update_in_rf_list(std::vector<any_poll_target> const &targets);

        [[nodiscard]] bool is_in_rejection_list(scanned_target const &target) const;

    public:
        scanner() = default;

        explicit scanner(std::shared_ptr<controller> ctrl, ms max_scan_interval = 5s);

        scanner(scanner const &) = delete;
        scanner &operator=(scanner const &) = delete;
        scanner(scanner &&) noexcept = default;
        scanner &operator=(scanner &&) noexcept = default;

        [[nodiscard]] inline std::vector<scanned_target> const &in_rf() const;

        [[nodiscard]] inline ms max_scan_interval() const;

        inline void set_max_scan_interval(ms timeout);

        void loop(scanner_responder &responder, bool init_and_test = true);

        [[nodiscard]] controller &ctrl();

        [[nodiscard]] controller const &ctrl() const;

        void stop();
    };
}// namespace pn532


namespace pn532 {

    ms scanner::max_scan_interval() const {
        return _timeout;
    }

    void scanner::set_max_scan_interval(ms timeout) {
        _timeout = timeout;
    }

    std::vector<scanned_target> const &scanner::in_rf() const {
        return _in_rf;
    }

    template <target_type Type>
    scanned_target::scanned_target(std::uint8_t index_, poll_target<Type> const &entry) : index{index_}, type{Type} {
        static constexpr auto BM = baudrate_modulation_of(Type);
        if constexpr (std::is_base_of_v<poll_target_dep_passive<BM>, poll_target<Type>>) {
            // Obtain NFCID3t from the atr_res_info, and the index from the target bit
            index = entry.logical_index;
            nfcid.resize(entry.atr_info.nfcid.size());
            std::copy(std::begin(entry.atr_info.nfcid), std::end(entry.atr_info.nfcid), std::begin(nfcid));
        } else if constexpr (std::is_base_of_v<target<BM>, poll_target<Type>>) {
            // Obtain the logical index from the target bit, and then differentiate
            index = entry.logical_index;
            if constexpr (BM == baudrate_modulation::kbps106_iso_iec_14443_typea) {
                nfcid = entry.nfcid;
            } else if constexpr (BM == baudrate_modulation::kbps212_felica or BM == baudrate_modulation::kbps424_felica) {
                nfcid.resize(entry.nfcid_2t.size());
                std::copy(std::begin(entry.nfcid_2t), std::end(entry.nfcid_2t), std::begin(nfcid));
            } else if constexpr (BM == baudrate_modulation::kbps106_iso_iec_14443_3_typeb) {
                // Slice off the PUPI (Pseudo-Unique PICC Identifier) out of the atqb response
                if (entry.atqb_response.size() >= 5) {
                    nfcid.resize(4);
                    std::copy_n(std::begin(entry.atqb_response) + 1, 4, std::begin(nfcid));
                } else {
                    // Just use the whole atqb response
                    nfcid.resize(entry.atqb_response.size());
                    std::copy(std::begin(entry.atqb_response), std::end(entry.atqb_response), std::begin(nfcid));
                }
            } else if constexpr (BM == baudrate_modulation::kbps106_innovision_jewel_tag) {
                // Use jewel id
                nfcid.resize(entry.jewel_id.size());
                std::copy(std::begin(entry.jewel_id), std::end(entry.jewel_id), std::begin(nfcid));
            }
        } else {
            static_assert(std::is_base_of_v<poll_target_with_atr, poll_target<Type>>);
            // Obtain NFCID3t from the atr_res_info, we cannot do anything about the index
            nfcid.resize(entry.atr_info.nfcid.size());
            std::copy(std::begin(entry.atr_info.nfcid), std::end(entry.atr_info.nfcid), std::begin(nfcid));
        }
    }
}// namespace pn532
#endif//PN532_SCANNER_HPP