mirror of
https://github.com/bettse/seader.git
synced 2026-03-30 14:15:56 +00:00
T=1 support
This commit is contained in:
82
ccid.c
82
ccid.c
@@ -63,23 +63,44 @@ void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
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;
|
||||
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);
|
||||
seader_uart->tx_buf[0] = SYNC;
|
||||
seader_uart->tx_buf[1] = CTRL;
|
||||
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 + 9] = 0;
|
||||
|
||||
seader_uart->tx_len = seader_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);
|
||||
}
|
||||
|
||||
@@ -121,14 +142,16 @@ void seader_ccid_XfrBlockToSlot(
|
||||
seader_uart->tx_buf[2 + 8] = 0;
|
||||
seader_uart->tx_buf[2 + 9] = 0;
|
||||
|
||||
memcpy(seader_uart->tx_buf + 2 + 10, data, len);
|
||||
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10 + 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_XfrBlock %d bytes: %s", seader_uart->tx_len, display);
|
||||
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);
|
||||
}
|
||||
@@ -319,10 +342,25 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
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(message.bSlot == sam_slot) {
|
||||
seader_worker_process_sam_message(seader, message.payload, message.dwLength);
|
||||
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 {
|
||||
FURI_LOG_D(TAG, "Discarding message on non-sam slot");
|
||||
}
|
||||
@@ -331,20 +369,18 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
FURI_LOG_I(TAG, "SAM ATR!");
|
||||
hasSAM = true;
|
||||
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) {
|
||||
FURI_LOG_I(TAG, "SAM ATR2!");
|
||||
hasSAM = true;
|
||||
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 {
|
||||
FURI_LOG_W(TAG, "Unknown ATR");
|
||||
if(seader_worker->callback) {
|
||||
@@ -353,7 +389,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Unhandled CCID message type %d", message.bMessageType);
|
||||
FURI_LOG_W(TAG, "Unhandled CCID message type %02x", message.bMessageType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
35
sam_api.c
35
sam_api.c
@@ -6,7 +6,6 @@
|
||||
|
||||
#define TAG "SAMAPI"
|
||||
|
||||
#define APDU_HEADER_LEN 5
|
||||
#define ASN1_PREFIX 6
|
||||
#define ASN1_DEBUG true
|
||||
#define SEADER_ICLASS_SR_SIO_BASE_BLOCK 10
|
||||
@@ -137,6 +136,7 @@ void seader_picopass_state_machine(Seader* seader, uint8_t* buffer, size_t len)
|
||||
bit_buffer_free(rx_buffer);
|
||||
}
|
||||
|
||||
uint8_t APDU_HEADER_LEN = 5;
|
||||
bool seader_send_apdu(
|
||||
Seader* seader,
|
||||
uint8_t CLA,
|
||||
@@ -144,12 +144,16 @@ bool seader_send_apdu(
|
||||
uint8_t P1,
|
||||
uint8_t P2,
|
||||
uint8_t* payload,
|
||||
uint8_t length) {
|
||||
uint8_t payloadLen) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -158,16 +162,30 @@ bool seader_send_apdu(
|
||||
apdu[1] = INS;
|
||||
apdu[2] = P1;
|
||||
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));
|
||||
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]);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -629,6 +647,7 @@ void seader_iso15693_transmit(
|
||||
uint8_t* buffer,
|
||||
size_t len) {
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
|
||||
BitBuffer* tx_buffer = bit_buffer_alloc(len);
|
||||
BitBuffer* rx_buffer = bit_buffer_alloc(SEADER_POLLER_MAX_BUFFER_SIZE);
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ struct SeaderUartBridge {
|
||||
uint8_t rx_buf[SEADER_UART_RX_BUF_SIZE];
|
||||
uint8_t tx_buf[SEADER_UART_RX_BUF_SIZE];
|
||||
size_t tx_len;
|
||||
|
||||
// T=0 or T=1
|
||||
uint8_t T;
|
||||
};
|
||||
|
||||
typedef struct SeaderUartBridge SeaderUartBridge;
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "ccid.h"
|
||||
#include "uart.h"
|
||||
#include "lrc.h"
|
||||
#include "t_1.h"
|
||||
#include "seader_worker.h"
|
||||
#include "seader_credential.h"
|
||||
|
||||
|
||||
231
t_1.c
Normal file
231
t_1.c
Normal file
@@ -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
t_1.h
Normal file
9
t_1.h
Normal file
@@ -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);
|
||||
3
uart.c
3
uart.c
@@ -159,6 +159,9 @@ int32_t seader_uart_worker(void* context) {
|
||||
SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) {
|
||||
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));
|
||||
|
||||
seader_uart->thread =
|
||||
|
||||
Reference in New Issue
Block a user