MX 1 yıl önce
ebeveyn
işleme
e58f5ef812

+ 1 - 1
application.fam

@@ -18,7 +18,7 @@ App(
     ],
     ],
     fap_icon="icons/logo.png",
     fap_icon="icons/logo.png",
     fap_category="NFC",
     fap_category="NFC",
-    fap_version="2.9",
+    fap_version="2.10",
     fap_author="bettse",
     fap_author="bettse",
 #    fap_extbuild=(
 #    fap_extbuild=(
 #        ExtFile(
 #        ExtFile(

+ 17 - 17
assembly.h

@@ -27,8 +27,8 @@
 #endif
 #endif
 
 
 #if defined(__APPLE__)
 #if defined(__APPLE__)
-#define HIDDEN(name) .private_extern name
-#define LOCAL_LABEL(name) L_##name
+#define HIDDEN(name)         .private_extern name
+#define LOCAL_LABEL(name)    L_##name
 // tell linker it can break up file at label boundaries
 // tell linker it can break up file at label boundaries
 #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
 #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
 #define SYMBOL_IS_FUNC(name)
 #define SYMBOL_IS_FUNC(name)
@@ -38,7 +38,7 @@
 
 
 #elif defined(__ELF__)
 #elif defined(__ELF__)
 
 
-#define HIDDEN(name) .hidden name
+#define HIDDEN(name)      .hidden name
 #define LOCAL_LABEL(name) .L_##name
 #define LOCAL_LABEL(name) .L_##name
 #define FILE_LEVEL_DIRECTIVE
 #define FILE_LEVEL_DIRECTIVE
 #if defined(__arm__) || defined(__aarch64__)
 #if defined(__arm__) || defined(__aarch64__)
@@ -60,7 +60,7 @@
 #define LOCAL_LABEL(name) .L##name
 #define LOCAL_LABEL(name) .L##name
 #define FILE_LEVEL_DIRECTIVE
 #define FILE_LEVEL_DIRECTIVE
 #define SYMBOL_IS_FUNC(name) .def name SEPARATOR.scl 2 SEPARATOR.type 32 SEPARATOR.endef
 #define SYMBOL_IS_FUNC(name) .def name SEPARATOR.scl 2 SEPARATOR.type 32 SEPARATOR.endef
-#define CONST_SECTION .section.rdata, "rd"
+#define CONST_SECTION        .section.rdata, "rd"
 
 
 #define NO_EXEC_STACK_DIRECTIVE
 #define NO_EXEC_STACK_DIRECTIVE
 
 
@@ -73,7 +73,7 @@
 #endif
 #endif
 
 
 // BTI and PAC gnu property note
 // BTI and PAC gnu property note
-#define NT_GNU_PROPERTY_TYPE_0 5
+#define NT_GNU_PROPERTY_TYPE_0             5
 #define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
 #define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
 #define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
 #define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
 #define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
 #define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
@@ -112,7 +112,7 @@
 
 
 #if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
 #if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
 #define CFI_START .cfi_startproc
 #define CFI_START .cfi_startproc
-#define CFI_END .cfi_endproc
+#define CFI_END   .cfi_endproc
 #else
 #else
 #define CFI_START
 #define CFI_START
 #define CFI_END
 #define CFI_END
@@ -124,11 +124,11 @@
 // - for '-mthumb -march=armv6' compiler defines '__thumb__'
 // - for '-mthumb -march=armv6' compiler defines '__thumb__'
 // - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
 // - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
 #if defined(__thumb2__) || defined(__thumb__)
 #if defined(__thumb2__) || defined(__thumb__)
-#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DEFINE_CODE_STATE     .thumb SEPARATOR
 #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
 #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
 #if defined(__thumb2__)
 #if defined(__thumb2__)
 #define USE_THUMB_2
 #define USE_THUMB_2
-#define IT(cond) it cond
+#define IT(cond)  it cond
 #define ITT(cond) itt cond
 #define ITT(cond) itt cond
 #define ITE(cond) ite cond
 #define ITE(cond) ite cond
 #else
 #else
@@ -158,10 +158,10 @@
 #endif
 #endif
 
 
 #ifdef ARM_HAS_BX
 #ifdef ARM_HAS_BX
-#define JMP(r) bx r
+#define JMP(r)     bx r
 #define JMPc(r, c) bx##c r
 #define JMPc(r, c) bx##c r
 #else
 #else
-#define JMP(r) mov pc, r
+#define JMP(r)     mov pc, r
 #define JMPc(r, c) mov##c pc, r
 #define JMPc(r, c) mov##c pc, r
 #endif
 #endif
 
 
@@ -187,18 +187,18 @@
 #define DEFINE_CODE_STATE
 #define DEFINE_CODE_STATE
 #endif
 #endif
 
 
-#define GLUE2_(a, b) a##b
-#define GLUE(a, b) GLUE2_(a, b)
-#define GLUE2(a, b) GLUE2_(a, b)
-#define GLUE3_(a, b, c) a##b##c
-#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE2_(a, b)       a##b
+#define GLUE(a, b)         GLUE2_(a, b)
+#define GLUE2(a, b)        GLUE2_(a, b)
+#define GLUE3_(a, b, c)    a##b##c
+#define GLUE3(a, b, c)     GLUE3_(a, b, c)
 #define GLUE4_(a, b, c, d) a##b##c##d
 #define GLUE4_(a, b, c, d) a##b##c##d
-#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+#define GLUE4(a, b, c, d)  GLUE4_(a, b, c, d)
 
 
 #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
 #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
 
 
 #ifdef VISIBILITY_HIDDEN
 #ifdef VISIBILITY_HIDDEN
-#define DECLARE_SYMBOL_VISIBILITY(name) HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY(name)           HIDDEN(SYMBOL_NAME(name)) SEPARATOR
 #define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) HIDDEN(name) SEPARATOR
 #define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) HIDDEN(name) SEPARATOR
 #else
 #else
 #define DECLARE_SYMBOL_VISIBILITY(name)
 #define DECLARE_SYMBOL_VISIBILITY(name)

+ 75 - 46
ccid.c

@@ -19,24 +19,6 @@ uint8_t getSequence(uint8_t slot) {
     return sequence[slot]++;
     return sequence[slot]++;
 }
 }
 
 
-uint8_t seader_ccid_calc_lrc(uint8_t* data, size_t len) {
-    uint8_t lrc = 0;
-    for(size_t i = 0; i < len; i++) {
-        lrc ^= data[i];
-    }
-    return lrc;
-}
-
-bool seader_ccid_validate_lrc(uint8_t* data, size_t len) {
-    uint8_t lrc = seader_ccid_calc_lrc(data, len - 1);
-    return lrc == data[len - 1];
-}
-
-size_t seader_ccid_add_lrc(uint8_t* data, size_t len) {
-    data[len] = seader_ccid_calc_lrc(data, len);
-    return len + 1;
-}
-
 void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
 void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
     if(powered[slot]) {
     if(powered[slot]) {
         return;
         return;
@@ -53,7 +35,7 @@ void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 7] = 2; //power
     seader_uart->tx_buf[2 + 7] = 2; //power
 
 
-    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
 }
 
 
@@ -74,25 +56,51 @@ void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot) {
     seader_uart->tx_buf[2 + 5] = slot;
     seader_uart->tx_buf[2 + 5] = slot;
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
 
 
-    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
 }
 
 
