M5Unit-NFC 0.1.1 git rev:9bb1360
Loading...
Searching...
No Matches
ndef.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_UNIFIED_NFC_NDEF_NDEF_HPP
11#define M5_UNIT_UNIFIED_NFC_NDEF_NDEF_HPP
12
13#include <cstdint>
14#include <vector>
15#include <m5_utility/stl/extension.hpp>
16#include <m5_utility/log/library_log.hpp>
17
18namespace m5 {
19namespace nfc {
24namespace ndef {
25
28constexpr uint8_t NDEF_MAJOR_VERSION{1};
29constexpr uint8_t NDEF_MINOR_VERSION{0};
30constexpr uint8_t MAGIC_NO_CC4{0xE1};
31constexpr uint8_t MAGIC_NO_CC8{0xE2};
32constexpr uint8_t ACCESS_FREE{0x00};
33constexpr uint8_t ACCESS_PROPRIETARY{0x02};
34
35constexpr uint8_t TYPE2_CC_BLOCK{3};
36constexpr uint16_t CC4_MAX_NDEF_LENGTH{2040};
38
43enum class Tag : uint8_t {
44 Null,
47 Message,
48 Proprietary = 0xFD,
50};
51
56using TagBits = uint8_t;
57
59constexpr inline TagBits tag_to_tagbit(const Tag t)
60{
61 return (t == Tag::Null) ? (1u << 0)
62 : (t == Tag::LockControl) ? (1u << 1)
63 : (t == Tag::MemoryControl) ? (1u << 2)
64 : (t == Tag::Message) ? (1u << 3)
65 : (t == Tag::Proprietary) ? (1u << 4)
66 : (t == Tag::Terminator) ? (1u << 5)
67 : 0u;
68}
69
71template <typename... Ts>
72struct are_all_tag : std::true_type {
73};
74template <typename T, typename... Ts>
75struct are_all_tag<T, Ts...> : std::integral_constant<bool, std::is_same<Tag, T>::value && are_all_tag<Ts...>::value> {
76};
77
78constexpr TagBits make_tag_bits_impl(TagBits acc)
79{
80 return acc;
81}
82
83template <typename... Rest>
84constexpr TagBits make_tag_bits_impl(TagBits acc, Tag head, Rest... rest)
85{
86 return make_tag_bits_impl(acc | tag_to_tagbit(head), rest...);
87}
89
95template <typename... T>
96constexpr TagBits make_tag_bits(T... tags)
97{
98 static_assert(sizeof...(tags) > 0, "At least one Tag is required");
99 static_assert(are_all_tag<T...>::value, "Arguments must be Tag");
100 return make_tag_bits_impl(0u, tags...);
101}
102
104inline constexpr bool contains_tag(const TagBits tb, const Tag t)
105{
106 return (tb & tag_to_tagbit(t)) != 0;
107}
108
111 make_tag_bits(m5::nfc::ndef::Tag::LockControl, m5::nfc::ndef::Tag::MemoryControl, m5::nfc::ndef::Tag::Message,
112 m5::nfc::ndef::Tag::Proprietary, m5::nfc::ndef::Tag::Terminator);
114constexpr TagBits tagBitsMessage = make_tag_bits(m5::nfc::ndef::Tag::Message);
115
117inline bool is_valid_tag(const uint8_t t)
118{
119 return t <= m5::stl::to_underlying(Tag::Message) || t == m5::stl::to_underlying(Tag::Proprietary) ||
120 t == m5::stl::to_underlying(Tag::Terminator);
121}
122
124inline bool is_terminator_tag(const uint8_t t)
125{
126 return t == m5::stl::to_underlying(Tag::Terminator);
127}
128
133enum class URIProtocol : uint8_t {
134 NA,
135 HTTP_WWW,
136 HTTPS_WWW,
137 HTTP,
138 HTTPS,
139 TEL,
140 MAILTO,
141 FTP_AA,
142 FTP_FTP,
143 FTPS,
144 SFTP,
145 SMB,
146 NFS,
147 FTP,
148 DEV,
149 NEWS,
150 TELNET,
151 IMAP,
152 RSTP,
153 URN,
154 POP,
155 SIP,
156 SIPS,
157 TFTP,
158 BTSPP,
159 BTL2CAP,
160 BTGOEP,
161 TCPOBEX,
162 IRDAOBEX,
163 FILE,
164 URN_EPC_ID,
168 URN_EPC,
169 NFC,
170};
171
173const char* get_uri_idc_string(const URIProtocol protocol);
174
179namespace type2 {
185 uint8_t block[4]{};
186
187 inline bool valid() const
188 {
189 return (block[0] == MAGIC_NO_CC4) && (major_version() >= NDEF_MAJOR_VERSION) &&
190 ((int16_t)minor_version() >= NDEF_MINOR_VERSION) && ndef_size();
191 }
192 inline bool can_read() const
193 {
194 return read_access() == ACCESS_FREE;
195 }
196 inline bool can_write() const
197 {
198 return write_access() == ACCESS_FREE;
199 }
200
201 // Getter
202 inline uint8_t major_version() const
203 {
204 return (block[1] >> 4) & 0x0F;
205 }
206 inline uint8_t minor_version() const
207 {
208 return block[1] & 0x0F;
209 }
210 inline uint16_t ndef_size() const
211 {
212 return (uint16_t)block[2] << 3;
213 }
214 inline uint8_t read_access() const
215 {
216 return (block[3] >> 4) & 0x0F;
217 }
218 inline uint8_t write_access() const
219 {
220 return block[3] & 0x0F;
221 }
222 // Setter
223 inline void major_version(const uint8_t v)
224 {
225 block[1] = (block[1] & 0x0F) | ((v & 0x0F) << 4);
226 }
227 inline void minor_version(const uint8_t v)
228 {
229 block[1] = (block[1] & 0xF0) | (v & 0x0F);
230 }
231 inline void ndef_size(const uint16_t sz)
232 {
233 block[2] = (sz > 2040) ? 0 : (sz >> 3);
234 }
235 inline void read_access(const uint8_t a)
236 {
237 block[3] = (block[3] & 0x0F) | ((a & 0x03) << 4);
238 }
239 inline void write_access(const uint8_t a)
240 {
241 block[3] = (block[3] & 0xF0) | (a & 0x03);
242 }
243};
244} // namespace type2
245
250namespace type3 {
256 uint8_t block[16]{};
257
258 static constexpr uint8_t DEFAULT_VERSION{0x10};
259
264 enum class WriteFlag : uint8_t {
265 Done,
266 InProgress = 0x0F,
267 };
268
273 enum class AccessFlag : uint8_t {
274 ReadOnly,
275 ReadWrite,
276 };
277 AttributeBlock() : block{DEFAULT_VERSION}
278 {
279 }
280
281 // Getter
282 inline uint8_t version() const
283 {
284 return block[0];
285 }
286 inline uint8_t max_block_to_read() const
287 {
288 return block[1];
289 }
290 inline uint8_t max_block_to_write() const
291 {
292 return block[2];
293 }
294 inline uint16_t blocks_for_ndef_storage() const
295 {
296 return ((uint16_t)block[3] << 8) | block[4];
297 }
298 inline WriteFlag write_flag() const
299 {
300 return (block[9] == 0) ? WriteFlag::Done : WriteFlag::InProgress;
301 }
302 inline AccessFlag access_flag() const
303 {
304 return (AccessFlag)block[10];
305 }
306 inline uint32_t current_ndef_message_length() const
307 {
308 return ((uint32_t)block[11] << 16) | ((uint32_t)block[12] << 8) | block[13];
309 }
310 inline uint16_t check_sum() const
311 {
312 return ((uint16_t)block[14] << 8) | block[15];
313 }
314
315 // Setter
316 inline void version(const uint8_t ver)
317 {
318 block[0] = ver;
319 }
320 inline void max_block_to_read(const uint8_t b)
321 {
322 block[1] = b;
323 }
324 inline void max_block_to_write(const uint8_t b)
325 {
326 block[2] = b;
327 }
328 inline void blocks_for_ndef_storage(const uint16_t s)
329 {
330 block[3] = s >> 8;
331 block[4] = s & 0xFF;
332 }
333 inline void write_flag(const WriteFlag f)
334 {
335 block[9] = m5::stl::to_underlying(f);
336 }
337 inline void access_flag(const AccessFlag f)
338 {
339 block[10] = m5::stl::to_underlying(f);
340 }
341 inline void current_ndef_message_length(const uint32_t len)
342 {
343 block[11] = len >> 16;
344 block[12] = len >> 8;
345 block[13] = len & 0xFF;
346 }
347
348 //
349 bool valid() const;
350 uint16_t calculate_check_sum() const;
351 uint16_t update_check_sum();
352};
353
354} // namespace type3
355
360namespace type4 {
361
362constexpr uint16_t CC_FILE_ID{0xE103};
363constexpr uint8_t NDEF_AID[] = {0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
364constexpr uint16_t NDEF_APP_FID{0xE110};
365constexpr uint16_t NDEF_FILE_ID{0xE104};
366
371enum class FileControlTag : uint8_t {
372 Message = 0x04,
373 Proprietary = 0x05,
374 // Extended = 0x06, //!< Extended NDEF (Over 32KB) Type 4 Tag Specification v2.0 or later
375 Invalid = 0xFF,
376};
377
382using FileControlTagBits = uint8_t;
383
385constexpr inline FileControlTagBits fc_to_fcbit(const FileControlTag t)
386{
387 return (t == FileControlTag::Message) ? (1u << 0) : ((t == FileControlTag::Proprietary) ? (1u << 1) : 0u);
388}
389
391template <typename... Ts>
392struct are_all_fc : std::true_type {
393};
394template <typename T, typename... Ts>
395struct are_all_fc<T, Ts...>
396 : std::integral_constant<bool, std::is_same<FileControlTag, T>::value && are_all_fc<Ts...>::value> {
397};
398
399constexpr FileControlTagBits make_fc_bits_impl(FileControlTagBits acc)
400{
401 return acc;
402}
403
404template <typename... Rest>
405constexpr FileControlTagBits make_fc_bits_impl(FileControlTagBits acc, FileControlTag head, Rest... rest)
406{
407 return make_fc_bits_impl(acc | fc_to_fcbit(head), rest...);
408}
410
416template <typename... T>
417constexpr FileControlTagBits make_fc_bits(T... fcs)
418{
419 static_assert(sizeof...(fcs) > 0, "At least one Fc is required");
420 static_assert(are_all_fc<T...>::value, "Arguments must be Fc");
421 return make_fc_bits_impl(0u, fcs...);
422}
423
425inline constexpr bool contains_file_control_tag(const FileControlTagBits tb, const FileControlTag t)
426{
427 return (tb & fc_to_fcbit(t)) != 0;
428}
429
431constexpr FileControlTagBits fcBitsAll = make_fc_bits(FileControlTag::Message, FileControlTag::Proprietary);
433constexpr FileControlTagBits fcBitsMessage = make_fc_bits(FileControlTag::Message);
434
440 uint8_t tag{};
441 uint8_t len{};
442 uint16_t ndef_file_id{};
443 uint16_t ndef_file_size{};
444 uint8_t read_access{};
445 uint8_t write_access{};
446
447 inline FileControlTag fctag() const
448 {
449 if (this->tag == 0x04 || this->tag == 0x05) {
450 return static_cast<FileControlTag>(this->tag);
451 }
452 return FileControlTag::Invalid;
453 }
454};
455
461 uint16_t cclen{};
462 uint8_t mapping_version{};
463 uint16_t mle{};
464 uint16_t mlc{};
465 std::vector<FileControlTLV> fctlvs{};
466
467 inline uint8_t major_version() const
468 {
469 return (mapping_version >> 4) & 0x0F;
470 }
471 inline uint8_t minor_version() const
472 {
473 return mapping_version & 0x0F;
474 }
475 inline bool valid() const
476 {
477 return cclen > 7 && !this->fctlvs.empty();
478 }
479
480 inline FileControlTLV fctlv(const uint8_t index) const
481 {
482 return index < this->fctlvs.size() ? this->fctlvs[index] : FileControlTLV{};
483 }
484 FileControlTLV fctlv(const FileControlTag fc = FileControlTag::Message) const;
485
486 bool parse(const uint8_t* buf, const uint16_t len);
487};
488
489} // namespace type4
490
495namespace type5 {
501 uint8_t block[8]{};
502
503 inline bool valid() const
504 {
505 return ((block[0] == MAGIC_NO_CC4) || (block[0] == MAGIC_NO_CC8)) && (major_version() >= NDEF_MAJOR_VERSION) &&
506 ((int16_t)minor_version() >= NDEF_MINOR_VERSION) && ndef_size();
507 }
508 inline bool can_read() const
509 {
510 return read_access() == ACCESS_FREE;
511 }
512 inline bool can_write() const
513 {
514 return write_access() == ACCESS_FREE;
515 }
516 inline uint8_t size() const
517 {
518 return (block[0] == MAGIC_NO_CC4) ? 4 : ((block[0] == MAGIC_NO_CC8) ? 8 : 0);
519 }
520 // Getter
521 inline uint8_t major_version() const
522 {
523 return (block[1] >> 6) & 0x03;
524 }
525 inline uint8_t minor_version() const
526 {
527 return (block[1] >> 4) & 0x03;
528 }
529 inline uint16_t ndef_size() const
530 {
531 // MLEN counts the memory in units of 8 bytes whatever the size of the CC
532 return (block[0] == MAGIC_NO_CC4) ? ((uint16_t)block[2] << 3)
533 : (block[0] == MAGIC_NO_CC8) ? ((uint16_t)(((uint16_t)block[6] << 8) | block[7]) << 3)
534 : 0;
535 }
536 inline uint8_t read_access() const
537 {
538 return (block[1] >> 2) & 0x03;
539 }
540 inline uint8_t write_access() const
541 {
542 return block[1] & 0x03;
543 }
544 inline uint8_t additional_feature() const
545 {
546 return block[3];
547 }
548 // Setter
549 inline void major_version(const uint8_t v)
550 {
551 block[1] = (block[1] & 0x3F) | ((v & 0x03) << 6);
552 }
553 inline void minor_version(const uint8_t v)
554 {
555 block[1] = (block[1] & 0xCF) | ((v & 0x03) << 4);
556 }
557 inline void ndef_size(const uint16_t sz)
558 {
559 if (block[0] == MAGIC_NO_CC4 && sz <= 2040) {
560 block[2] = (sz >> 3);
561 } else if (block[0] == MAGIC_NO_CC8) {
562 const uint16_t mlen = sz >> 3;
563 block[6] = (mlen >> 8);
564 block[7] = mlen & 0xFF;
565 } else {
566 // A four byte container holds MLEN in one byte, so anything above 2040 needs the eight
567 // byte form. Say so rather than leave the caller thinking the size was taken
568 M5_LIB_LOGW("Cannot store %u bytes in a %02X capability container", sz, block[0]);
569 }
570 }
571 inline void read_access(const uint8_t a)
572 {
573 block[1] = (block[1] & 0xF3) | ((a & 0x03) << 2);
574 }
575 inline void write_access(const uint8_t a)
576 {
577 block[1] = (block[1] & 0xFC) | (a & 0x03);
578 }
579 inline void additional_feature(const uint8_t af)
580 {
581 block[3] = af;
582 }
583};
584} // namespace type5
585
586} // namespace ndef
587} // namespace nfc
588} // namespace m5
589
590#endif
NFC-A definitions.
NFC-B definitions.
NFC-F definitions.
Top level namespace of M5Stack.
For NDEF.
NFC related definitions.
For NDEF Type2.
For NDEF Type3.
For NDEF Type4.
For NDEF Type5.
NFC-V definitions.
constexpr FileControlTagBits make_fc_bits(T... fcs)
Make FileControlBit from FileControlTag.
Definition ndef.hpp:417
constexpr uint16_t NDEF_APP_FID
ISO DF FID for NDEF app.
Definition ndef.hpp:364
constexpr uint8_t TYPE2_CC_BLOCK
Block for CC type2.
Definition ndef.hpp:35
constexpr uint8_t NDEF_MINOR_VERSION
Support minor version.
Definition ndef.hpp:29
constexpr uint8_t NDEF_AID[]
AID for NDEF.
Definition ndef.hpp:363
constexpr uint8_t MAGIC_NO_CC4
4 byte CC
Definition ndef.hpp:30
FileControlTag
File control for File Control TLV for type4.
Definition ndef.hpp:371
@ Invalid
Unknown / not yet decoded.
constexpr uint8_t ACCESS_PROPRIETARY
Access condition (proprietary)
Definition ndef.hpp:33
uint8_t TagBits
TLV(Tag,Length,Value) tag bit group for type2/5.
Definition ndef.hpp:56
constexpr TagBits make_tag_bits(T... tags)
Make TagBit from tag.
Definition ndef.hpp:96
constexpr FileControlTagBits fcBitsAll
All fcs.
Definition ndef.hpp:431
constexpr TagBits tag_to_tagbit(const Tag t)
Tag to TagBit.
Definition ndef.hpp:59
URIProtocol
URI Identifier Code.
Definition ndef.hpp:133
@ FTP_AA
ftp://anonymous:anonymous@
constexpr TagBits tagBitsAll
All tags.
Definition ndef.hpp:110
constexpr TagBits tagBitsMessage
Message only.
Definition ndef.hpp:114
constexpr FileControlTagBits fcBitsMessage
Message only.
Definition ndef.hpp:433
constexpr FileControlTagBits fc_to_fcbit(const FileControlTag t)
Tag to TagBit.
Definition ndef.hpp:385
constexpr bool contains_file_control_tag(const FileControlTagBits tb, const FileControlTag t)
Check whether FileControlTagBits contains given FileControl.
Definition ndef.hpp:425
bool is_terminator_tag(const uint8_t t)
Is terminator?
Definition ndef.hpp:124
constexpr uint8_t ACCESS_FREE
Access condition (Free access)
Definition ndef.hpp:32
constexpr uint16_t CC_FILE_ID
CC file id.
Definition ndef.hpp:362
constexpr uint8_t MAGIC_NO_CC8
8 byte CC (Type5)
Definition ndef.hpp:31
Tag
TLV(Tag,Length,Value) tag for type2/5.
Definition ndef.hpp:43
@ Proprietary
Proprietary.
@ LockControl
Lock control.
@ MemoryControl
Memory control.
@ Terminator
Terminator.
constexpr uint16_t NDEF_FILE_ID
ISO EF FID for NDEF file.
Definition ndef.hpp:365
bool is_valid_tag(const uint8_t t)
Is valid tag?
Definition ndef.hpp:117
constexpr uint8_t NDEF_MAJOR_VERSION
Support major version.
Definition ndef.hpp:28
constexpr bool contains_tag(const TagBits tb, const Tag t)
Check whether TagBits contains given Tag.
Definition ndef.hpp:104
constexpr uint16_t CC4_MAX_NDEF_LENGTH
Maximum ndef length for 4 byte CC.
Definition ndef.hpp:36
NFC
NFC type.
Definition nfc.hpp:27
Capability container for Type2.
Definition ndef.hpp:184
For Type 3 tag (T3T)
Definition ndef.hpp:255
AccessFlag
Permission to read and write.
Definition ndef.hpp:273
WriteFlag
Flag for fault tolerance.
Definition ndef.hpp:264
Capability container for Type4.
Definition ndef.hpp:460
uint16_t cclen
CC length.
Definition ndef.hpp:461
uint16_t mlc
Maximum Lc.
Definition ndef.hpp:464
uint16_t mle
Maximum Le.
Definition ndef.hpp:463
uint8_t mapping_version
Mapping version.
Definition ndef.hpp:462
File control TLV.
Definition ndef.hpp:439
uint8_t tag
File control tag.
Definition ndef.hpp:440
uint8_t read_access
Read access.
Definition ndef.hpp:444
uint8_t len
Length.
Definition ndef.hpp:441
uint8_t write_access
Write access.
Definition ndef.hpp:445
uint16_t ndef_file_size
NDEF file size.
Definition ndef.hpp:443
uint16_t ndef_file_id
NDEF file ID.
Definition ndef.hpp:442
Capability container for Type5.
Definition ndef.hpp:500