Przeglądaj źródła

Merge seader from https://github.com/bettse/seader

Willy-JL 1 rok temu
rodzic
commit
667b20d74d

+ 89 - 34
seader/.clang-format

@@ -3,22 +3,55 @@ Language:        Cpp
 AccessModifierOffset: -4
 AlignAfterOpenBracket: AlwaysBreak
 AlignArrayOfStructures: None
-AlignConsecutiveMacros: None
-AlignConsecutiveAssignments: None
-AlignConsecutiveBitFields: None
-AlignConsecutiveDeclarations: None
+AlignConsecutiveAssignments:
+  Enabled:         false
+  AcrossEmptyLines: false
+  AcrossComments:  false
+  AlignCompound:   false
+  AlignFunctionPointers: false
+  PadOperators:    true
+AlignConsecutiveBitFields:
+  Enabled:         true
+  AcrossEmptyLines: true
+  AcrossComments:  true
+  AlignCompound:   false
+  AlignFunctionPointers: false
+  PadOperators:    true
+AlignConsecutiveDeclarations:
+  Enabled:         false
+  AcrossEmptyLines: false
+  AcrossComments:  false
+  AlignCompound:   false
+  AlignFunctionPointers: false
+  PadOperators:    true
+AlignConsecutiveMacros:
+  Enabled:         true
+  AcrossEmptyLines: false
+  AcrossComments:  true
+  AlignCompound:   true
+  AlignFunctionPointers: false
+  PadOperators:    true
+AlignConsecutiveShortCaseStatements:
+  Enabled:         false
+  AcrossEmptyLines: false
+  AcrossComments:  false
+  AlignCaseColons: false
 AlignEscapedNewlines: Left
 AlignOperands:   Align
-AlignTrailingComments: false
+AlignTrailingComments:
+  Kind:            Never
+  OverEmptyLines:  0
 AllowAllArgumentsOnNextLine: true
 AllowAllParametersOfDeclarationOnNextLine: false
-AllowShortEnumsOnASingleLine: true
+AllowBreakBeforeNoexceptSpecifier: Never
 AllowShortBlocksOnASingleLine: Never
 AllowShortCaseLabelsOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: None
-AllowShortLambdasOnASingleLine: All
 AllowShortIfStatementsOnASingleLine: WithoutElse
-AllowShortLoopsOnASingleLine: true
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
 AlwaysBreakAfterDefinitionReturnType: None
 AlwaysBreakAfterReturnType: None
 AlwaysBreakBeforeMultilineStrings: false
@@ -27,17 +60,18 @@ AttributeMacros:
   - __capability
 BinPackArguments: false
 BinPackParameters: false
+BitFieldColonSpacing: Both
 BraceWrapping:
   AfterCaseLabel:  false
   AfterClass:      false
   AfterControlStatement: Never
   AfterEnum:       false
+  AfterExternBlock: false
   AfterFunction:   false
   AfterNamespace:  false
   AfterObjCDeclaration: false
   AfterStruct:     false
   AfterUnion:      false
-  AfterExternBlock: false
   BeforeCatch:     false
   BeforeElse:      false
   BeforeLambdaBody: false
@@ -46,38 +80,35 @@ BraceWrapping:
   SplitEmptyFunction: true
   SplitEmptyRecord: true
   SplitEmptyNamespace: true
+BreakAdjacentStringLiterals: true
+BreakAfterAttributes: Leave
+BreakAfterJavaFieldAnnotations: false
+BreakArrays:     true
 BreakBeforeBinaryOperators: None
-BreakBeforeConceptDeclarations: true
+BreakBeforeConceptDeclarations: Always
 BreakBeforeBraces: Attach
-BreakBeforeInheritanceComma: false
-BreakInheritanceList: BeforeColon
+BreakBeforeInlineASMColon: OnlyMultiline
 BreakBeforeTernaryOperators: false
-BreakConstructorInitializersBeforeComma: false
 BreakConstructorInitializers: BeforeComma