-void seader_ccid_SetParameters(SeaderUartBridge* seader_uart) {
-    uint8_t T1 = 1;
+void seader_ccid_SetParameters(Seader* seader, uint8_t slot, uint8_t* atr, size_t atr_len) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+    UNUSED(atr_len);
+    FURI_LOG_D(TAG, "seader_ccid_SetParameters(%d)", slot);
+
+    uint8_t payloadLen = 0;
+    if(seader_uart->T == 0) {
+        payloadLen = 5;
+    } else if(atr[4] == 0xB1 && seader_uart->T == 1) {
+        payloadLen = 7;
+    }
     memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
     memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
     seader_uart->tx_buf[0] = SYNC;
     seader_uart->tx_buf[0] = SYNC;
     seader_uart->tx_buf[1] = CTRL;
     seader_uart->tx_buf[1] = CTRL;
     seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters;
     seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters;
-    seader_uart->tx_buf[2 + 1] = 0;
-    seader_uart->tx_buf[2 + 5] = sam_slot;
-    seader_uart->tx_buf[2 + 6] = getSequence(sam_slot);
-    seader_uart->tx_buf[2 + 7] = T1;
+    seader_uart->tx_buf[2 + 1] = payloadLen;
+    seader_uart->tx_buf[2 + 5] = slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(slot);
+    seader_uart->tx_buf[2 + 7] = seader_uart->T;
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
 
 
-    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    if(seader_uart->T == 0) {
+        // I'm leaving this here for completeness, but it was actually causing ICC_MUTE on the first apdu.
+        seader_uart->tx_buf[2 + 10] = 0x96; //atr[2]; //bmFindexDindex
+        seader_uart->tx_buf[2 + 11] = 0x00; //bmTCCKST1
+        seader_uart->tx_buf[2 + 12] = 0x00; //bGuardTimeT0
+        seader_uart->tx_buf[2 + 13] = 0x0a; //bWaitingIntegerT0
+        seader_uart->tx_buf[2 + 14] = 0x00; //bClockStop
+    } else if(seader_uart->T == 1) {
+        seader_uart->tx_buf[2 + 10] = atr[2]; //bmFindexDindex
+        seader_uart->tx_buf[2 + 11] = 0x10; //bmTCCKST1
+        seader_uart->tx_buf[2 + 12] = 0xfe; //bGuardTimeT1
+        seader_uart->tx_buf[2 + 13] = atr[6]; //bWaitingIntegerT1
+        seader_uart->tx_buf[2 + 14] = atr[8]; //bClockStop
+        seader_uart->tx_buf[2 + 15] = atr[5]; //bIFSC
+        seader_uart->tx_buf[2 + 16] = 0x00; //bNadValue
+    }
 
 
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10 + payloadLen);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
 }
 
 
@@ -108,7 +116,7 @@ void seader_ccid_GetParameters(SeaderUartBridge* seader_uart) {
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
 
 
-    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
 
 
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
 }
@@ -126,16 +134,24 @@ void seader_ccid_XfrBlockToSlot(
     seader_uart->tx_buf[0] = SYNC;
     seader_uart->tx_buf[0] = SYNC;
     seader_uart->tx_buf[1] = CTRL;
     seader_uart->tx_buf[1] = CTRL;
     seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
     seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
-    seader_uart->tx_buf[2 + 1] = len;
+    seader_uart->tx_buf[2 + 1] = (len >> 0) & 0xff;
+    seader_uart->tx_buf[2 + 2] = (len >> 8) & 0xff;
     seader_uart->tx_buf[2 + 5] = slot;
     seader_uart->tx_buf[2 + 5] = slot;
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 7] = 5;
     seader_uart->tx_buf[2 + 7] = 5;
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 8] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
     seader_uart->tx_buf[2 + 9] = 0;
 
 
-    memcpy(seader_uart->tx_buf + 2 + 10, data, len);
-    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10 + len);
-    // FURI_LOG_I(TAG, "seader_ccid_XfrBlock %d bytes", seader_uart->tx_len);
+    uint8_t header_len = 2 + 10;
+    memcpy(seader_uart->tx_buf + header_len, data, len);
+    seader_uart->tx_len = header_len + len;
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, seader_uart->tx_len);
+
+    char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
+    for(uint8_t i = 0; i < seader_uart->tx_len; i++) {
+        snprintf(display + (i * 2), sizeof(display), "%02x", seader_uart->tx_buf[i]);
+    }
+    FURI_LOG_D(TAG, "seader_ccid_XfrBlockToSlot(%d) %d: %s", slot, seader_uart->tx_len, display);
 
 
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
 }
@@ -248,12 +264,12 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
         }
         }
         message.consumed += 2 + 10 + message.dwLength + 1;
         message.consumed += 2 + 10 + message.dwLength + 1;
 
 
-        if(seader_ccid_validate_lrc(cmd, 2 + 10 + message.dwLength + 1) == false) {
+        if(seader_validate_lrc(cmd, 2 + 10 + message.dwLength + 1) == false) {
             FURI_LOG_W(
             FURI_LOG_W(
                 TAG,
                 TAG,
                 "Invalid LRC.  Recv: %02x vs Calc: %02x",
                 "Invalid LRC.  Recv: %02x vs Calc: %02x",
                 cmd[2 + 10 + message.dwLength + 1],
                 cmd[2 + 10 + message.dwLength + 1],
-                seader_ccid_calc_lrc(cmd, 2 + 10 + message.dwLength));
+                seader_calc_lrc(cmd, 2 + 10 + message.dwLength));
             // TODO: Should I respond with an error?
             // TODO: Should I respond with an error?
             return message.consumed;
             return message.consumed;
         }
         }
@@ -326,10 +342,25 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
             return message.consumed;
             return message.consumed;
         }
         }
 
 
-        if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock) {
+        if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_Parameters) {
+            FURI_LOG_D(TAG, "Got Parameters");
+            if(seader_uart->T == 1) {
+                seader_t_1_set_IFSD(seader);
+            } else {
+                seader_worker_send_version(seader);
+                if(seader_worker->callback) {
+                    seader_worker->callback(SeaderWorkerEventSamPresent, seader_worker->context);
+                }
+            }
+        } else if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock) {
             if(hasSAM) {
             if(hasSAM) {
                 if(message.bSlot == sam_slot) {
                 if(message.bSlot == sam_slot) {
-                    seader_worker_process_sam_message(seader, &message);
+                    if(seader_uart->T == 0) {
+                        seader_worker_process_sam_message(
+                            seader, message.payload, message.dwLength);
+                    } else if(seader_uart->T == 1) {
+                        seader_recv_t1(seader, &message);
+                    }
                 } else {
                 } else {
                     FURI_LOG_D(TAG, "Discarding message on non-sam slot");
                     FURI_LOG_D(TAG, "Discarding message on non-sam slot");
                 }
                 }
@@ -338,20 +369,18 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
                     FURI_LOG_I(TAG, "SAM ATR!");
                     FURI_LOG_I(TAG, "SAM ATR!");
                     hasSAM = true;
                     hasSAM = true;
                     sam_slot = message.bSlot;
                     sam_slot = message.bSlot;
-                    seader_worker_send_version(seader);
-                    if(seader_worker->callback) {
-                        seader_worker->callback(
-                            SeaderWorkerEventSamPresent, seader_worker->context);
+                    if(seader_uart->T == 0) {
+                        seader_ccid_GetParameters(seader_uart);
+                    } else if(seader_uart->T == 1) {
+                        seader_ccid_SetParameters(
+                            seader, sam_slot, message.payload, message.dwLength);
                     }
                     }
                 } else if(memcmp(SAM_ATR2, message.payload, sizeof(SAM_ATR2)) == 0) {
                 } else if(memcmp(SAM_ATR2, message.payload, sizeof(SAM_ATR2)) == 0) {
                     FURI_LOG_I(TAG, "SAM ATR2!");
                     FURI_LOG_I(TAG, "SAM ATR2!");
                     hasSAM = true;
                     hasSAM = true;
                     sam_slot = message.bSlot;
                     sam_slot = message.bSlot;
-                    seader_worker_send_version(seader);
-                    if(seader_worker->callback) {
-                        seader_worker->callback(
-                            SeaderWorkerEventSamPresent, seader_worker->context);
-                    }
+                    // I don't have an ATR2 to test with
+                    seader_ccid_GetParameters(seader_uart);
                 } else {
                 } else {
                     FURI_LOG_W(TAG, "Unknown ATR");
                     FURI_LOG_W(TAG, "Unknown ATR");
                     if(seader_worker->callback) {
                     if(seader_worker->callback) {
@@ -360,7 +389,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
                 }
                 }
             }
             }
         } else {
         } else {
-            FURI_LOG_W(TAG, "Unhandled CCID message type %d", message.bMessageType);
+            FURI_LOG_W(TAG, "Unhandled CCID message type %02x", message.bMessageType);
         }
         }
     }
     }
 
 

