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