-BreakAfterJavaFieldAnnotations: false
+BreakInheritanceList: BeforeColon
 BreakStringLiterals: false
 ColumnLimit:     99
 CommentPragmas:  '^ IWYU pragma:'
-QualifierAlignment: Leave
 CompactNamespaces: false
 ConstructorInitializerIndentWidth: 4
 ContinuationIndentWidth: 4
 Cpp11BracedListStyle: true
-DeriveLineEnding: true
 DerivePointerAlignment: false
 DisableFormat:   false
 EmptyLineAfterAccessModifier: Never
 EmptyLineBeforeAccessModifier: LogicalBlock
 ExperimentalAutoDetectBinPacking: false
-PackConstructorInitializers: BinPack
-BasedOnStyle:    ''
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-AllowAllConstructorInitializersOnNextLine: true
 FixNamespaceComments: false
 ForEachMacros:
   - foreach
   - Q_FOREACH
   - BOOST_FOREACH
+  - M_EACH
 IfMacros:
   - KJ_IF_MAYBE
 IncludeBlocks:   Preserve
@@ -97,19 +128,30 @@ IncludeCategories:
 IncludeIsMainRegex: '(Test)?$'
 IncludeIsMainSourceRegex: ''
 IndentAccessModifiers: false
-IndentCaseLabels: false
 IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentExternBlock: AfterExternBlock
 IndentGotoLabels: true
 IndentPPDirectives: None
-IndentExternBlock: AfterExternBlock
-IndentRequires:  false
+IndentRequiresClause: false
 IndentWidth:     4
 IndentWrappedFunctionNames: true
+InsertBraces:    false
+InsertNewlineAtEOF: true
 InsertTrailingCommas: None
+IntegerLiteralSeparator:
+  Binary:          0
+  BinaryMinDigits: 0
+  Decimal:         0
+  DecimalMinDigits: 0
+  Hex:             0
+  HexMinDigits:    0
 JavaScriptQuotes: Leave
 JavaScriptWrapImports: true
 KeepEmptyLinesAtTheStartOfBlocks: false
+KeepEmptyLinesAtEOF: false
 LambdaBodyIndentation: Signature
+LineEnding:      DeriveLF
 MacroBlockBegin: ''
 MacroBlockEnd:   ''
 MaxEmptyLinesToKeep: 1
@@ -119,34 +161,44 @@ ObjCBlockIndentWidth: 4
 ObjCBreakBeforeNestedBlockParam: true
 ObjCSpaceAfterProperty: true
 ObjCSpaceBeforeProtocolList: true
+PackConstructorInitializers: BinPack
 PenaltyBreakAssignment: 10
 PenaltyBreakBeforeFirstCallParameter: 30
 PenaltyBreakComment: 10
 PenaltyBreakFirstLessLess: 0
 PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
 PenaltyBreakString: 10
 PenaltyBreakTemplateDeclaration: 10
 PenaltyExcessCharacter: 100
-PenaltyReturnTypeOnItsOwnLine: 60
 PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 60
 PointerAlignment: Left
 PPIndentWidth:   -1
+QualifierAlignment: Leave
 ReferenceAlignment: Pointer
 ReflowComments:  false
 RemoveBracesLLVM: false
+RemoveParentheses: Leave
+RemoveSemicolon: true
+RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
 SeparateDefinitionBlocks: Leave
 ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
 SortIncludes:    Never
 SortJavaStaticImport: Before
-SortUsingDeclarations: false
+SortUsingDeclarations: Never
 SpaceAfterCStyleCast: false
 SpaceAfterLogicalNot: false
 SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
 SpaceBeforeAssignmentOperators: true
 SpaceBeforeCaseColon: false
 SpaceBeforeCpp11BracedList: false
 SpaceBeforeCtorInitializerColon: true
 SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
 SpaceBeforeParens: Never
 SpaceBeforeParensOptions:
   AfterControlStatements: false
@@ -155,32 +207,35 @@ SpaceBeforeParensOptions:
   AfterFunctionDeclarationName: false
   AfterIfMacros:   false
   AfterOverloadedOperator: false
