Program Listing for File helper.hpp

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

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

#ifndef PN532_SCAN_HELPER_HPP
#define PN532_SCAN_HELPER_HPP

#include <pn532/controller.hpp>

namespace pn532::helper {
    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;
        [[nodiscard]] inline explicit operator bool() const noexcept;
    };

    struct autorelease_target : scanned_target {
        std::weak_ptr<controller> ctrl = {};

        autorelease_target() = default;

        inline autorelease_target(std::shared_ptr<controller> const &ctrl_, scanned_target target_);

        template <target_type Type>
        autorelease_target(std::shared_ptr<controller> const &ctrl_, std::uint8_t index_, poll_target<Type> const &entry);

        inline autorelease_target(std::shared_ptr<controller> const &ctrl_, std::uint8_t index_, any_poll_target const &entry);

        inline result<rf_status> release(ms timeout = default_timeout);

        inline ~autorelease_target();
    };

    [[nodiscard]] result<autorelease_target> scan(
            std::shared_ptr<controller> const &ctrl,
            scanned_target const &skip_prev_target = scanned_target{},
            std::vector<target_type> const &targets = controller::poll_all_targets,
            ms timeout = long_timeout);

}// namespace pn532::helper


namespace pn532::helper {

    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));
        }
    }

    inline scanned_target::operator bool() const noexcept {
        return index < std::numeric_limits<std::uint8_t>::max();
    }

    template <target_type Type>
    autorelease_target::autorelease_target(std::shared_ptr<controller> const &ctrl_, std::uint8_t index_, poll_target<Type> const &entry)
        : scanned_target{index_, entry}, ctrl{ctrl_->weak_from_this()} {}

    autorelease_target::autorelease_target(std::shared_ptr<controller> const &ctrl_, std::uint8_t index_, any_poll_target const &entry)
        : scanned_target{index_, entry}, ctrl{ctrl_->weak_from_this()} {}

    autorelease_target::autorelease_target(std::shared_ptr<controller> const &ctrl_, scanned_target target_)
        : scanned_target{std::move(target_)}, ctrl{ctrl_->weak_from_this()} {}

    result<rf_status> autorelease_target::release(ms timeout) {
        if (index < std::numeric_limits<std::uint8_t>::max()) {
            if (const auto ctrl_strong_ref = ctrl.lock(); ctrl_strong_ref) {
                auto r = ctrl_strong_ref->initiator_release(index);
                if (r) {
                    // Done, the weak ref can be destroyed
                    ctrl = {};
                }
                return r;
            }
            return channel_error::app_error;
        }
        return channel_error::malformed;
    }

    autorelease_target::~autorelease_target() {
        release();
    }
}// namespace pn532::helper
#endif//PN532_SCAN_HELPER_HPP