+ 31 - 27
ccid.h

@@ -11,7 +11,7 @@
 
 
 #define SYNC (0x03)
 #define SYNC (0x03)
 #define CTRL (0x06)
 #define CTRL (0x06)
-#define NAK (0x15)
+#define NAK  (0x15)
 
 
 #define BMICCSTATUS_MASK 0x03
 #define BMICCSTATUS_MASK 0x03
 /*
 /*
@@ -23,48 +23,52 @@
 
 
 // TODO: rename/renumber
 // TODO: rename/renumber
 #define SLOT_0_MASK 0x03
 #define SLOT_0_MASK 0x03
-#define CARD_OUT_1 0x02
-#define CARD_IN_1 0x03
+#define CARD_OUT_1  0x02
+#define CARD_IN_1   0x03
 #define SLOT_1_MASK 0x0C
 #define SLOT_1_MASK 0x0C
-#define CARD_IN_2 0x04
-#define CARD_OUT_2 0x0C
+#define CARD_IN_2   0x04
+#define CARD_OUT_2  0x0C
 
 
 /*
 /*
  *  * BULK_OUT messages from PC to Reader
  *  * BULK_OUT messages from PC to Reader
  *   * Defined in CCID Rev 1.1 6.1 (page 26)
  *   * Defined in CCID Rev 1.1 6.1 (page 26)
  *    */
  *    */
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65
-#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f
-#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c
-#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d
-#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b
-#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e
-#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71
-#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn                   0x62
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff                  0x63
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus                0x65
+#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                     0x6f
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters                0x6c
+#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters              0x6d
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters                0x61
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                       0x6b
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                     0x6e
+#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                       0x6a
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                       0x69
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical                   0x71
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                        0x72
 #define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
 #define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
 /*
 /*
  *  * BULK_IN messages from Reader to PC
  *  * BULK_IN messages from Reader to PC
  *   * Defined in CCID Rev 1.1 6.2 (page 48)
  *   * Defined in CCID Rev 1.1 6.2 (page 48)
  *    */
  *    */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80
-#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82
-#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83
-#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock                    0x80
+#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus                   0x81
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters                   0x82
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                       0x83
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency    0x84
 /*
 /*
  *  * INTERRUPT_IN messages from Reader to PC
  *  * INTERRUPT_IN messages from Reader to PC
  *   * Defined in CCID Rev 1.1 6.3 (page 56)
  *   * Defined in CCID Rev 1.1 6.3 (page 56)
  *    */
  *    */
-#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50
-#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51
+#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange             0x50
+#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError                0x51
 
 
 /* Status codes that go in bStatus (see 6.2.6) */
 /* Status codes that go in bStatus (see 6.2.6) */
-enum { ICC_STATUS_PRESENT_ACTIVE = 0, ICC_STATUS_PRESENT_INACTIVE, ICC_STATUS_NOT_PRESENT };
+enum {
+    ICC_STATUS_PRESENT_ACTIVE = 0,
+    ICC_STATUS_PRESENT_INACTIVE,
+    ICC_STATUS_NOT_PRESENT
+};
 enum {
 enum {
     COMMAND_STATUS_NO_ERROR = 0,
     COMMAND_STATUS_NO_ERROR = 0,
     COMMAND_STATUS_FAILED,
     COMMAND_STATUS_FAILED,
@@ -95,7 +99,7 @@ struct CCID_Message {
 void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart);
 void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart);
 void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot);
 void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot);
 void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot);
 void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot);
-void seader_ccid_SetParameters(SeaderUartBridge* seader_uart);
+void seader_ccid_SetParameters(Seader* seader, uint8_t slot, uint8_t* atr, size_t atr_len);
 void seader_ccid_GetParameters(SeaderUartBridge* seader_uart);
 void seader_ccid_GetParameters(SeaderUartBridge* seader_uart);
 void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len);
 void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len);
 void seader_ccid_XfrBlockToSlot(
 void seader_ccid_XfrBlockToSlot(

BIN
fake_screenshot.pxd


+ 19 - 0
lrc.c

@@ -0,0 +1,19 @@
+#include "lrc.h"
+
+uint8_t seader_calc_lrc(uint8_t* data, size_t len) {
+    uint8_t lrc = 0;
+    for(size_t i = 0; i < len; i++) {
+        lrc ^= data[i];
+    }
+    return lrc;
+}
+
+bool seader_validate_lrc(uint8_t* data, size_t len) {
+    uint8_t lrc = seader_calc_lrc(data, len - 1);
+    return lrc == data[len - 1];
+}
+
+size_t seader_add_lrc(uint8_t* data, size_t len) {
+    data[len] = seader_calc_lrc(data, len);
+    return len + 1;
+}

+ 9 - 0
lrc.h

@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+uint8_t seader_calc_lrc(uint8_t* data, size_t len);
+bool seader_validate_lrc(uint8_t* data, size_t len);
+size_t seader_add_lrc(uint8_t* data, size_t len);

+ 1 - 1
protocol/picopass_poller_i.h

@@ -7,7 +7,7 @@
 #include <nfc/helpers/iso13239_crc.h>
 #include <nfc/helpers/iso13239_crc.h>
 
 
 #define PICOPASS_POLLER_BUFFER_SIZE (255)
 #define PICOPASS_POLLER_BUFFER_SIZE (255)
-#define PICOPASS_CRC_SIZE (2)
+#define PICOPASS_CRC_SIZE           (2)
 
 
 typedef enum {
 typedef enum {
     PicopassPollerSessionStateIdle,
     PicopassPollerSessionStateIdle,

+ 15 - 15
protocol/picopass_protocol.h

@@ -1,22 +1,22 @@
 #pragma once
 #pragma once
 
 
-#define PICOPASS_BLOCK_LEN 8
-#define PICOPASS_MAX_APP_LIMIT 32
-#define PICOPASS_UID_LEN 8
+#define PICOPASS_BLOCK_LEN           8
+#define PICOPASS_MAX_APP_LIMIT       32
+#define PICOPASS_UID_LEN             8
 #define PICOPASS_READ_CHECK_RESP_LEN 8
 #define PICOPASS_READ_CHECK_RESP_LEN 8
-#define PICOPASS_CHECK_RESP_LEN 4
-#define PICOPASS_MAC_LEN 4
-#define PICOPASS_KEY_LEN 8
-
-#define CSN_INDEX 0
-#define CFG_INDEX 1
-#define EPURSE_INDEX 2
-#define KD_INDEX 3
-#define KC_INDEX 4
-#define AIA_INDEX 5
+#define PICOPASS_CHECK_RESP_LEN      4
+#define PICOPASS_MAC_LEN             4
+#define PICOPASS_KEY_LEN             8
+
+#define CSN_INDEX      0
+#define CFG_INDEX      1
+#define EPURSE_INDEX   2
+#define KD_INDEX       3
+#define KC_INDEX       4
+#define AIA_INDEX      5
 #define PACS_CFG_INDEX 6
 #define PACS_CFG_INDEX 6
-#define PACS_INDEX 7
-#define SR_SIO_INDEX 10
+#define PACS_INDEX     7
+#define SR_SIO_INDEX   10
 
 
 #define PICOPASS_FDT_LISTEN_FC (1000)
 #define PICOPASS_FDT_LISTEN_FC (1000)
 
 

+ 1 - 1
protocol/rfal_picopass.h

@@ -3,7 +3,7 @@
 #include <furi_hal_nfc.h>
 #include <furi_hal_nfc.h>
 
 
 #define RFAL_PICOPASS_UID_LEN 8
 #define RFAL_PICOPASS_UID_LEN 8
-#define PICOPASS_BLOCK_LEN 8
+#define PICOPASS_BLOCK_LEN    8
 
 
 enum {
 enum {
     // PicoPass command bytes:
     // PicoPass command bytes:

+ 69 - 72
sam_api.c

@@ -6,11 +6,10 @@
 
 
 #define TAG "SAMAPI"
 #define TAG "SAMAPI"
 
 
-#define APDU_HEADER_LEN 5
-#define ASN1_PREFIX 6
-#define ASN1_DEBUG true
+#define ASN1_PREFIX                     6
+#define ASN1_DEBUG                      true
 #define SEADER_ICLASS_SR_SIO_BASE_BLOCK 10
 #define SEADER_ICLASS_SR_SIO_BASE_BLOCK 10
-#define SEADER_SERIAL_FILE_NAME "sam_serial"
+#define SEADER_SERIAL_FILE_NAME         "sam_serial"
 
 
 const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
 const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78};
 
 
@@ -34,7 +33,7 @@ void* calloc(size_t count, size_t size) {
 }
 }
 
 
 // Forward declarations
 // Forward declarations
-void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t len);
+void seader_send_nfc_rx(Seader* seader, uint8_t* buffer, size_t len);
 
 
 PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
 PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer* rx_buffer) {
     const uint8_t* buffer = bit_buffer_get_data(tx_buffer);
     const uint8_t* buffer = bit_buffer_get_data(tx_buffer);
@@ -56,9 +55,6 @@ PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer*
 }
 }
 
 
 void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len) {
 void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     bit_buffer_append_bytes(tx_buffer, buffer, len);
     bit_buffer_append_bytes(tx_buffer, buffer, len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
@@ -131,7 +127,7 @@ void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len)
         }
         }
 
 
         seader_send_nfc_rx(
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
             bit_buffer_get_size_bytes(rx_buffer));
 
 