+  AfterPlacementOperator: true
+  AfterRequiresInClause: false
+  AfterRequiresInExpression: false
   BeforeNonEmptyParentheses: false
-SpaceAroundPointerQualifiers: Default
 SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
 SpaceInEmptyBlock: false
-SpaceInEmptyParentheses: false
 SpacesBeforeTrailingComments: 1
 SpacesInAngles:  Never
-SpacesInConditionalStatement: false
 SpacesInContainerLiterals: false
-SpacesInCStyleCastParentheses: false
 SpacesInLineCommentPrefix:
   Minimum:         1
   Maximum:         -1
-SpacesInParentheses: false
+SpacesInParens:  Never
+SpacesInParensOptions:
+  InCStyleCasts:   false
+  InConditionalStatements: false
+  InEmptyParentheses: false
+  Other:           false
 SpacesInSquareBrackets: false
-SpaceBeforeSquareBrackets: false
-BitFieldColonSpacing: Both
-Standard:        c++03
+Standard:        c++20
 StatementAttributeLikeMacros:
   - Q_EMIT
 StatementMacros:
   - Q_UNUSED
   - QT_REQUIRE_VERSION
 TabWidth:        4
-UseCRLF:         false
 UseTab:          Never
+VerilogBreakBetweenInstancePorts: true
 WhitespaceSensitiveMacros:
   - STRINGIZE
   - PP_STRINGIZE

+ 1 - 1
seader/application.fam

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

+ 17 - 17
seader/assembly.h

@@ -27,8 +27,8 @@
 #endif
 
 #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
 #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
 #define SYMBOL_IS_FUNC(name)
@@ -38,7 +38,7 @@
 
 #elif defined(__ELF__)
 
-#define HIDDEN(name) .hidden name
+#define HIDDEN(name)      .hidden name
 #define LOCAL_LABEL(name) .L_##name
 #define FILE_LEVEL_DIRECTIVE
 #if defined(__arm__) || defined(__aarch64__)
@@ -60,7 +60,7 @@
 #define LOCAL_LABEL(name) .L##name
 #define FILE_LEVEL_DIRECTIVE
 #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
 
@@ -73,7 +73,7 @@
 #endif
 
 // 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_BTI 1
 #define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
@@ -112,7 +112,7 @@
 
 #if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
 #define CFI_START .cfi_startproc
-#define CFI_END .cfi_endproc
+#define CFI_END   .cfi_endproc
 #else
 #define CFI_START
 #define CFI_END
@@ -124,11 +124,11 @@
 // - for '-mthumb -march=armv6' compiler defines '__thumb__'
 // - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
 #if defined(__thumb2__) || defined(__thumb__)
-#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DEFINE_CODE_STATE     .thumb SEPARATOR
 #define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
 #if defined(__thumb2__)
 #define USE_THUMB_2
-#define IT(cond) it cond
+#define IT(cond)  it cond
 #define ITT(cond) itt cond
 #define ITE(cond) ite cond
 #else
@@ -158,10 +158,10 @@
 #endif
 
 #ifdef ARM_HAS_BX
-#define JMP(r) bx r
+#define JMP(r)     bx r
 #define JMPc(r, c) bx##c r
 #else
-#define JMP(r) mov pc, r
+#define JMP(r)     mov pc, r
 #define JMPc(r, c) mov##c pc, r
 #endif
 
@@ -187,18 +187,18 @@
 #define DEFINE_CODE_STATE
 #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) 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)
 
 #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
 #else
 #define DECLARE_SYMBOL_VISIBILITY(name)

+ 22 - 29
seader/ccid.c

@@ -19,24 +19,6 @@ uint8_t getSequence(uint8_t 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) {
     if(powered[slot]) {
         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 + 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);
 }
 
@@ -74,11 +56,16 @@ void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot) {
     seader_uart->tx_buf[2 + 5] = 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);
 }
 
