SE050 Driver
API reference
Loading...
Searching...
No Matches
se050_t1_session.hpp
Go to the documentation of this file.
1
22#pragma once
23
24#include "se050_atr.hpp"
25#include "se050_crc.hpp"
26#include "se050_types.hpp"
27
28#include <algorithm>
29#include <cstddef>
30#include <cstdint>
31#include <cstring>
32
33namespace se050 {
34
36namespace t1 {
37
39inline constexpr std::uint8_t kNadHostToSe = 0x5AU;
41inline constexpr std::uint8_t kNadSeToHost = 0xA5U;
43inline constexpr std::size_t kMaxInformationField = 254U;
45inline constexpr std::size_t kMaxRawBlockBytes = 3U + kMaxInformationField + 2U;
46
48inline constexpr std::uint8_t kPcbSWarmReset = 0xC6U;
50inline constexpr std::uint8_t kPcbSGetAtr = 0xC7U;
52inline constexpr std::uint8_t kPcbSResyncReq = 0xC0U;
53inline constexpr std::uint8_t kPcbSResyncResp = 0xE0U;
55inline constexpr std::uint8_t kPcbSWtxReq = 0xC3U;
56inline constexpr std::uint8_t kPcbSWtxResp = 0xE3U;
57
58[[nodiscard]] inline constexpr bool IsIBlock(std::uint8_t pcb) noexcept {
59 return (pcb & 0x80U) == 0U;
60}
61[[nodiscard]] inline constexpr bool IsRBlock(std::uint8_t pcb) noexcept {
62 return (pcb & 0xC0U) == 0x80U;
63}
64[[nodiscard]] inline constexpr bool IsSBlock(std::uint8_t pcb) noexcept {
65 return (pcb & 0xC0U) == 0xC0U;
66}
67[[nodiscard]] inline constexpr bool IBlockMore(std::uint8_t pcb) noexcept {
68 return (pcb & 0x20U) != 0U;
69}
70[[nodiscard]] inline constexpr std::uint8_t IBlockPcb(std::uint8_t ns_bit, bool more) noexcept {
71 return static_cast<std::uint8_t>(((ns_bit & 1U) << 6) | (more ? 0x20U : 0U));
72}
73[[nodiscard]] inline constexpr std::uint8_t RBlockAckPcb(std::uint8_t nr_bit) noexcept {
74 return static_cast<std::uint8_t>(0x80U | ((nr_bit & 1U) << 4));
75}
76[[nodiscard]] inline constexpr std::uint8_t IBlockSeqFromPcb(std::uint8_t pcb) noexcept {
77 return static_cast<std::uint8_t>((pcb >> 6) & 1U);
78}
80[[nodiscard]] inline constexpr std::uint8_t RBlockNrFromPcb(std::uint8_t pcb) noexcept {
81 return static_cast<std::uint8_t>((pcb >> 4) & 1U);
82}
84inline constexpr std::uint8_t kRBlockErrEdc = 0x01U;
86inline constexpr std::uint8_t kRBlockErrOther = 0x02U;
88[[nodiscard]] inline constexpr std::uint8_t RBlockNackPcb(std::uint8_t nr_bit, std::uint8_t err) noexcept {
89 return static_cast<std::uint8_t>(0x80U | ((nr_bit & 1U) << 4) | (err & 0x0FU));
90}
92inline constexpr std::uint8_t kDefaultMaxRetransmissions = 3U;
93
94} // namespace t1
95
100template <typename TransportT>
102public:
103 explicit T1Session(TransportT& transport) noexcept : transport_(transport) {}
104
106 void SetInterFrameDelayMs(std::uint32_t ms) noexcept { inter_frame_delay_ms_ = ms; }
107
108 [[nodiscard]] std::uint32_t InterFrameDelayMs() const noexcept { return inter_frame_delay_ms_; }
109
111 void SetReadRetries(std::uint8_t retries) noexcept { max_read_retries_ = retries; }
112
113 [[nodiscard]] std::uint8_t ReadRetries() const noexcept { return max_read_retries_; }
114
116 void SetReadRetryDelayMs(std::uint32_t ms) noexcept { read_retry_delay_ms_ = ms; }
117
118 [[nodiscard]] std::uint32_t ReadRetryDelayMs() const noexcept { return read_retry_delay_ms_; }
119
121 void SetMaxWtxRequests(std::uint8_t max_wtx_requests) noexcept { max_wtx_requests_ = max_wtx_requests; }
122
123 [[nodiscard]] std::uint8_t MaxWtxRequests() const noexcept { return max_wtx_requests_; }
124
129 void SetIfsc(std::size_t ifsc) noexcept {
130 ifsc_ = std::min<std::size_t>(std::max<std::size_t>(ifsc, 1U), t1::kMaxInformationField);
131 }
132
133 [[nodiscard]] std::size_t Ifsc() const noexcept { return ifsc_; }
134
139 void SetMaxRetransmissions(std::uint8_t n) noexcept { max_retransmissions_ = n; }
140
141 [[nodiscard]] std::uint8_t MaxRetransmissions() const noexcept { return max_retransmissions_; }
142
143 TransportT& Transport() noexcept { return transport_; }
144 const TransportT& Transport() const noexcept { return transport_; }
145
150 [[nodiscard]] Error ChipWarmReset(std::uint32_t timeout_ms) noexcept {
151 const Error se = SendSBlock(t1::kPcbSWarmReset, timeout_ms);
152 if (se != Error::Ok) {
153 return se;
154 }
155 std::uint8_t raw[t1::kMaxRawBlockBytes]{};
156 std::size_t raw_len = 0;
157 const Error re = RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
159 return re;
160 }
161
168 [[nodiscard]] Error GetAnswerToReset(std::uint8_t* buf, std::size_t cap, std::size_t* len_out,
169 std::uint32_t timeout_ms) noexcept {
170 if (len_out == nullptr) {
172 }
173 *len_out = 0;
175 const Error se = SendSBlock(t1::kPcbSGetAtr, timeout_ms);
176 if (se != Error::Ok) {
177 return se;
178 }
179 std::uint8_t raw[t1::kMaxRawBlockBytes]{};
180 std::size_t raw_len = 0;
181 const Error re = RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
182 if (re != Error::Ok) {
183 return re;
184 }
185 if (raw_len < 5U) {
186 return Error::Protocol;
187 }
188 if (!t1::IsSBlock(raw[1])) {
189 return Error::Protocol;
190 }
191 const std::uint8_t ln = raw[2];
192 if (3U + static_cast<std::size_t>(ln) + 2U != raw_len) {
193 return Error::Protocol;
194 }
195 if (static_cast<std::size_t>(ln) > cap) {
197 }
198 if (ln > 0U) {
199 std::memcpy(buf, raw + 3U, ln);
200 }
201 *len_out = ln;
203 atr::Profile profile{};
204 if (atr::Parse(raw + 3U, ln, &profile) == Error::Ok && profile.ifsc != 0U) {
205 SetIfsc(profile.ifsc); /* honour the SE's block size for every later command */
206 }
207 return Error::Ok;
208 }
209
220 [[nodiscard]] Error RecoverAfterHostReset(std::uint32_t timeout_ms) noexcept {
221 if (!transport_.EnsureInitialized()) {
223 }
224 std::uint8_t raw[t1::kMaxRawBlockBytes]{};
225 std::size_t raw_len = 0;
226 /* Ok or Crc: a stale block was drained. Transport or Timeout: nothing was pending. */
227 (void)RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
229 const Error se = SendSBlock(t1::kPcbSResyncReq, timeout_ms);
230 if (se != Error::Ok) {
231 return se;
232 }
233 std::uint8_t wtx_count = 0;
234 for (int guard = 0; guard < 16; ++guard) {
235 const Error re = RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
236 if (re != Error::Ok) {
237 return re;
238 }
239 if (raw[0] != t1::kNadSeToHost) {
240 return Error::Protocol;
241 }
242 if (raw[1] == t1::kPcbSResyncResp) {
244 return Error::Ok;
245 }
246 if (raw[1] != t1::kPcbSWtxReq) {
247 return Error::Protocol;
248 }
249 const Error w = HandleSBlock(raw, raw_len, timeout_ms, &wtx_count);
250 if (w != Error::Ok) {
251 return w;
252 }
253 }
254 return Error::Protocol;
255 }
256
272 [[nodiscard]] Error ExchangeInformation(const std::uint8_t* cmd, std::size_t cmd_len, std::uint8_t* rsp,
273 std::size_t rsp_cap, std::size_t* rsp_len,
274 std::uint32_t timeout_ms) noexcept {
275 if (rsp_len == nullptr) {
277 }
278 *rsp_len = 0;
279 if (!transport_.EnsureInitialized()) {
281 }
282
283 std::uint8_t retransmissions = 0;
284 std::size_t off = 0;
285 while (off < cmd_len) {
286 const std::size_t chunk = std::min(cmd_len - off, ifsc_);
287 const bool more_chain = (off + chunk) < cmd_len;
288 const std::uint8_t pcb = t1::IBlockPcb(host_ns_, more_chain);
289 const Error w = SendRawBlock(pcb, cmd + off, static_cast<std::uint8_t>(chunk), timeout_ms);
290 if (w != Error::Ok) {
291 return w;
292 }
293 host_ns_ ^= 1U;
294 off += chunk;
295 if (more_chain) {
296 const Error rr = ExpectChainAck(timeout_ms, &retransmissions);
297 if (rr != Error::Ok) {
298 return rr;
299 }
300 }
301 }
302
303 std::size_t total_rx = 0;
304 std::uint8_t wtx_count = 0;
305 for (int guard = 0; guard < 64; ++guard) {
306 std::uint8_t raw[t1::kMaxRawBlockBytes]{};
307 std::size_t raw_len = 0;
308 const Error rb = RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
309 if (rb == Error::Crc) {
310 /* ISO/IEC 7816-3 11.6.3: ask for the block again with R(N(R) = expected, EDC error). */
311 if (++retransmissions > max_retransmissions_) {
312 return Error::Crc;
313 }
314 const Error n = SendRawBlock(t1::RBlockNackPcb(card_ns_, t1::kRBlockErrEdc), nullptr, 0U,
315 timeout_ms);
316 if (n != Error::Ok) {
317 return n;
318 }
319 continue;
320 }
321 if (rb != Error::Ok) {
322 return rb;
323 }
324 if (raw_len < 5U) {
325 return Error::Protocol;
326 }
327 if (raw[0] != t1::kNadSeToHost) {
328 return Error::Protocol;
329 }
330 if (t1::IsSBlock(raw[1])) {
331 const Error sb = HandleSBlock(raw, raw_len, timeout_ms, &wtx_count);
332 if (sb != Error::Ok) {
333 return sb;
334 }
335 continue;
336 }
337 if (t1::IsRBlock(raw[1])) {
338 /* The SE rejected our last I-block (N(R) = its N(S)): send it again. */
339 if (t1::RBlockNrFromPcb(raw[1]) != static_cast<std::uint8_t>(host_ns_ ^ 1U) ||
340 last_iblock_len_ == 0U) {
341 return Error::Protocol;
342 }
343 if (++retransmissions > max_retransmissions_) {
344 return Error::Protocol;
345 }
346 const Error rt = RetransmitLastIBlock(timeout_ms);
347 if (rt != Error::Ok) {
348 return rt;
349 }
350 continue;
351 }
352 const std::uint8_t seq = t1::IBlockSeqFromPcb(raw[1]);
353 if (seq != card_ns_) {
354 return Error::Sequence;
355 }
356 const std::uint8_t ln = raw[2];
357 if (3U + static_cast<std::size_t>(ln) + 2U != raw_len) {
358 return Error::Protocol;
359 }
360 if (total_rx + static_cast<std::size_t>(ln) > rsp_cap) {
362 }
363 if (ln > 0U) {
364 std::memcpy(rsp + total_rx, raw + 3U, ln);
365 total_rx += ln;
366 }
367 card_ns_ ^= 1U;
368 if (!t1::IBlockMore(raw[1])) {
369 *rsp_len = total_rx;
370 return Error::Ok;
371 }
372 const Error ack = SendRBlockAck(t1::RBlockAckPcb(card_ns_), timeout_ms);
373 if (ack != Error::Ok) {
374 return ack;
375 }
376 }
377 return Error::Protocol;
378 }
379
381 void ResetSequenceState() noexcept {
382 host_ns_ = 0;
383 card_ns_ = 0;
384 }
385
386private:
387 [[nodiscard]] Error SendSBlock(std::uint8_t pcb, std::uint32_t timeout_ms) noexcept {
388 if (!transport_.EnsureInitialized()) {
390 }
391 return SendRawBlock(pcb, nullptr, 0, timeout_ms);
392 }
393
394 [[nodiscard]] Error SendRawBlock(std::uint8_t pcb, const std::uint8_t* inf, std::uint8_t inf_len,
395 std::uint32_t timeout_ms) noexcept {
396 if (static_cast<std::size_t>(inf_len) > t1::kMaxInformationField) {
398 }
399 std::uint8_t frame[t1::kMaxRawBlockBytes]{};
400 frame[0] = t1::kNadHostToSe;
401 frame[1] = pcb;
402 frame[2] = inf_len;
403 if (inf_len > 0 && inf != nullptr) {
404 std::memcpy(frame + 3U, inf, inf_len);
405 }
406 crc::AppendEdc(frame, 3U + inf_len);
407 if (t1::IsIBlock(pcb)) {
408 std::memcpy(last_iblock_, frame, 3U + inf_len + 2U);
409 last_iblock_len_ = 3U + inf_len + 2U;
410 }
411 const Error e = transport_.Write(frame, 3U + inf_len + 2U, timeout_ms);
412 if (e != Error::Ok) {
413 return e;
414 }
415 transport_.delay_ms(inter_frame_delay_ms_);
416 return Error::Ok;
417 }
418
419 [[nodiscard]] Error SendRBlockAck(std::uint8_t pcb, std::uint32_t timeout_ms) noexcept {
420 return SendRawBlock(pcb, nullptr, 0, timeout_ms);
421 }
422
423 [[nodiscard]] Error RecvT1Block(std::uint8_t* out, std::size_t cap, std::size_t* total_len,
424 std::uint32_t timeout_ms) noexcept {
425 if (cap < 5U) {
427 }
428 Error e = ReadWithRetry(out, 3U, timeout_ms);
429 if (e != Error::Ok) {
430 return e;
431 }
432 const std::uint8_t ln = out[2];
433 if (3U + static_cast<std::size_t>(ln) + 2U > cap) {
435 }
436 if (ln + 2U > 0U) {
437 e = ReadWithRetry(out + 3U, ln + 2U, timeout_ms);
438 if (e != Error::Ok) {
439 return e;
440 }
441 }
442 const std::size_t tot = 3U + ln + 2U;
443 if (!crc::VerifyFrameCrc(out, tot)) {
444 return Error::Crc;
445 }
446 *total_len = tot;
447 return Error::Ok;
448 }
449
450 [[nodiscard]] Error RetransmitLastIBlock(std::uint32_t timeout_ms) noexcept {
451 const Error e = transport_.Write(last_iblock_, last_iblock_len_, timeout_ms);
452 if (e != Error::Ok) {
453 return e;
454 }
455 transport_.delay_ms(inter_frame_delay_ms_);
456 return Error::Ok;
457 }
458
464 [[nodiscard]] Error ExpectChainAck(std::uint32_t timeout_ms, std::uint8_t* retransmissions) noexcept {
465 std::uint8_t wtx_count = 0;
466 for (int guard = 0; guard < 16; ++guard) {
467 std::uint8_t raw[t1::kMaxRawBlockBytes]{};
468 std::size_t raw_len = 0;
469 const Error e = RecvT1Block(raw, sizeof(raw), &raw_len, timeout_ms);
470 if (e == Error::Crc) {
471 if (++(*retransmissions) > max_retransmissions_) {
472 return Error::Crc;
473 }
474 const Error n = SendRawBlock(t1::RBlockNackPcb(card_ns_, t1::kRBlockErrEdc), nullptr, 0U,
475 timeout_ms);
476 if (n != Error::Ok) {
477 return n;
478 }
479 continue;
480 }
481 if (e != Error::Ok) {
482 return e;
483 }
484 if (raw_len < 5U || raw[0] != t1::kNadSeToHost) {
485 return Error::Protocol;
486 }
487 if (t1::IsSBlock(raw[1])) {
488 const Error sb = HandleSBlock(raw, raw_len, timeout_ms, &wtx_count);
489 if (sb != Error::Ok) {
490 return sb;
491 }
492 continue;
493 }
494 if (!t1::IsRBlock(raw[1])) {
495 return Error::Protocol;
496 }
497 if (t1::RBlockNrFromPcb(raw[1]) == host_ns_) {
498 return Error::Ok; /* acknowledged: the SE expects the next N(S) */
499 }
500 if (++(*retransmissions) > max_retransmissions_) {
501 return Error::Protocol;
502 }
503 const Error rt = RetransmitLastIBlock(timeout_ms);
504 if (rt != Error::Ok) {
505 return rt;
506 }
507 }
508 return Error::Protocol;
509 }
510
511 [[nodiscard]] static constexpr bool IsRetryableReadError(Error e) noexcept {
512 return e == Error::Transport || e == Error::Timeout;
513 }
514
515 [[nodiscard]] Error ReadWithRetry(std::uint8_t* rx, std::size_t rx_len, std::uint32_t timeout_ms) noexcept {
516 for (std::uint8_t attempt = 0; attempt <= max_read_retries_; ++attempt) {
517 const Error e = transport_.Read(rx, rx_len, timeout_ms);
518 if (e == Error::Ok) {
519 return Error::Ok;
520 }
521 if (!IsRetryableReadError(e) || attempt == max_read_retries_) {
522 return e;
523 }
524 transport_.delay_ms(read_retry_delay_ms_);
525 }
526 return Error::Transport;
527 }
528
529 [[nodiscard]] Error HandleSBlock(const std::uint8_t* raw, std::size_t raw_len, std::uint32_t timeout_ms,
530 std::uint8_t* wtx_count) noexcept {
531 if (raw == nullptr || raw_len < 5U) {
532 return Error::Protocol;
533 }
534 const std::uint8_t ln = raw[2];
535 if (3U + static_cast<std::size_t>(ln) + 2U != raw_len) {
536 return Error::Protocol;
537 }
538 if (raw[1] == t1::kPcbSWtxReq) {
539 if (wtx_count == nullptr || *wtx_count >= max_wtx_requests_) {
540 return Error::Protocol;
541 }
542 ++(*wtx_count);
543 return SendRawBlock(t1::kPcbSWtxResp, (ln > 0U) ? (raw + 3U) : nullptr, ln, timeout_ms);
544 }
545 if (raw[1] == t1::kPcbSResyncReq) {
547 return SendRawBlock(t1::kPcbSResyncResp, nullptr, 0U, timeout_ms);
548 }
549 return Error::Protocol;
550 }
551
552 TransportT& transport_;
553 std::uint32_t inter_frame_delay_ms_{2};
554 std::uint8_t max_read_retries_{6};
555 std::uint32_t read_retry_delay_ms_{2};
556 std::uint8_t max_wtx_requests_{8};
557 std::uint8_t host_ns_{0};
558 std::uint8_t card_ns_{0};
559 std::size_t ifsc_{t1::kMaxInformationField};
560 std::uint8_t max_retransmissions_{t1::kDefaultMaxRetransmissions};
561 std::uint8_t last_iblock_[t1::kMaxRawBlockBytes]{};
562 std::size_t last_iblock_len_{0};
563};
564
565} // namespace se050
Stateful T=1 session bound to a concrete I²C transport.
Definition se050_t1_session.hpp:101
Error ExchangeInformation(const std::uint8_t *cmd, std::size_t cmd_len, std::uint8_t *rsp, std::size_t rsp_cap, std::size_t *rsp_len, std::uint32_t timeout_ms) noexcept
Exchange a raw information field payload (APDU bytes) with the SE using I-blocks.
Definition se050_t1_session.hpp:272
std::uint8_t MaxRetransmissions() const noexcept
Definition se050_t1_session.hpp:141
void ResetSequenceState() noexcept
Reset sequence counters (call after electrical / protocol reset).
Definition se050_t1_session.hpp:381
void SetMaxRetransmissions(std::uint8_t n) noexcept
How many times one block is requested or sent again within an exchange before it fails (ISO/IEC 7816-...
Definition se050_t1_session.hpp:139
void SetReadRetryDelayMs(std::uint32_t ms) noexcept
Delay between retryable read attempts (transport polling interval).
Definition se050_t1_session.hpp:116
std::uint8_t MaxWtxRequests() const noexcept
Definition se050_t1_session.hpp:123
T1Session(TransportT &transport) noexcept
Definition se050_t1_session.hpp:103
std::uint32_t ReadRetryDelayMs() const noexcept
Definition se050_t1_session.hpp:118
void SetIfsc(std::size_t ifsc) noexcept
Information field size of the SE (IFSC): the largest INF the host puts in one I-block.
Definition se050_t1_session.hpp:129
std::uint8_t ReadRetries() const noexcept
Definition se050_t1_session.hpp:113
std::size_t Ifsc() const noexcept
Definition se050_t1_session.hpp:133
const TransportT & Transport() const noexcept
Definition se050_t1_session.hpp:144
TransportT & Transport() noexcept
Definition se050_t1_session.hpp:143
void SetInterFrameDelayMs(std::uint32_t ms) noexcept
Delay between a completed Write and the first Read of the response.
Definition se050_t1_session.hpp:106
std::uint32_t InterFrameDelayMs() const noexcept
Definition se050_t1_session.hpp:108
void SetMaxWtxRequests(std::uint8_t max_wtx_requests) noexcept
Upper bound of tolerated WTX request/response cycles within a single exchange.
Definition se050_t1_session.hpp:121
Error RecoverAfterHostReset(std::uint32_t timeout_ms) noexcept
Start-up sequence for SE050 erratum I2C.1, then resynchronise the block numbers.
Definition se050_t1_session.hpp:220
Error GetAnswerToReset(std::uint8_t *buf, std::size_t cap, std::size_t *len_out, std::uint32_t timeout_ms) noexcept
Retrieve the SE050 T=1oI2C profile / ATR-like byte string (S-block GET ATR).
Definition se050_t1_session.hpp:168
Error ChipWarmReset(std::uint32_t timeout_ms) noexcept
Send an S-block warm-reset style request (PCB = t1::kPcbSWarmReset, empty INF).
Definition se050_t1_session.hpp:150
void SetReadRetries(std::uint8_t retries) noexcept
Number of retry attempts for retryable I²C read errors while waiting response blocks.
Definition se050_t1_session.hpp:111
Error Parse(const std::uint8_t *inf, std::size_t inf_len, Profile *out) noexcept
Definition se050_atr.hpp:31
bool VerifyFrameCrc(const std::uint8_t *frame, std::size_t total_len) noexcept
Verify EDC on a full received frame (includes trailing 2-byte CRC).
Definition se050_crc.hpp:52
void AppendEdc(std::uint8_t *frame, std::size_t len_without_edc) noexcept
Append EDC immediately after frame[0 .. len_without_edc-1].
Definition se050_crc.hpp:45
constexpr std::uint8_t kPcbSWtxResp
Definition se050_t1_session.hpp:56
constexpr bool IsSBlock(std::uint8_t pcb) noexcept
Definition se050_t1_session.hpp:64
constexpr std::uint8_t kPcbSResyncResp
Definition se050_t1_session.hpp:53
constexpr bool IsIBlock(std::uint8_t pcb) noexcept
Definition se050_t1_session.hpp:58
constexpr bool IBlockMore(std::uint8_t pcb) noexcept
Definition se050_t1_session.hpp:67
constexpr std::uint8_t kPcbSWtxReq
S-block request/response pair for waiting-time extension.
Definition se050_t1_session.hpp:55
constexpr std::uint8_t RBlockNrFromPcb(std::uint8_t pcb) noexcept
N(R) of an R-block: the sequence number of the I-block its sender expects next.
Definition se050_t1_session.hpp:80
constexpr std::size_t kMaxInformationField
Maximum information field size per block (ISO 7816-3 typical upper bound).
Definition se050_t1_session.hpp:43
constexpr std::uint8_t kPcbSGetAtr
S-block PCB used by NXP stacks for GET ATR / card profile read (LEN = 0 INF).
Definition se050_t1_session.hpp:50
constexpr std::uint8_t kPcbSResyncReq
S-block request/response pair for resynchronization.
Definition se050_t1_session.hpp:52
constexpr std::uint8_t kNadHostToSe
NAD value used by the host for command blocks.
Definition se050_t1_session.hpp:39
constexpr std::uint8_t kDefaultMaxRetransmissions
Default number of times one block is sent again before an exchange fails.
Definition se050_t1_session.hpp:92
constexpr std::uint8_t kRBlockErrOther
R-block error code: other error (ISO/IEC 7816-3 11.4.3).
Definition se050_t1_session.hpp:86
constexpr std::size_t kMaxRawBlockBytes
Raw block buffer high water: prologue + INF + EDC.
Definition se050_t1_session.hpp:45
constexpr bool IsRBlock(std::uint8_t pcb) noexcept
Definition se050_t1_session.hpp:61
constexpr std::uint8_t RBlockNackPcb(std::uint8_t nr_bit, std::uint8_t err) noexcept
R-block asking for the block with sequence number nr again, with error code err.
Definition se050_t1_session.hpp:88
constexpr std::uint8_t RBlockAckPcb(std::uint8_t nr_bit) noexcept
Definition se050_t1_session.hpp:73
constexpr std::uint8_t IBlockSeqFromPcb(std::uint8_t pcb) noexcept
Definition se050_t1_session.hpp:76
constexpr std::uint8_t kPcbSWarmReset
S-block PCB used by NXP stacks for a 7816-style warm reset request (LEN = 0 INF).
Definition se050_t1_session.hpp:48
constexpr std::uint8_t kNadSeToHost
NAD value returned by the SE in response blocks.
Definition se050_t1_session.hpp:41
constexpr std::uint8_t IBlockPcb(std::uint8_t ns_bit, bool more) noexcept
Definition se050_t1_session.hpp:70
constexpr std::uint8_t kRBlockErrEdc
R-block error code: EDC error (ISO/IEC 7816-3 11.4.3).
Definition se050_t1_session.hpp:84
Definition se050_apdu.hpp:15
Error
Definition se050_types.hpp:14
Parser for SE050 T=1oI2C ATR/profile INF payload.
ISO/IEC 7816-3 T=1 EDC (16-bit CRC) for NXP SE050 T1oI2C blocks.
Shared types, limits, and error codes for the HF-SE050 driver.
Definition se050_atr.hpp:16