@@ -140,16 +136,24 @@ void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len)
     bit_buffer_free(rx_buffer);
     bit_buffer_free(rx_buffer);
 }
 }
 
 
+uint8_t APDU_HEADER_LEN = 5;
 bool seader_send_apdu(
 bool seader_send_apdu(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     uint8_t CLA,
     uint8_t CLA,
     uint8_t INS,
     uint8_t INS,
     uint8_t P1,
     uint8_t P1,
     uint8_t P2,
     uint8_t P2,
     uint8_t* payload,
     uint8_t* payload,
-    uint8_t length) {
-    if(APDU_HEADER_LEN + length > SEADER_UART_RX_BUF_SIZE) {
-        FURI_LOG_E(TAG, "Cannot send message, too long: %d", APDU_HEADER_LEN + length);
+    uint8_t payloadLen) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+
+    if(seader_uart->T == 1) {
+        APDU_HEADER_LEN = 7;
+    }
+
+    if(APDU_HEADER_LEN + payloadLen > SEADER_UART_RX_BUF_SIZE) {
+        FURI_LOG_E(TAG, "Cannot send message, too long: %d", APDU_HEADER_LEN + payloadLen);
         return false;
         return false;
     }
     }
 
 
@@ -158,16 +162,30 @@ bool seader_send_apdu(
     apdu[1] = INS;
     apdu[1] = INS;
     apdu[2] = P1;
     apdu[2] = P1;
     apdu[3] = P2;
     apdu[3] = P2;
-    apdu[4] = length;
-    memcpy(apdu + APDU_HEADER_LEN, payload, length);
+
+    if(seader_uart->T == 1) {
+        apdu[4] = 0x00;
+        apdu[5] = 0x00;
+        apdu[6] = payloadLen;
+    } else {
+        apdu[4] = payloadLen;
+    }
+
+    memcpy(apdu + APDU_HEADER_LEN, payload, payloadLen);
+    uint8_t length = APDU_HEADER_LEN + payloadLen;
 
 
     memset(display, 0, sizeof(display));
     memset(display, 0, sizeof(display));
-    for(uint8_t i = 0; i < APDU_HEADER_LEN + length; i++) {
+    for(uint8_t i = 0; i < length; i++) {
         snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
         snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
     }
     }
     FURI_LOG_D(TAG, "seader_send_apdu %s", display);
     FURI_LOG_D(TAG, "seader_send_apdu %s", display);
 
 
-    seader_ccid_XfrBlock(seader_uart, apdu, APDU_HEADER_LEN + length);
+    if(seader_uart->T == 1) {
+        seader_send_t1(seader_uart, apdu, length);
+    } else {
+        seader_ccid_XfrBlock(seader_uart, apdu, length);
+    }
+
     return true;
     return true;
 }
 }
 
 