-void seader_ccid_SetParameters(SeaderUartBridge* seader_uart) {
+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(slot);
+    UNUSED(atr);
+    UNUSED(atr_len);
     uint8_t T1 = 1;
     memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
     seader_uart->tx_buf[0] = SYNC;
@@ -91,7 +78,7 @@ void seader_ccid_SetParameters(SeaderUartBridge* seader_uart) {
     seader_uart->tx_buf[2 + 8] = 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);
 }
@@ -108,7 +95,7 @@ void seader_ccid_GetParameters(SeaderUartBridge* seader_uart) {
     seader_uart->tx_buf[2 + 8] = 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);
 }
@@ -126,7 +113,8 @@ void seader_ccid_XfrBlockToSlot(
     seader_uart->tx_buf[0] = SYNC;
     seader_uart->tx_buf[1] = CTRL;
     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 + 6] = getSequence(slot);
     seader_uart->tx_buf[2 + 7] = 5;
@@ -134,8 +122,13 @@ void seader_ccid_XfrBlockToSlot(
     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);
+    seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10 + 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_XfrBlock %d bytes: %s", seader_uart->tx_len, display);
 
     furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
 }
@@ -248,12 +241,12 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
         }
         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(
                 TAG,
                 "Invalid LRC.  Recv: %02x vs Calc: %02x",
                 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?
             return message.consumed;
         }
