M5Unit-NFC 0.1.0 git rev:93745b5
Loading...
Searching...
No Matches
nfc_layer_a.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
17#ifndef M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_A_HPP
18#define M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_A_HPP
19
21#include "nfc/a/nfca.hpp"
22#include "nfc/isoDEP/isoDEP.hpp"
24#include "nfc/ndef/ndef.hpp"
25#include <vector>
26#include <memory>
27
28namespace m5 {
29
30namespace unit {
31class UnitMFRC522; // M5Unit-RFID
32class UnitWS1850S; // M5Unit-RFID
33class UnitST25R3916;
34class CapST25R3916;
35} // namespace unit
36
37namespace nfc {
38
44public:
45 struct Adapter;
47 explicit NFCLayerA(m5::unit::UnitMFRC522& u); // The implementation of this function is located in M5Unit-RFID
49 explicit NFCLayerA(m5::unit::UnitWS1850S& u); // The implementation of this function is located in M5Unit-RFID
54 virtual ~NFCLayerA();
55
58
67 virtual bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
68 const uint32_t timeout_ms) override;
69 // virtual bool transmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms) override;
70 // virtual bool receive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms) override;
75 virtual m5::nfc::NFCForumTag supportsNFCTag() const override;
80 virtual file_system_feature_t supportsFilesystem() const override;
85 virtual m5::nfc::isodep::IsoDEP* isoDEP() override
86 {
87 return &_isoDEP;
88 }
93 virtual uint16_t maximum_fifo_depth() const override;
95
101 inline bool isActive(const m5::nfc::a::PICC& picc) const
102 {
103 return _activePICC.valid() && _activePICC == picc;
104 }
111 {
112 return _activePICC;
113 }
119 {
120 return _cfg;
121 }
127 void config(const m5::nfc::a::config_t& cfg);
128
131
137 bool request(uint16_t& atqa);
144 bool wakeup(uint16_t& atqa);
145
155 bool detect(m5::nfc::a::PICC& picc, const uint32_t timeout_ms = 100U);
165 bool detect(std::vector<m5::nfc::a::PICC>& piccs, const uint32_t timeout_ms = 1000U);
175 bool select(m5::nfc::a::PICC& picc);
184 bool activate(const m5::nfc::a::PICC& picc, const bool force_rats = false);
192 bool reactivate(const m5::nfc::a::PICC& picc, const bool force_rats = false);
204 inline bool reactivate()
205 {
206 return reactivate(_activePICC);
207 }
209
212
218 bool deactivate();
219
227 bool identify(m5::nfc::a::PICC& picc);
228
236 bool read4(uint8_t rx[4], const uint8_t addr);
244 bool read16(uint8_t rx[16], const uint8_t addr);
255 bool read(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr,
256 const m5::nfc::a::mifare::classic::Key& key = m5::nfc::a::mifare::classic::DEFAULT_KEY);
267 bool read(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr, const m5::nfc::a::mifare::plus::AESKey& key);
268
280 bool write4(const uint8_t addr, const uint8_t* tx, const uint16_t tx_len, const bool safety = true);
292 bool write16(const uint8_t addr, const uint8_t* tx, const uint16_t tx_len, const bool safety = true);
304 bool write(const uint8_t saddr, const uint8_t* tx, const uint16_t tx_len,
305 const m5::nfc::a::mifare::classic::Key& key = m5::nfc::a::mifare::classic::DEFAULT_KEY);
316 bool write(const uint8_t addr, const uint8_t* tx, const uint16_t tx_len,
318
325 bool dump(const m5::nfc::a::mifare::classic::Key& mkey = m5::nfc::a::mifare::classic::DEFAULT_KEY);
333 bool dump(const uint8_t block);
335
339
346 const uint8_t block, const m5::nfc::a::mifare::classic::Key& key = m5::nfc::a::mifare::classic::DEFAULT_KEY);
354 const uint8_t block, const m5::nfc::a::mifare::classic::Key& key = m5::nfc::a::mifare::classic::DEFAULT_KEY);
355
385 bool mifareClassicReadAccessCondition(uint8_t& c123, const uint8_t block);
397 bool mifareClassicWriteAccessCondition(const uint8_t block, const uint8_t c123,
400
409 bool mifareClassicIsValueBlock(bool& is_value_block, const uint8_t block);
417 bool mifareClassicReadValueBlock(int32_t& value, const uint8_t block);
425 bool mifareClassicWriteValueBlock(const uint8_t block, const int32_t value);
437 bool mifareClassicDecrementValueBlock(const uint8_t block, const uint32_t delta, const bool transfer = true);
449 bool mifareClassicIncrementValueBlock(const uint8_t block, const uint32_t delta, const bool transfer = true);
457 bool mifareClassicTransferValueBlock(const uint8_t block);
465 bool mifareClassicRestoreValueBlock(const uint8_t block);
467
471
481
485
490 bool mifareUltralightCAuthenticate(const uint8_t key[16]);
492
496
510 const m5::nfc::a::mifare::plus::AESKey& card_config_key = m5::nfc::a::mifare::plus::DEFAULT_KEY,
511 const m5::nfc::a::mifare::plus::AESKey& card_master_key = m5::nfc::a::mifare::plus::DEFAULT_KEY,
512 const m5::nfc::a::mifare::plus::AESKey& l2_switch_key = m5::nfc::a::mifare::plus::DEFAULT_KEY,
513 const m5::nfc::a::mifare::plus::AESKey& l3_switch_key = m5::nfc::a::mifare::plus::DEFAULT_KEY,
514 const m5::nfc::a::mifare::plus::AESKey& aes_sector_key = m5::nfc::a::mifare::plus::DEFAULT_FF_KEY,
515 const m5::nfc::a::mifare::classic::Key& key_a = m5::nfc::a::mifare::classic::DEFAULT_KEY,
516 const m5::nfc::a::mifare::classic::Key& key_b = m5::nfc::a::mifare::classic::DEFAULT_KEY);
525 const m5::nfc::a::mifare::plus::AESKey& sl2_switch_key = m5::nfc::a::mifare::plus::DEFAULT_KEY);
534 const m5::nfc::a::mifare::plus::AESKey& l3_switch_key = m5::nfc::a::mifare::plus::DEFAULT_KEY);
535
537
541
546 bool ndefIsValidFormat(bool& valid);
557 bool ndefPrepareDesfire(const uint32_t max_ndef_size);
565 bool ndefRead(m5::nfc::ndef::TLV& msg);
573 bool ndefRead(std::vector<m5::nfc::ndef::TLV>& tlvs,
574 const m5::nfc::ndef::TagBits tagBits = m5::nfc::ndef::tagBitsAll);
583 bool ndefWrite(const m5::nfc::ndef::TLV& msg);
593 bool ndefWrite(const std::vector<m5::nfc::ndef::TLV>& tlvs);
595
596protected:
597 virtual bool read(uint8_t* rx, uint16_t& rx_len, const uint16_t saddr) override;
598 virtual bool write(const uint16_t saddr, const uint8_t* tx, const uint16_t tx_len) override;
599 inline virtual uint16_t first_user_block() const override
600 {
601 return _activePICC.firstUserBlock();
602 }
603 inline virtual uint16_t last_user_block() const override
604 {
605 return _activePICC.lastUserBlock();
606 }
607 inline virtual uint16_t user_area_size() const override
608 {
609 return _activePICC.userAreaSize();
610 }
611 inline virtual uint16_t unit_size_read() const override
612 {
613 return _activePICC.supportsNFC() ? (_activePICC.isMifareUltralight() ? 16 : 4) : 16;
614 }
615 inline virtual uint16_t unit_size_write() const override
616 {
617 return (_activePICC.supportsNFC()) ? 4 : 16;
618 }
619
620 bool identify_picc(m5::nfc::a::PICC& picc);
621 m5::nfc::a::Type identify_picc_st25ta();
622 uint8_t identify_plus_sl03();
623
624 bool read_using_fast(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr);
625 bool read_using_read16(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr,
627 bool write_using_write4(const uint8_t addr, const uint8_t* tx, const uint16_t tx_len);
628 bool write_using_write16(const uint8_t addr, const uint8_t* tx, const uint16_t tx_len,
630
631 bool nfca_request_ats(m5::nfc::a::ATS& ats, const uint8_t fsdi = 5, const uint8_t cid = 0);
632 bool nfca_deselect();
633
634 bool mifare_get_version_L3(uint8_t ver[8]);
635 bool mifare_get_version_L4_raw(uint8_t* ver, uint16_t& ver_len);
636 bool mifare_get_version_L4_wrapped(uint8_t* ver, uint16_t& ver_len);
637
638 bool mifare_plus_authenticateAES(const uint16_t key_no, const m5::nfc::a::mifare::plus::AESKey& key);
639 bool mifare_plus_authenticateAES_L3(const uint16_t key_no, const m5::nfc::a::mifare::plus::AESKey& key);
640 bool mifare_plus_read_plain_nomac(const uint16_t block, const uint8_t count, std::vector<uint8_t>& out);
641 bool mifare_plus_read_plain_mac(const uint16_t block, const uint8_t count, std::vector<uint8_t>& out);
642 bool mifare_plus_read_mac_l4(const uint16_t block, const uint8_t count, std::vector<uint8_t>& out,
643 const bool plain);
644 bool mifare_plus_write_mac_l4(const uint16_t block, const uint8_t* data, const uint16_t data_len, const bool plain);
645
646 bool mifare_classic_value_block(const m5::nfc::a::Command cmd, const uint8_t block, const uint32_t arg = 0);
647
648 bool mifare_ultralightC_authenticate1(uint8_t ek[8]);
649 bool mifare_ultralightC_authenticate2(uint8_t rx_ek[8], const uint8_t tx_ek[16]);
650
651 bool ntag_read_page(uint8_t* rx, uint16_t& rx_len, const uint8_t spage, const uint8_t epage);
652 bool ntag_write_page(const uint8_t page, const uint8_t tx[4]); // NTAG,UL,ULC
653
654 bool dump_sector_structure(const m5::nfc::a::PICC& picc, const m5::nfc::a::mifare::classic::Key& key);
655 bool dump_sector(const uint8_t sector);
656 bool dump_sector_mifare_plus_sl3(const uint8_t sector);
657 bool dump_page_structure(const uint16_t maxPage);
658 bool dump_page(const uint8_t page, const uint16_t maxPage);
659 bool dump_mifare_plus_sl3(const m5::nfc::a::mifare::plus::AESKey& key);
660 bool dump_desfire();
661 bool dump_desfire_light();
662 bool dump_st25ta();
663
664 static bool push_back_picc(std::vector<m5::nfc::a::PICC>& v, const m5::nfc::a::PICC& picc);
665
666protected:
667 m5::nfc::a::PICC _activePICC{};
671
672private:
673 bool mifare_plus_transceive_raw(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len);
674
675 // Session state for MIFARE Plus
676 struct MifarePlusSession {
677 bool authenticated{};
678 uint16_t key_no{};
679 uint16_t r_ctr{};
680 uint16_t w_ctr{};
681 uint8_t frame_num{};
682 std::array<uint8_t, 4> ti{};
683 std::array<uint8_t, 16> kenc{};
684 std::array<uint8_t, 16> kmac{};
685 };
686
687 MifarePlusSession _mfp_session{};
688 std::unique_ptr<Adapter> _impl;
689};
690
692// Impl for units
693struct NFCLayerA::Adapter {
694 virtual ~Adapter() = default;
695
696 virtual uint16_t max_fifo_depth() const = 0;
697
698 virtual bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
699 const uint32_t timeout_ms) = 0;
700
701 virtual bool request(uint16_t& atqa) = 0;
702 virtual bool wakeup(uint16_t& atqa) = 0;
703
704 virtual bool select(m5::nfc::a::PICC& picc) = 0;
705 virtual bool activate(const m5::nfc::a::PICC& picc) = 0;
706 virtual bool hlt() = 0;
707
708 virtual bool nfca_read_block(uint8_t rx[16], const uint8_t addr) = 0;
709 virtual bool nfca_write_block(const uint8_t addr, const uint8_t tx[16]) = 0;
710 virtual bool mifare_classic_authenticate(const bool auth_a, const m5::nfc::a::PICC& picc, const uint8_t block,
711 const m5::nfc::a::mifare::classic::Key& key) = 0;
712 virtual bool mifare_classic_value_block(const m5::nfc::a::Command cmd, const uint8_t block,
713 const uint32_t arg = 0) = 0;
714};
716
717} // namespace nfc
718} // namespace m5
719
720#endif
Common interface layer for each chip of the NFC-A reader.
Definition nfc_layer_a.hpp:43
bool dump(const m5::nfc::a::mifare::classic::Key &mkey=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Dump all blocks/files.
Definition nfc_layer_a.cpp:920
bool mifareClassicTransferValueBlock(const uint8_t block)
Transfer inner buffer value to block.
Definition nfc_layer_a.cpp:1118
bool request(uint16_t &atqa)
Send REQA to discover a PICC in IDLE.
Definition nfc_layer_a.cpp:202
virtual uint16_t first_user_block() const override
First user block.
Definition nfc_layer_a.hpp:599
bool mifareClassicReadValueBlock(int32_t &value, const uint8_t block)
Read the specific block as the value block.
Definition nfc_layer_a.cpp:1064
bool mifareClassicIsValueBlock(bool &is_value_block, const uint8_t block)
Is specific block the value block?
Definition nfc_layer_a.cpp:1032
bool detect(m5::nfc::a::PICC &picc, const uint32_t timeout_ms=100U)
Detect single idle PICC.
Definition nfc_layer_a.cpp:214
NFCLayerA(m5::unit::UnitMFRC522 &u)
Constructor with UnitMFRC522 (M5Unit-RFID)
bool mifarePlusUpgradeSecurityLevel2(const m5::nfc::a::mifare::plus::AESKey &sl2_switch_key=m5::nfc::a::mifare::plus::DEFAULT_KEY)
Upgrade security level to SL2 (AES over CRYPTO1)
Definition nfc_layer_a.cpp:1326
bool mifarePlusUpgradeSecurityLevel1(const m5::nfc::a::mifare::plus::AESKey &card_config_key=m5::nfc::a::mifare::plus::DEFAULT_KEY, const m5::nfc::a::mifare::plus::AESKey &card_master_key=m5::nfc::a::mifare::plus::DEFAULT_KEY, const m5::nfc::a::mifare::plus::AESKey &l2_switch_key=m5::nfc::a::mifare::plus::DEFAULT_KEY, const m5::nfc::a::mifare::plus::AESKey &l3_switch_key=m5::nfc::a::mifare::plus::DEFAULT_KEY, const m5::nfc::a::mifare::plus::AESKey &aes_sector_key=m5::nfc::a::mifare::plus::DEFAULT_FF_KEY, const m5::nfc::a::mifare::classic::Key &key_a=m5::nfc::a::mifare::classic::DEFAULT_KEY, const m5::nfc::a::mifare::classic::Key &key_b=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Upgrade security level to SL1 (Classic compatibility mode)
Definition nfc_layer_a.cpp:1236
bool write(const uint8_t saddr, const uint8_t *tx, const uint16_t tx_len, const m5::nfc::a::mifare::classic::Key &key=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Write any bytes to user area.
Definition nfc_layer_a.cpp:760
bool isActive(const m5::nfc::a::PICC &picc) const
Is the specified PICC currently active?
Definition nfc_layer_a.hpp:101
virtual uint16_t last_user_block() const override
Last user block.
Definition nfc_layer_a.hpp:603
virtual file_system_feature_t supportsFilesystem() const override
Supported file system features.
Definition nfc_layer_a.cpp:197
bool activate(const m5::nfc::a::PICC &picc, const bool force_rats=false)
Activate a specific PICC (anti-collision against the given PICC)
Definition nfc_layer_a.cpp:284
bool mifareUltralightCAuthenticate(const uint8_t key[16])
Authentication for MIFARE UltralightC.
Definition nfc_layer_a.cpp:1158
bool mifareUltralightChangeFormatToNDEF()
Write change to NFC Type-2 (NDEF) format for MIFARE Ultralight/C.
Definition nfc_layer_a.cpp:1128
bool ndefPrepareDesfire(const uint32_t max_ndef_size)
Prepare NDEF files on MIFARE DESFire (EV1/EV2/EV3)
Definition nfc_layer_a.cpp:1376
bool mifareClassicWriteValueBlock(const uint8_t block, const int32_t value)
Write the specific block as the value block.
Definition nfc_layer_a.cpp:1091
bool ndefIsValidFormat(bool &valid)
Is the PICC data in NDEF format?
Definition nfc_layer_a.cpp:1362
bool select(m5::nfc::a::PICC &picc)
Select a PICC (anti-collision + SELECT cascade to ACTIVE)
Definition nfc_layer_a.cpp:269
virtual m5::nfc::isodep::IsoDEP * isoDEP() override
Get ISO-DEP context.
Definition nfc_layer_a.hpp:85
bool read16(uint8_t rx[16], const uint8_t addr)
Read the 1 block / 4 page (16 bytes)
Definition nfc_layer_a.cpp:534
NFCLayerA(m5::unit::UnitWS1850S &u)
Constructor with UnitWS1850S (M5Unit-RFID)
bool mifareClassicDecrementValueBlock(const uint8_t block, const uint32_t delta, const bool transfer=true)
Decrement value of the value block.
Definition nfc_layer_a.cpp:1102
const m5::nfc::a::PICC & activatedPICC() const
Retrieve the currently activated PICC.
Definition nfc_layer_a.hpp:110
bool ndefRead(m5::nfc::ndef::TLV &msg)
Read NDEF Message TLV.
Definition nfc_layer_a.cpp:1384
bool write4(const uint8_t addr, const uint8_t *tx, const uint16_t tx_len, const bool safety=true)
Write the 1 page (4 bytes)
Definition nfc_layer_a.cpp:712
bool reactivate()
Reactivate the previously selected PICC.
Definition nfc_layer_a.hpp:204
virtual uint16_t unit_size_read() const override
Unit size for read.
Definition nfc_layer_a.hpp:611
bool identify(m5::nfc::a::PICC &picc)
Identify the specified PICC type.
Definition nfc_layer_a.cpp:341
m5::nfc::a::config_t config() const
Get the NFC-A activation configuration.
Definition nfc_layer_a.hpp:118
bool read4(uint8_t rx[4], const uint8_t addr)
Read the 1 page.
Definition nfc_layer_a.cpp:516
bool mifareClassicAuthenticateB(const uint8_t block, const m5::nfc::a::mifare::classic::Key &key=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Authentication by KeyB for MIFARE classic.
Definition nfc_layer_a.cpp:965
bool deactivate()
Send HLTA to the currently selected PICC (deactivate)
Definition nfc_layer_a.cpp:326
bool mifareClassicWriteAccessCondition(const uint8_t block, const uint8_t c123, const m5::nfc::a::mifare::classic::Key &akey, const m5::nfc::a::mifare::classic::Key &bkey)
Write the specific block access conditions.
Definition nfc_layer_a.cpp:996
virtual m5::nfc::NFCForumTag supportsNFCTag() const override
Supported NFC Forum tag type.
Definition nfc_layer_a.cpp:192
bool ndefPrepareDesfireLight()
Prepare NDEF files on MIFARE DESFire Light.
Definition nfc_layer_a.cpp:1368
bool mifareClassicAuthenticateA(const uint8_t block, const m5::nfc::a::mifare::classic::Key &key=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Authentication by KeyA for MIFARE classic.
Definition nfc_layer_a.cpp:960
bool ndefWrite(const m5::nfc::ndef::TLV &msg)
Write NDEF message.
Definition nfc_layer_a.cpp:1401
virtual uint16_t unit_size_write() const override
Unit size for write.
Definition nfc_layer_a.hpp:615
bool mifarePlusUpgradeSecurityLevel3(const m5::nfc::a::mifare::plus::AESKey &l3_switch_key=m5::nfc::a::mifare::plus::DEFAULT_KEY)
Upgrade security level to SL3 (AES)
Definition nfc_layer_a.cpp:1344
virtual uint16_t maximum_fifo_depth() const override
Maximum FIFO depth in bytes.
Definition nfc_layer_a.cpp:187
bool mifareClassicReadAccessCondition(uint8_t &c123, const uint8_t block)
Read the specific block access conditions.
Definition nfc_layer_a.cpp:970
virtual uint16_t user_area_size() const override
User area size (bytes)
Definition nfc_layer_a.hpp:607
bool mifareClassicRestoreValueBlock(const uint8_t block)
Restore block value to inner buffer.
Definition nfc_layer_a.cpp:1123
bool read(uint8_t *rx, uint16_t &rx_len, const uint8_t saddr, const m5::nfc::a::mifare::classic::Key &key=m5::nfc::a::mifare::classic::DEFAULT_KEY)
Read any bytes from user area.
Definition nfc_layer_a.cpp:542
bool wakeup(uint16_t &atqa)
Send WUPA to wake a PICC from IDLE or HALT.
Definition nfc_layer_a.cpp:207
bool write16(const uint8_t addr, const uint8_t *tx, const uint16_t tx_len, const bool safety=true)
Write the 1 block / 4 page (16 bytes)
Definition nfc_layer_a.cpp:728
virtual bool transceive(uint8_t *rx, uint16_t &rx_len, const uint8_t *tx, const uint16_t tx_len, const uint32_t timeout_ms) override
Transceive (NFC-A)
Definition nfc_layer_a.cpp:181
bool mifareClassicIncrementValueBlock(const uint8_t block, const uint32_t delta, const bool transfer=true)
Increment value of the value block.
Definition nfc_layer_a.cpp:1110
Common interface for NFC layer.
Definition nfc_layer.hpp:26
ISO Data Exchange Protocol.
Definition isoDEP.hpp:240
NDEF operations layer.
Definition ndef_layer.hpp:35
NDEF TLV container.
Definition ndef_tlv.hpp:27
ST25R3916 unit in CapCC1101 (SPI)
Definition unit_ST25R3916.hpp:2113
ST25R3916 Unit.
Definition unit_ST25R3916.hpp:39
ISO Data Exchange Protocol.
std::array< uint8_t, 16 > AESKey
MIFARE Plus SL2/3 Key (AES)
Definition mifare.hpp:278
std::array< uint8_t, 6 > Key
MIFARE classic Key.
Definition mifare.hpp:50
Top level namespace of M5Stack.
NFC related definitions.
Unit-related namespace.
NFC-V definitions.
NDEF related.
uint8_t TagBits
TLV(Tag,Length,Value) tag bit group for type2/5.
Definition ndef.hpp:55
Common layer for NDEF related.
uint8_t file_system_feature_t
Alias for file_system_feature_t.
Definition nfc.hpp:62
NFCForumTag
NFC Forum Tag Type.
Definition nfc.hpp:39
Common layer for NFC related units.
NFC-A definitions.
Command
ISO-14443-3/4,MIFARE,NTAG commands.
Definition nfca.hpp:684
Type
Type of the PICC.
Definition nfca.hpp:31
Answer to request.
Definition nfca.hpp:394
PICC for NFC-A.
Definition nfca.hpp:481
uint16_t userAreaSize() const
Total user area size.
Definition nfca.hpp:604
bool supportsNFC() const
Supports NFC?
Definition nfca.hpp:633
uint16_t lastUserBlock() const
Total size.
Definition nfca.hpp:619
bool valid() const
Valid?
Definition nfca.hpp:502
uint16_t firstUserBlock() const
Gets the first user block/page address.
Definition nfca.hpp:615
bool isMifareUltralight() const
Is MIFARE Ultralight series?
Definition nfca.hpp:539
NFC-A activation configuration (RATS parameters)
Definition nfca.hpp:729