@@ -184,7 +202,7 @@ static int seader_print_struct_callback(const void* buffer, size_t size, void* a
 }
 }
 
 
 void seader_send_payload(
 void seader_send_payload(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     Payload_t* payload,
     Payload_t* payload,
     uint8_t to,
     uint8_t to,
     uint8_t from,
     uint8_t from,
@@ -214,11 +232,11 @@ void seader_send_payload(
     rBuffer[1] = from;
     rBuffer[1] = from;
     rBuffer[2] = replyTo;
     rBuffer[2] = replyTo;
 
 
-    seader_send_apdu(seader_uart, 0xA0, 0xDA, 0x02, 0x63, rBuffer, 6 + er.encoded);
+    seader_send_apdu(seader, 0xA0, 0xDA, 0x02, 0x63, rBuffer, 6 + er.encoded);
 }
 }
 
 
 void seader_send_response(
 void seader_send_response(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     Response_t* response,
     Response_t* response,
     uint8_t to,
     uint8_t to,
     uint8_t from,
     uint8_t from,
@@ -230,15 +248,12 @@ void seader_send_response(
     payload->present = Payload_PR_response;
     payload->present = Payload_PR_response;
     payload->choice.response = *response;
     payload->choice.response = *response;
 
 
-    seader_send_payload(seader_uart, payload, to, from, replyTo);
+    seader_send_payload(seader, payload, to, from, replyTo);
 
 
-    free(payload);
+    ASN_STRUCT_FREE(asn_DEF_Payload, payload);
 }
 }
 
 
 void seader_send_request_pacs(Seader* seader) {
 void seader_send_request_pacs(Seader* seader) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     RequestPacs_t* requestPacs = 0;
     RequestPacs_t* requestPacs = 0;
     requestPacs = calloc(1, sizeof *requestPacs);
     requestPacs = calloc(1, sizeof *requestPacs);
     assert(requestPacs);
     assert(requestPacs);
@@ -261,17 +276,14 @@ void seader_send_request_pacs(Seader* seader) {
     payload->present = Payload_PR_samCommand;
     payload->present = Payload_PR_samCommand;
     payload->choice.samCommand = *samCommand;
     payload->choice.samCommand = *samCommand;
 
 
-    seader_send_payload(seader_uart, payload, 0x44, 0x0a, 0x44);
+    seader_send_payload(seader, payload, 0x44, 0x0a, 0x44);
 
 
-    free(requestPacs);
-    free(samCommand);
-    free(payload);
+    ASN_STRUCT_FREE(asn_DEF_Payload, payload);
+    ASN_STRUCT_FREE(asn_DEF_SamCommand, samCommand);
+    ASN_STRUCT_FREE(asn_DEF_RequestPacs, requestPacs);
 }
 }
 
 
 void seader_worker_send_serial_number(Seader* seader) {
 void seader_worker_send_serial_number(Seader* seader) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     SamCommand_t* samCommand = 0;
     SamCommand_t* samCommand = 0;
     samCommand = calloc(1, sizeof *samCommand);
     samCommand = calloc(1, sizeof *samCommand);
     assert(samCommand);
     assert(samCommand);
@@ -286,16 +298,13 @@ void seader_worker_send_serial_number(Seader* seader) {
     payload->present = Payload_PR_samCommand;
     payload->present = Payload_PR_samCommand;
     payload->choice.samCommand = *samCommand;
     payload->choice.samCommand = *samCommand;
 
 
-    seader_send_payload(seader_uart, payload, 0x44, 0x0a, 0x44);
+    seader_send_payload(seader, payload, 0x44, 0x0a, 0x44);
 
 
-    free(samCommand);
-    free(payload);
+    ASN_STRUCT_FREE(asn_DEF_Payload, payload);
+    ASN_STRUCT_FREE(asn_DEF_SamCommand, samCommand);
 }
 }
 
 
 void seader_worker_send_version(Seader* seader) {
 void seader_worker_send_version(Seader* seader) {
-    SeaderWorker* seader_worker = seader->worker;
-
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     SamCommand_t* samCommand = 0;
     SamCommand_t* samCommand = 0;
     samCommand = calloc(1, sizeof *samCommand);
     samCommand = calloc(1, sizeof *samCommand);
     assert(samCommand);
     assert(samCommand);
@@ -310,15 +319,13 @@ void seader_worker_send_version(Seader* seader) {
     payload->present = Payload_PR_samCommand;
     payload->present = Payload_PR_samCommand;
     payload->choice.samCommand = *samCommand;
     payload->choice.samCommand = *samCommand;
 
 
-    seader_send_payload(seader_uart, payload, 0x44, 0x0a, 0x44);
+    seader_send_payload(seader, payload, 0x44, 0x0a, 0x44);
 
 
-    free(samCommand);
-    free(payload);
+    ASN_STRUCT_FREE(asn_DEF_Payload, payload);
+    ASN_STRUCT_FREE(asn_DEF_SamCommand, samCommand);
 }
 }
 
 
 void seader_send_card_detected(Seader* seader, CardDetails_t* cardDetails) {
 void seader_send_card_detected(Seader* seader, CardDetails_t* cardDetails) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     CardDetected_t* cardDetected = 0;
     CardDetected_t* cardDetected = 0;
     cardDetected = calloc(1, sizeof *cardDetected);
     cardDetected = calloc(1, sizeof *cardDetected);
     assert(cardDetected);
     assert(cardDetected);
@@ -340,11 +347,11 @@ void seader_send_card_detected(Seader* seader, CardDetails_t* cardDetails) {
     payload->present = Payload_PR_samCommand;
     payload->present = Payload_PR_samCommand;
     payload->choice.samCommand = *samCommand;
     payload->choice.samCommand = *samCommand;
 
 
-    seader_send_payload(seader_uart, payload, 0x44, 0x0a, 0x44);
+    seader_send_payload(seader, payload, 0x44, 0x0a, 0x44);
 
 
-    free(payload);
-    free(samCommand);
-    free(cardDetected);
+    ASN_STRUCT_FREE(asn_DEF_Payload, payload);
+    ASN_STRUCT_FREE(asn_DEF_SamCommand, samCommand);
+    ASN_STRUCT_FREE(asn_DEF_CardDetected, cardDetected);
 }
 }
 
 
 bool seader_unpack_pacs(Seader* seader, uint8_t* buf, size_t size) {
 bool seader_unpack_pacs(Seader* seader, uint8_t* buf, size_t size) {
@@ -402,16 +409,16 @@ bool seader_unpack_pacs(Seader* seader, uint8_t* buf, size_t size) {
 //    800201298106683d052026b6820101
 //    800201298106683d052026b6820101
 //300F800201298106683D052026B6820101
 //300F800201298106683D052026B6820101
 bool seader_parse_version(SeaderWorker* seader_worker, uint8_t* buf, size_t size) {
 bool seader_parse_version(SeaderWorker* seader_worker, uint8_t* buf, size_t size) {
-    SamVersion_t* version = 0;
-    version = calloc(1, sizeof *version);
-    assert(version);
-
     bool rtn = false;
     bool rtn = false;
     if(size > 30) {
     if(size > 30) {
         // Too large to handle now
         // Too large to handle now
         FURI_LOG_W(TAG, "Version of %d is to long to parse", size);
         FURI_LOG_W(TAG, "Version of %d is to long to parse", size);
         return false;
         return false;
     }
     }
+    SamVersion_t* version = 0;
+    version = calloc(1, sizeof *version);
+    assert(version);
+
     // Add sequence prefix
     // Add sequence prefix
     uint8_t seq[32] = {0x30};
     uint8_t seq[32] = {0x30};
     seq[1] = (uint8_t)size;
     seq[1] = (uint8_t)size;
@@ -570,7 +577,7 @@ bool seader_parse_response(Seader* seader, Response_t* response) {
     return false;
     return false;
 }
 }
 
 
-void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t len) {
+void seader_send_nfc_rx(Seader* seader, uint8_t* buffer, size_t len) {
     OCTET_STRING_t rxData = {.buf = buffer, .size = len};
     OCTET_STRING_t rxData = {.buf = buffer, .size = len};
     uint8_t status[] = {0x00, 0x00};
     uint8_t status[] = {0x00, 0x00};
     RfStatus_t rfStatus = {.buf = status, .size = 2};
     RfStatus_t rfStatus = {.buf = status, .size = 2};
@@ -596,11 +603,11 @@ void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t l
     response->present = Response_PR_nfcResponse;
     response->present = Response_PR_nfcResponse;
     response->choice.nfcResponse = *nfcResponse;
     response->choice.nfcResponse = *nfcResponse;
 
 
-    seader_send_response(seader_uart, response, 0x14, 0x0a, 0x0);
+    seader_send_response(seader, response, 0x14, 0x0a, 0x0);
 
 
-    free(nfcRx);
-    free(nfcResponse);
-    free(response);
+    ASN_STRUCT_FREE(asn_DEF_NFCRx, nfcRx);
+    ASN_STRUCT_FREE(asn_DEF_NFCResponse, nfcResponse);
+    ASN_STRUCT_FREE(asn_DEF_Response, response);
 }
 }
 
 
 void seader_capture_sio(BitBuffer* tx_buffer, BitBuffer* rx_buffer, SeaderCredential* credential) {
 void seader_capture_sio(BitBuffer* tx_buffer, BitBuffer* rx_buffer, SeaderCredential* credential) {
@@ -639,12 +646,7 @@ void seader_iso15693_transmit(
     PicopassPoller* picopass_poller,
     PicopassPoller* picopass_poller,
     uint8_t* buffer,
     uint8_t* buffer,
     size_t len) {
     size_t len) {
-    UNUSED(seader);
-    UNUSED(buffer);
-    UNUSED(len);
-
     SeaderWorker* seader_worker = seader->worker;
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
 
 
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
@@ -671,7 +673,7 @@ void seader_iso15693_transmit(
 
 
         seader_capture_sio(tx_buffer, rx_buffer, seader->credential);
         seader_capture_sio(tx_buffer, rx_buffer, seader->credential);
         seader_send_nfc_rx(
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
             bit_buffer_get_size_bytes(rx_buffer));
 
 
@@ -696,7 +698,6 @@ void seader_iso14443a_transmit(
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(iso14443_4a_poller);
     furi_assert(iso14443_4a_poller);
     SeaderWorker* seader_worker = seader->worker;
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     SeaderCredential* credential = seader->credential;
     SeaderCredential* credential = seader->credential;
 
 
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
@@ -721,7 +722,7 @@ void seader_iso14443a_transmit(
 
 
         seader_capture_sio(tx_buffer, rx_buffer, credential);
         seader_capture_sio(tx_buffer, rx_buffer, credential);
         seader_send_nfc_rx(
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
             bit_buffer_get_size_bytes(rx_buffer));
 
 
@@ -745,7 +746,6 @@ void seader_mfc_transmit(
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(mfc_poller);
     furi_assert(mfc_poller);
     SeaderWorker* seader_worker = seader->worker;
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
 
 
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
@@ -876,7 +876,7 @@ void seader_mfc_transmit(
         }
         }
 
 
         seader_send_nfc_rx(
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
             bit_buffer_get_size_bytes(rx_buffer));
 
 
@@ -936,9 +936,8 @@ void seader_parse_nfc_command_transmit(
     }
     }
 }
 }
 
 
-void seader_parse_nfc_off(SeaderUartBridge* seader_uart) {
+void seader_parse_nfc_off(Seader* seader) {
     FURI_LOG_D(TAG, "Set Field Off");
     FURI_LOG_D(TAG, "Set Field Off");
-
     NFCResponse_t* nfcResponse = 0;
     NFCResponse_t* nfcResponse = 0;
     nfcResponse = calloc(1, sizeof *nfcResponse);
     nfcResponse = calloc(1, sizeof *nfcResponse);
     assert(nfcResponse);
     assert(nfcResponse);
@@ -952,21 +951,19 @@ void seader_parse_nfc_off(SeaderUartBridge* seader_uart) {
     response->present = Response_PR_nfcResponse;
     response->present = Response_PR_nfcResponse;
     response->choice.nfcResponse = *nfcResponse;
     response->choice.nfcResponse = *nfcResponse;
 
 
-    seader_send_response(seader_uart, response, 0x44, 0x0a, 0);
+    seader_send_response(seader, response, 0x44, 0x0a, 0);
 
 
     free(response);
     free(response);
     free(nfcResponse);
     free(nfcResponse);
 }
 }
 
 
 void seader_parse_nfc_command(Seader* seader, NFCCommand_t* nfcCommand, SeaderPollerContainer* spc) {
 void seader_parse_nfc_command(Seader* seader, NFCCommand_t* nfcCommand, SeaderPollerContainer* spc) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     switch(nfcCommand->present) {
     switch(nfcCommand->present) {
     case NFCCommand_PR_nfcSend:
     case NFCCommand_PR_nfcSend:
         seader_parse_nfc_command_transmit(seader, &nfcCommand->choice.nfcSend, spc);
         seader_parse_nfc_command_transmit(seader, &nfcCommand->choice.nfcSend, spc);
         break;
         break;
     case NFCCommand_PR_nfcOff:
     case NFCCommand_PR_nfcOff:
-        seader_parse_nfc_off(seader_uart);
+        seader_parse_nfc_off(seader);
         seader->worker->stage = SeaderPollerEventTypeComplete;
         seader->worker->stage = SeaderPollerEventTypeComplete;
         break;
         break;
     default:
     default:

+ 1 - 0
scenes/seader_scene_read_14a.c

@@ -56,6 +56,7 @@ void seader_scene_read_14a_on_exit(void* context) {
     if(seader->poller) {
     if(seader->poller) {
         nfc_poller_stop(seader->poller);
         nfc_poller_stop(seader->poller);
         nfc_poller_free(seader->poller);
         nfc_poller_free(seader->poller);
+        seader->poller = NULL;
     }
     }
 
 
     // Clear view
     // Clear view

+ 1 - 0
scenes/seader_scene_read_mfc.c

@@ -60,6 +60,7 @@ void seader_scene_read_mfc_on_exit(void* context) {
     if(seader->poller) {
     if(seader->poller) {
         nfc_poller_stop(seader->poller);
         nfc_poller_stop(seader->poller);
         nfc_poller_free(seader->poller);
         nfc_poller_free(seader->poller);
+        seader->poller = NULL;
     }
     }
 
 
     // Clear view
     // Clear view

+ 1 - 0
scenes/seader_scene_read_picopass.c

@@ -55,6 +55,7 @@ void seader_scene_read_picopass_on_exit(void* context) {
     if(seader->picopass_poller) {
     if(seader->picopass_poller) {
         picopass_poller_stop(seader->picopass_poller);
         picopass_poller_stop(seader->picopass_poller);
         picopass_poller_free(seader->picopass_poller);
         picopass_poller_free(seader->picopass_poller);
+        seader->picopass_poller = NULL;
     }
     }
 
 
     // Clear view
     // Clear view

+ 5 - 1
seader_bridge.h

@@ -9,7 +9,8 @@
 #include <furi.h>
 #include <furi.h>
 #include <furi_hal.h>
 #include <furi_hal.h>
 
 
-#define SEADER_UART_RX_BUF_SIZE (128)
+// https://ww1.microchip.com/downloads/en/DeviceDoc/00001561C.pdf
+#define SEADER_UART_RX_BUF_SIZE (261)
 
 
 typedef struct {
 typedef struct {
     uint8_t uart_ch;
     uint8_t uart_ch;
@@ -41,6 +42,9 @@ struct SeaderUartBridge {
     uint8_t rx_buf[SEADER_UART_RX_BUF_SIZE];
     uint8_t rx_buf[SEADER_UART_RX_BUF_SIZE];
     uint8_t tx_buf[SEADER_UART_RX_BUF_SIZE];
     uint8_t tx_buf[SEADER_UART_RX_BUF_SIZE];
     size_t tx_len;
     size_t tx_len;
+
+    // T=0 or T=1
+    uint8_t T;
 };
 };
 
 
 typedef struct SeaderUartBridge SeaderUartBridge;
 typedef struct SeaderUartBridge SeaderUartBridge;

+ 2 - 2
seader_credential.h

@@ -7,9 +7,9 @@
 #include "protocol/picopass_protocol.h"
 #include "protocol/picopass_protocol.h"
 
 
 #define SEADER_CRED_NAME_MAX_LEN 22
 #define SEADER_CRED_NAME_MAX_LEN 22
-#define SEADER_APP_EXTENSION ".credential"
+#define SEADER_APP_EXTENSION     ".credential"
 #define SEADER_APP_MFC_EXTENSION ".nfc"
 #define SEADER_APP_MFC_EXTENSION ".nfc"
-#define SEADER_APP_MFC_FOLDER ANY_PATH("nfc")
+#define SEADER_APP_MFC_FOLDER    ANY_PATH("nfc")
 
 
 typedef void (*SeaderLoadingCallback)(void* context, bool state);
 typedef void (*SeaderLoadingCallback)(void* context, bool state);
 
 

+ 2 - 0
seader_i.h

@@ -50,6 +50,8 @@
 #include "seader.h"
 #include "seader.h"
 #include "ccid.h"
 #include "ccid.h"
 #include "uart.h"
 #include "uart.h"
+#include "lrc.h"
+#include "t_1.h"
 #include "seader_worker.h"
 #include "seader_worker.h"
 #include "seader_credential.h"
 #include "seader_credential.h"
 
 

+ 8 - 12
seader_worker.c

@@ -6,16 +6,13 @@
 #define TAG "SeaderWorker"
 #define TAG "SeaderWorker"
 
 
 #define APDU_HEADER_LEN 5
 #define APDU_HEADER_LEN 5
-#define ASN1_PREFIX 6
-#define ASN1_DEBUG true
+#define ASN1_PREFIX     6
+#define ASN1_DEBUG      true
 
 
 #define RFAL_PICOPASS_TXRX_FLAGS                                                    \
 #define RFAL_PICOPASS_TXRX_FLAGS                                                    \
     (FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \
     (FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_TX_MANUAL | FURI_HAL_NFC_LL_TXRX_FLAGS_AGC_ON | \
      FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP)
      FURI_HAL_NFC_LL_TXRX_FLAGS_PAR_RX_REMV | FURI_HAL_NFC_LL_TXRX_FLAGS_CRC_RX_KEEP)
 
 
-// TODO: const
-uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
-
 char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
 char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
 
 
 // Forward declaration
 // Forward declaration
@@ -114,9 +111,7 @@ bool seader_process_success_response(Seader* seader, uint8_t* apdu, size_t len)
     return true;
     return true;
 }
 }
 
 
-bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
-    size_t len = message->dwLength;
-    uint8_t* apdu = message->payload;
+bool seader_worker_process_sam_message(Seader* seader, uint8_t* apdu, uint32_t len) {
     SeaderWorker* seader_worker = seader->worker;
     SeaderWorker* seader_worker = seader->worker;
     SeaderUartBridge* seader_uart = seader_worker->uart;
     SeaderUartBridge* seader_uart = seader_worker->uart;
     if(len < 2) {
     if(len < 2) {
@@ -126,10 +121,11 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
     for(uint8_t i = 0; i < len; i++) {
     for(uint8_t i = 0; i < len; i++) {
         snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
         snprintf(display + (i * 2), sizeof(display), "%02x", apdu[i]);
     }
     }
-    // FURI_LOG_I(TAG, "APDU: %s", display);
+    FURI_LOG_I(TAG, "APDU: %s", display);
 
 
     uint8_t SW1 = apdu[len - 2];
     uint8_t SW1 = apdu[len - 2];
     uint8_t SW2 = apdu[len - 1];
     uint8_t SW2 = apdu[len - 1];
+    uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
 
 
     switch(SW1) {
     switch(SW1) {
     case 0x61:
     case 0x61:
@@ -138,7 +134,6 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
         seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE));
         seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE));
         return true;
         return true;
         break;
         break;
-
     case 0x90:
     case 0x90:
         if(SW2 == 0x00) {
         if(SW2 == 0x00) {
             if(len > 2) {
             if(len > 2) {
@@ -146,6 +141,9 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
             }
             }
         }
         }
         break;
         break;
+    default:
+        FURI_LOG_W(TAG, "Unknown SW %02x%02x", SW1, SW2);
+        break;
     }
     }
 
 
     return false;
     return false;
@@ -304,8 +302,6 @@ NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void
             break;
             break;
         case Iso14443_4aErrorTimeout:
         case Iso14443_4aErrorTimeout:
             break;
             break;
-        case Iso14443_4aErrorSendExtra:
-            break;
         }
         }
     }
     }
 
 

+ 1 - 1
seader_worker.h

@@ -62,7 +62,7 @@ void seader_worker_start(
     void* context);
     void* context);
 
 
 void seader_worker_stop(SeaderWorker* seader_worker);
 void seader_worker_stop(SeaderWorker* seader_worker);
-bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message);
+bool seader_worker_process_sam_message(Seader* seader, uint8_t* apdu, uint32_t len);
 void seader_worker_send_version(Seader* seader);
 void seader_worker_send_version(Seader* seader);
 
 
 NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);
 NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);

+ 1 - 1
seader_worker_i.h

@@ -13,7 +13,7 @@
 #include <PAC.h>
 #include <PAC.h>
 #include <SamVersion.h>
 #include <SamVersion.h>
 
 
-#define SEADER_POLLER_MAX_FWT (200000U)
+#define SEADER_POLLER_MAX_FWT         (200000U)
 #define SEADER_POLLER_MAX_BUFFER_SIZE (255U)
 #define SEADER_POLLER_MAX_BUFFER_SIZE (255U)
 
 
 struct SeaderWorker {
 struct SeaderWorker {

+ 231 - 0
t_1.c

@@ -0,0 +1,231 @@
+#include "t_1.h"
+
+#define TAG "Seader:T=1"
+
+// http://www.sat-digest.com/SatXpress/SmartCard/ISO7816-4.htm
+
+/* I know my T=1 is terrible, but I'm also only targetting one specific 'card' */
+
+#define MORE_BIT               0x20
+#define IFSD_VALUE             0xfe
+#define IFSC_VALUE             0xfe // Fom the SAM ATR
+#define R_BLOCK                0x80
+#define R_SEQUENCE_NUMBER_MASK 0x10
+
+// TODO: T1 struct
+uint8_t NAD = 0x00;
+uint8_t dPCB = 0x40; // Init to 0x40 so first call to next_pcb will return 0x00
+uint8_t cPCB = 0x00; // Init to 0x40 so first call to next_pcb will return 0x00
+
+uint8_t seader_next_dpcb() {
+    uint8_t next_pcb = dPCB ^ 0x40;
+    //FURI_LOG_D(TAG, "dPCB was: %02X, current dPCB: %02X", dPCB, next_pcb);
+    dPCB = next_pcb;
+    return dPCB;
+}
+
+uint8_t seader_next_cpcb() {
+    uint8_t next_pcb = cPCB ^ 0x40;
+    //FURI_LOG_D(TAG, "cPCB was: %02X, current cPCB: %02X", cPCB, next_pcb);
+    cPCB = next_pcb;
+    return cPCB;
+}
+
+void seader_t_1_set_IFSD(Seader* seader) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+    uint8_t frame[5];
+    uint8_t frame_len = 0;
+
+    frame[0] = NAD;
+    frame[1] = 0xC1; // S(IFS request)
+    frame[2] = 0x01;
+    frame[3] = IFSD_VALUE;
+    frame_len = 4;
+
+    frame_len = seader_add_lrc(frame, frame_len);
+
+    seader_ccid_XfrBlock(seader_uart, frame, frame_len);
+}
+
+void seader_t_1_send_ack(Seader* seader) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+    uint8_t frame[4];
+    uint8_t frame_len = 0;
+
+    frame[0] = NAD;
+    frame[1] = R_BLOCK | (seader_next_cpcb() >> 2);
+    frame[2] = 0x00;
+    frame_len = 3;
+
+    frame_len = seader_add_lrc(frame, frame_len);
+
+    //FURI_LOG_D(TAG, "Sending R-Block ACK: PCB: %02x", frame[1]);
+
+    seader_ccid_XfrBlock(seader_uart, frame, frame_len);
+}
+
+BitBuffer* seader_t_1_tx_buffer;
+size_t seader_t_1_tx_buffer_offset = 0;
+
+void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len) {
+    uint8_t frame[SEADER_UART_RX_BUF_SIZE];
+    uint8_t frame_len = 0;
+
+    if(len > IFSC_VALUE) {
+        if(seader_t_1_tx_buffer == NULL) {
+            seader_t_1_tx_buffer = bit_buffer_alloc(768);
+            bit_buffer_copy_bytes(seader_t_1_tx_buffer, apdu, len);
+        }
+        size_t remaining =
+            (bit_buffer_get_size_bytes(seader_t_1_tx_buffer) - seader_t_1_tx_buffer_offset);
+        size_t copy_length = remaining > IFSC_VALUE ? IFSC_VALUE : remaining;
+
+        frame[0] = NAD;
+        if(remaining > IFSC_VALUE) {
+            frame[1] = seader_next_dpcb() | MORE_BIT;
+        } else {
+            frame[1] = seader_next_dpcb();
+        }
+        frame[2] = copy_length;
+        frame_len = 3;
+
+        memcpy(
+            frame + frame_len,
+            bit_buffer_get_data(seader_t_1_tx_buffer) + seader_t_1_tx_buffer_offset,
+            copy_length);
+        frame_len += copy_length;
+
+        frame_len = seader_add_lrc(frame, frame_len);
+
+        /*
+        FURI_LOG_D(
+            TAG,
+            "Sending T=1 frame %s more bit set.  Remaining: %d, Copy Length: %d",
+            (remaining > IFSC_VALUE) ? "with" : "without",
+            remaining,
+            copy_length);
+            */
+
+        seader_ccid_XfrBlock(seader_uart, frame, frame_len);
+
+        seader_t_1_tx_buffer_offset += copy_length;
+        if(seader_t_1_tx_buffer_offset >= bit_buffer_get_size_bytes(seader_t_1_tx_buffer)) {
+            bit_buffer_free(seader_t_1_tx_buffer);
+            seader_t_1_tx_buffer = NULL;
+            seader_t_1_tx_buffer_offset = 0;
+        }
+        return;
+    }
+
+    frame[0] = NAD;
+    frame[1] = seader_next_dpcb();
+    frame[2] = len;
+    frame_len = 3;
+
+    if(len > 0) {
+        memcpy(frame + frame_len, apdu, len);
+        frame_len += len;
+    }
+
+    frame_len = seader_add_lrc(frame, frame_len);
+
+    seader_ccid_XfrBlock(seader_uart, frame, frame_len);
+}
+
+BitBuffer* seader_t_1_rx_buffer;
+
+bool seader_recv_t1(Seader* seader, CCID_Message* message) {
+    // remove/validate NAD, PCB, LEN, LRC
+    if(message->dwLength < 4) {
+        FURI_LOG_W(TAG, "Invalid T=1 frame: too short");
+        return false;
+    }
+    //uint8_t NAD = message->payload[0];
+    uint8_t rPCB = message->payload[1];
+    uint8_t LEN = message->payload[2];
+    //uint8_t LRC = message->payload[3 + LEN];
+    //FURI_LOG_D(TAG, "NAD: %02X, rPCB: %02X, LEN: %02X, LRC: %02X", NAD, rPCB, LEN, LRC);
+
+    if(rPCB == 0xE1) {
+        // S(IFS response)
+        seader_worker_send_version(seader);
+        SeaderWorker* seader_worker = seader->worker;
+        if(seader_worker->callback) {
+            seader_worker->callback(SeaderWorkerEventSamPresent, seader_worker->context);
+        }
+        return false;
+    }
+
+    if(rPCB == cPCB) {
+        seader_next_cpcb();
+        if(seader_t_1_rx_buffer != NULL) {
+            bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
+
+            // TODO: validate LRC
+
+            seader_worker_process_sam_message(
+                seader,
+                (uint8_t*)bit_buffer_get_data(seader_t_1_rx_buffer),
+                bit_buffer_get_size_bytes(seader_t_1_rx_buffer));
+
+            bit_buffer_free(seader_t_1_rx_buffer);
+            seader_t_1_rx_buffer = NULL;
+            return true;
+        }
+
+        if(seader_validate_lrc(message->payload, message->dwLength) == false) {
+            return false;
+        }
+
+        // Skip NAD, PCB, LEN
+        message->payload = message->payload + 3;
+        message->dwLength = LEN;
+
+        if(message->dwLength == 0) {
+            //FURI_LOG_D(TAG, "Received T=1 frame with no data");
+            return true;
+        }
+        return seader_worker_process_sam_message(seader, message->payload, message->dwLength);
+    } else if(rPCB == (cPCB | MORE_BIT)) {
+        //FURI_LOG_D(TAG, "Received T=1 frame with more bit set");
+        if(seader_t_1_rx_buffer == NULL) {
+            seader_t_1_rx_buffer = bit_buffer_alloc(512);
+        }
+        bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
+        seader_t_1_send_ack(seader);
+        return false;
+    } else if((rPCB & R_BLOCK) == R_BLOCK) {
+        uint8_t R_SEQ = (rPCB & R_SEQUENCE_NUMBER_MASK) >> 4;
+        uint8_t I_SEQ = (dPCB ^ 0x40) >> 6;
+        if(R_SEQ != I_SEQ) {
+            /*
+            FURI_LOG_D(
+                TAG,
+                "Received R-Block: Incorrect sequence.  Expected: %02X, Received: %02X",
+                I_SEQ,
+                R_SEQ);
+
+            */
+            // When this happens, the flipper freezes if it is doing NFC and my attempts to do events to stop that have failed
+            return false;
+        }
+
+        if(seader_t_1_tx_buffer != NULL) {
+            // Send more data, re-using the buffer to trigger the code path that sends the next block
+            SeaderWorker* seader_worker = seader->worker;
+            SeaderUartBridge* seader_uart = seader_worker->uart;
+            seader_send_t1(
+                seader_uart,
+                (uint8_t*)bit_buffer_get_data(seader_t_1_tx_buffer),
+                bit_buffer_get_size_bytes(seader_t_1_tx_buffer));
+            return false;
+        }
+    } else {
+        FURI_LOG_W(
+            TAG, "Invalid T=1 frame: PCB mismatch.  Expected: %02X, Received: %02X", cPCB, rPCB);
+    }
+
+    return false;
+}

+ 9 - 0
t_1.h

@@ -0,0 +1,9 @@
+#pragma once
+
+#include "ccid.h"
+
+typedef struct CCID_Message CCID_Message;
+
+void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len);
+bool seader_recv_t1(Seader* seader, CCID_Message* message);
+void seader_t_1_set_IFSD(Seader* seader);

+ 5 - 2
uart.c

@@ -98,7 +98,7 @@ int32_t seader_uart_worker(void* context) {
     seader_uart->tx_sem = furi_semaphore_alloc(1, 1);
     seader_uart->tx_sem = furi_semaphore_alloc(1, 1);
 
 
     seader_uart->tx_thread =
     seader_uart->tx_thread =
-        furi_thread_alloc_ex("SeaderUartTxWorker", 2 * 1024, seader_uart_tx_thread, seader);
+        furi_thread_alloc_ex("SeaderUartTxWorker", 3 * 1024, seader_uart_tx_thread, seader);
 
 
     seader_uart_serial_init(seader_uart, seader_uart->cfg.uart_ch);
     seader_uart_serial_init(seader_uart, seader_uart->cfg.uart_ch);
     seader_uart_set_baudrate(seader_uart, seader_uart->cfg.baudrate);
     seader_uart_set_baudrate(seader_uart, seader_uart->cfg.baudrate);
@@ -159,10 +159,13 @@ int32_t seader_uart_worker(void* context) {
 SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) {
 SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) {
     SeaderUartBridge* seader_uart = malloc(sizeof(SeaderUartBridge));
     SeaderUartBridge* seader_uart = malloc(sizeof(SeaderUartBridge));
 
 
+    seader_uart->T = 0;
+    seader_uart->T = (seader->is_debug_enabled ? 1 : 0);
+
     memcpy(&(seader_uart->cfg_new), cfg, sizeof(SeaderUartConfig));
     memcpy(&(seader_uart->cfg_new), cfg, sizeof(SeaderUartConfig));
 
 
     seader_uart->thread =
     seader_uart->thread =
-        furi_thread_alloc_ex("SeaderUartWorker", 4 * 1024, seader_uart_worker, seader);
+        furi_thread_alloc_ex("SeaderUartWorker", 5 * 1024, seader_uart_worker, seader);
 
 
     furi_thread_start(seader_uart->thread);
     furi_thread_start(seader_uart->thread);
     return seader_uart;
     return seader_uart;