@@ -329,7 +322,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
         if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock) {
             if(hasSAM) {
                 if(message.bSlot == sam_slot) {
-                    seader_worker_process_sam_message(seader, &message);
+                    seader_worker_process_sam_message(seader, message.payload, message.dwLength);
                 } else {
                     FURI_LOG_D(TAG, "Discarding message on non-sam slot");
                 }

+ 31 - 27
seader/ccid.h

@@ -11,7 +11,7 @@
 
 #define SYNC (0x03)
 #define CTRL (0x06)
-#define NAK (0x15)
+#define NAK  (0x15)
 
 #define BMICCSTATUS_MASK 0x03
 /*
@@ -23,48 +23,52 @@
 
 // TODO: rename/renumber
 #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 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
  *   * 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
 /*
  *  * BULK_IN messages from Reader to PC
  *   * 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
  *   * 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) */
-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 {
     COMMAND_STATUS_NO_ERROR = 0,
     COMMAND_STATUS_FAILED,
@@ -95,7 +99,7 @@ struct CCID_Message {
 void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart);
 void seader_ccid_IccPowerOn(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_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len);
 void seader_ccid_XfrBlockToSlot(

+ 19 - 0
seader/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
seader/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
seader/protocol/picopass_poller_i.h

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

+ 15 - 15
seader/protocol/picopass_protocol.h

@@ -1,22 +1,22 @@
 #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_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_INDEX 7
-#define SR_SIO_INDEX 10
+#define PACS_INDEX     7
+#define SR_SIO_INDEX   10
 
 #define PICOPASS_FDT_LISTEN_FC (1000)
 

+ 1 - 1
seader/protocol/rfal_picopass.h

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

+ 44 - 66
seader/sam_api.c

@@ -6,11 +6,11 @@
 
 #define TAG "SAMAPI"
 
-#define APDU_HEADER_LEN 5
-#define ASN1_PREFIX 6
-#define ASN1_DEBUG true
+#define APDU_HEADER_LEN                 5
+#define ASN1_PREFIX                     6
+#define ASN1_DEBUG                      true
 #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};
 
@@ -34,7 +34,7 @@ void* calloc(size_t count, size_t size) {
 }
 
 // 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) {
     const uint8_t* buffer = bit_buffer_get_data(tx_buffer);
@@ -56,9 +56,6 @@ PicopassError seader_worker_fake_epurse_update(BitBuffer* tx_buffer, BitBuffer*
 }
 
 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);
     bit_buffer_append_bytes(tx_buffer, buffer, len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
@@ -131,7 +128,7 @@ void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len)
         }
 
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
 
@@ -141,13 +138,16 @@ void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len)
 }
 
 bool seader_send_apdu(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     uint8_t CLA,
     uint8_t INS,
     uint8_t P1,
     uint8_t P2,
     uint8_t* payload,
     uint8_t length) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+
     if(APDU_HEADER_LEN + length > SEADER_UART_RX_BUF_SIZE) {
         FURI_LOG_E(TAG, "Cannot send message, too long: %d", APDU_HEADER_LEN + length);
         return false;
@@ -184,7 +184,7 @@ static int seader_print_struct_callback(const void* buffer, size_t size, void* a
 }
 
 void seader_send_payload(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     Payload_t* payload,
     uint8_t to,
     uint8_t from,
@@ -214,11 +214,11 @@ void seader_send_payload(
     rBuffer[1] = from;
     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(
-    SeaderUartBridge* seader_uart,
+    Seader* seader,
     Response_t* response,
     uint8_t to,
     uint8_t from,
@@ -230,15 +230,12 @@ void seader_send_response(
     payload->present = Payload_PR_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) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     RequestPacs_t* requestPacs = 0;
     requestPacs = calloc(1, sizeof *requestPacs);
     assert(requestPacs);
@@ -261,17 +258,14 @@ void seader_send_request_pacs(Seader* seader) {
     payload->present = Payload_PR_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) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     SamCommand_t* samCommand = 0;
     samCommand = calloc(1, sizeof *samCommand);
     assert(samCommand);
@@ -286,16 +280,13 @@ void seader_worker_send_serial_number(Seader* seader) {
     payload->present = Payload_PR_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) {
-    SeaderWorker* seader_worker = seader->worker;
-
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     SamCommand_t* samCommand = 0;
     samCommand = calloc(1, sizeof *samCommand);
     assert(samCommand);
@@ -310,15 +301,13 @@ void seader_worker_send_version(Seader* seader) {
     payload->present = Payload_PR_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) {
-    SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     CardDetected_t* cardDetected = 0;
     cardDetected = calloc(1, sizeof *cardDetected);
     assert(cardDetected);
@@ -340,11 +329,11 @@ void seader_send_card_detected(Seader* seader, CardDetails_t* cardDetails) {
     payload->present = Payload_PR_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) {
@@ -402,16 +391,16 @@ bool seader_unpack_pacs(Seader* seader, uint8_t* buf, size_t size) {
 //    800201298106683d052026b6820101
 //300F800201298106683D052026B6820101
 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;
     if(size > 30) {
         // Too large to handle now
         FURI_LOG_W(TAG, "Version of %d is to long to parse", size);
         return false;
     }
+    SamVersion_t* version = 0;
+    version = calloc(1, sizeof *version);
+    assert(version);
+
     // Add sequence prefix
     uint8_t seq[32] = {0x30};
     seq[1] = (uint8_t)size;
@@ -570,7 +559,7 @@ bool seader_parse_response(Seader* seader, Response_t* response) {
     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};
     uint8_t status[] = {0x00, 0x00};
     RfStatus_t rfStatus = {.buf = status, .size = 2};
@@ -596,11 +585,11 @@ void seader_send_nfc_rx(SeaderUartBridge* seader_uart, uint8_t* buffer, size_t l
     response->present = Response_PR_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) {
@@ -639,13 +628,7 @@ void seader_iso15693_transmit(
     PicopassPoller* picopass_poller,
     uint8_t* buffer,
     size_t len) {
-    UNUSED(seader);
-    UNUSED(buffer);
-    UNUSED(len);
-
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
-
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
 
@@ -671,7 +654,7 @@ void seader_iso15693_transmit(
 
         seader_capture_sio(tx_buffer, rx_buffer, seader->credential);
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
 
@@ -696,7 +679,6 @@ void seader_iso14443a_transmit(
     furi_assert(buffer);
     furi_assert(iso14443_4a_poller);
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
     SeaderCredential* credential = seader->credential;
 
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
@@ -721,7 +703,7 @@ void seader_iso14443a_transmit(
 
         seader_capture_sio(tx_buffer, rx_buffer, credential);
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
 
@@ -745,7 +727,6 @@ void seader_mfc_transmit(
     furi_assert(buffer);
     furi_assert(mfc_poller);
     SeaderWorker* seader_worker = seader->worker;
-    SeaderUartBridge* seader_uart = seader_worker->uart;
 
     BitBuffer* tx_buffer = bit_buffer_alloc(len);
     BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
@@ -876,7 +857,7 @@ void seader_mfc_transmit(
         }
 
         seader_send_nfc_rx(
-            seader_uart,
+            seader,
             (uint8_t*)bit_buffer_get_data(rx_buffer),
             bit_buffer_get_size_bytes(rx_buffer));
 
@@ -936,9 +917,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");
-
     NFCResponse_t* nfcResponse = 0;
     nfcResponse = calloc(1, sizeof *nfcResponse);
     assert(nfcResponse);
@@ -952,21 +932,19 @@ void seader_parse_nfc_off(SeaderUartBridge* seader_uart) {
     response->present = Response_PR_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(nfcResponse);
 }
 
 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) {
     case NFCCommand_PR_nfcSend:
         seader_parse_nfc_command_transmit(seader, &nfcCommand->choice.nfcSend, spc);
         break;
     case NFCCommand_PR_nfcOff:
-        seader_parse_nfc_off(seader_uart);
+        seader_parse_nfc_off(seader);
         seader->worker->stage = SeaderPollerEventTypeComplete;
         break;
     default:

+ 1 - 0
seader/scenes/seader_scene_read_14a.c

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

+ 1 - 0
seader/scenes/seader_scene_read_mfc.c

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

+ 1 - 0
seader/scenes/seader_scene_read_picopass.c

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

+ 2 - 1
seader/seader_bridge.h

@@ -9,7 +9,8 @@
 #include <furi.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 {
     uint8_t uart_ch;

+ 2 - 2
seader/seader_credential.h

@@ -7,9 +7,9 @@
 #include "protocol/picopass_protocol.h"
 
 #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_FOLDER ANY_PATH("nfc")
+#define SEADER_APP_MFC_FOLDER    ANY_PATH("nfc")
 
 typedef void (*SeaderLoadingCallback)(void* context, bool state);
 

+ 1 - 0
seader/seader_i.h

@@ -52,6 +52,7 @@
 #include "seader.h"
 #include "ccid.h"
 #include "uart.h"
+#include "lrc.h"
 #include "seader_worker.h"
 #include "seader_credential.h"
 

+ 8 - 10
seader/seader_worker.c

@@ -6,16 +6,13 @@
 #define TAG "SeaderWorker"
 
 #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                                                    \
     (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)
 
-// TODO: const
-uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
-
 char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
 
 // Forward declaration
@@ -114,9 +111,7 @@ bool seader_process_success_response(Seader* seader, uint8_t* apdu, size_t len)
     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;
     SeaderUartBridge* seader_uart = seader_worker->uart;
     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++) {
         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 SW2 = apdu[len - 1];
+    uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
 
     switch(SW1) {
     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));
         return true;
         break;
-
     case 0x90:
         if(SW2 == 0x00) {
             if(len > 2) {
@@ -146,6 +141,9 @@ bool seader_worker_process_sam_message(Seader* seader, CCID_Message* message) {
             }
         }
         break;
+    default:
+        FURI_LOG_W(TAG, "Unknown SW %02x%02x", SW1, SW2);
+        break;
     }
 
     return false;

+ 1 - 1
seader/seader_worker.h

@@ -62,7 +62,7 @@ void seader_worker_start(
     void* context);
 
 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);
 
 NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void* context);

+ 1 - 1
seader/seader_worker_i.h

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

+ 2 - 2
seader/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_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_set_baudrate(seader_uart, seader_uart->cfg.baudrate);
@@ -162,7 +162,7 @@ SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) {
     memcpy(&(seader_uart->cfg_new), cfg, sizeof(SeaderUartConfig));
 
     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);
     return seader_uart;