summaryrefslogtreecommitdiff
path: root/openpicc/application
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc/application')
-rw-r--r--openpicc/application/iso14443_layer3a.c51
-rw-r--r--openpicc/application/iso14443_layer3a.h14
-rw-r--r--openpicc/application/ssc_picc.c13
3 files changed, 68 insertions, 10 deletions
diff --git a/openpicc/application/iso14443_layer3a.c b/openpicc/application/iso14443_layer3a.c
index af0fc69..c1f7bce 100644
--- a/openpicc/application/iso14443_layer3a.c
+++ b/openpicc/application/iso14443_layer3a.c
@@ -61,6 +61,8 @@ const iso14443_frame NULL_FRAME = {
{}
};
+const u_int8_t ISO14443A_SHORT_FRAME_REQA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH] = _ISO14443A_SHORT_FRAME_REQA;
+const u_int8_t ISO14443A_SHORT_FRAME_WUPA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH] = _ISO14443A_SHORT_FRAME_WUPA;
#define PLL_LOCK_HYSTERESIS portTICK_RATE_MS*5
@@ -106,6 +108,28 @@ void iso14443_transmit(ssc_dma_tx_buffer_t *buf, int fdt, int div)
ssc_tx_start(buf);
}
+static void _is_reqa_or_wupa(enum ssc_mode ssc_mode, u_int8_t* samples, int *is_reqa, int *is_wupa)
+{
+ if(ssc_mode == SSC_MODE_14443A_SHORT) {
+ *is_reqa = *is_wupa = 0;
+ ISO14443A_SHORT_TYPE sample = *(ISO14443A_SHORT_TYPE*)samples;
+ if(sample == REQA) {
+ *is_reqa = 1;
+ } else if(sample == WUPA) {
+ *is_wupa = 1;
+ }
+ } else if(ssc_mode == SSC_MODE_14443A) {
+ int i;
+ *is_reqa = *is_wupa = 1;
+ for(i=0; i<ISO14443A_SHORT_FRAME_COMPARE_LENGTH; i++) {
+ if(samples[i] != ISO14443A_SHORT_FRAME_REQA[i]) is_reqa = 0;
+ if(samples[i] != ISO14443A_SHORT_FRAME_WUPA[i]) is_wupa = 0;
+ }
+ } else {
+ *is_reqa = *is_wupa = 0;
+ }
+}
+
static int atqa_sent = 0;
/* Running in ISR mode */
void __ramfunc iso14443_layer3a_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode, u_int8_t* samples)
@@ -113,13 +137,15 @@ void __ramfunc iso14443_layer3a_irq_ext(u_int32_t ssc_sr, enum ssc_mode ssc_mode
(void)ssc_sr;
int fdt;
if((ssc_mode == SSC_MODE_14443A_SHORT || ssc_mode == SSC_MODE_14443A) && samples) {
- ISO14443A_SHORT_TYPE sample = *(ISO14443A_SHORT_TYPE*)samples;
- portBASE_TYPE send_atqa = 0;
- if(sample == REQA) {
+ int is_reqa, is_wupa;
+ _is_reqa_or_wupa(ssc_mode, samples, &is_reqa, &is_wupa);
+ portBASE_TYPE send_atqa = is_reqa || is_wupa;
+
+ if(is_reqa) {
fdt = ISO14443A_FDT_SHORT_0;
if(state == IDLE)
send_atqa = 1;
- } else if(sample == WUPA) {
+ } else if(is_wupa) {
fdt = ISO14443A_FDT_SHORT_1;
if(state == IDLE || state == HALT)
send_atqa = 1;
@@ -316,7 +342,11 @@ void iso14443_layer3a_state_machine (void *pvParameters)
DumpStringToUSB("] ");
DumpBufferToUSB((char*)buffer->data, (buffer->len_transfers * buffer->reception_mode->transfersize_pdc)/8);
DumpStringToUSB(" Decoded: ");
+ vLedBlinkGreen();
+ vLedSetGreen(1);
iso14443a_decode_miller(&received_frame, buffer);
+ vLedBlinkGreen();
+ vLedSetGreen(0);
DumpBufferToUSB((char*)received_frame.data, received_frame.numbytes + (received_frame.numbits+7)/8);
DumpStringToUSB(" ");
DumpUIntToUSB(received_frame.parameters.a.last_bit);
@@ -324,13 +354,16 @@ void iso14443_layer3a_state_machine (void *pvParameters)
usb_print_set_default_flush(i);
}
+ int is_reqa=0, is_wupa=0;
switch(state) {
case IDLE:
case HALT:
- if(first_sample == WUPA || (state==IDLE && first_sample==REQA)) {
+ if(buffer->data) _is_reqa_or_wupa(buffer->reception_mode->mode, buffer->data, &is_reqa, &is_wupa);
+
+ if(is_wupa || (state==IDLE && is_reqa)) {
/* Need to transmit ATQA */
LAYER3_DEBUG("Received ");
- LAYER3_DEBUG(first_sample == WUPA ? "WUPA" : "REQA");
+ LAYER3_DEBUG(is_wupa ? "WUPA" : "REQA");
if(atqa_sent) {
LAYER3_DEBUG(", woke up to send ATQA\n\r");
atqa_sent = 0;
@@ -358,7 +391,11 @@ void iso14443_layer3a_state_machine (void *pvParameters)
if(prefill_buffer(&ssc_tx_buffer, &NULL_FRAME)) {
usb_print_string_f("Sending response ...",0);
ssc_tx_buffer.state = PROCESSING;
- iso14443_transmit(&ssc_tx_buffer, ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1, 8);
+ iso14443_transmit(&ssc_tx_buffer,
+ received_frame.parameters.a.last_bit==ISO14443A_LAST_BIT_0 ?
+ ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_0 :
+ ISO14443A_TRANSMIT_AT_NEXT_INTERVAL_1,
+ 8);
while( ssc_tx_buffer.state != FREE ) {
vTaskDelay(portTICK_RATE_MS);
}
diff --git a/openpicc/application/iso14443_layer3a.h b/openpicc/application/iso14443_layer3a.h
index 8925249..42a37bc 100644
--- a/openpicc/application/iso14443_layer3a.h
+++ b/openpicc/application/iso14443_layer3a.h
@@ -42,18 +42,30 @@ enum ISO14443_STATES {
/* definitions for two-times oversampling */
#define ISO14443A_SAMPLE_LEN 2
+/* For SSC_MODE_ISO14443A_SHORT */
+#define ISO14443A_SHORT_LEN 18
#define REQA 0x4929
#define WUPA 0x2249
#define ISO14443A_SOF_SAMPLE 0x01
#define ISO14443A_SOF_LEN 2
-#define ISO14443A_SHORT_LEN 18
#define ISO14443A_EOF_SAMPLE 0x00
#define ISO14443A_EOF_LEN 5
+/* For SSC_MODE_ISO14443A */
+#define ISO14443A_SHORT_FRAME_COMPARE_LENGTH 2
+#define _ISO14443A_SHORT_FRAME_REQA { 0x29, 0x49 }
+#define _ISO14443A_SHORT_FRAME_WUPA { 0x49, 0x22 }
+// FIXME not correct. This should be compare_length == 3 (which is 9 at 4 per compare), but this
+// needs enhanced ssc irq code to transfer the last read (incomplete) data from the ssc holding
+// register to the buffer
+
#endif
+extern const u_int8_t ISO14443A_SHORT_FRAME_REQA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH];
+extern const u_int8_t ISO14443A_SHORT_FRAME_WUPA[ISO14443A_SHORT_FRAME_COMPARE_LENGTH];
+
/* A short frame should be received in one single SSC transfer */
#if (ISO14443A_SHORT_LEN <= 8)
/* SSC transfer size in bits */
diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c
index e5d2085..79df04e 100644
--- a/openpicc/application/ssc_picc.c
+++ b/openpicc/application/ssc_picc.c
@@ -56,6 +56,7 @@
#define DEBUGR(x, args ...)
#endif
+#define DEBUG_LOAD_AND_UNLOAD 0
static const AT91PS_SSC ssc = AT91C_BASE_SSC;
static AT91PS_PDC rx_pdc;
@@ -79,7 +80,10 @@ static const ssc_mode_def ssc_sizes[] = {
/* 14443A Standard Frame: FIXME 16 transfers of 32 bits (maximum number), resulting in 512 samples */
[SSC_MODE_14443A_STANDARD] = {SSC_MODE_14443A_STANDARD, 32, 32, 16},
/* 14443A Frame, don't care if standard or short */
- [SSC_MODE_14443A] = {SSC_MODE_14443A, ISO14443A_SAMPLE_LEN, 8, ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS},
+ [SSC_MODE_14443A] = {SSC_MODE_14443A,
+ 4 * ISO14443A_SAMPLE_LEN, // transfersize_ssc
+ 4 * ISO14443A_SAMPLE_LEN <= 8 ? 8 : 16, // transfersize_pdc
+ ISO14443A_MAX_RX_FRAME_SIZE_IN_BITS},
[SSC_MODE_14443B] = {SSC_MODE_14443B, 32, 32, 16}, /* 64 bytes */
[SSC_MODE_EDGE_ONE_SHOT] = {SSC_MODE_EDGE_ONE_SHOT, 32, 32, 16}, /* 64 bytes */
[SSC_MODE_CONTINUOUS] = {SSC_MODE_CONTINUOUS, 32, 32, 511}, /* 2044 bytes */
@@ -178,6 +182,7 @@ static int __ramfunc __ssc_rx_load(int secondary)
ssc_state.buffer[0] = buffer;
}
+ if(DEBUG_LOAD_AND_UNLOAD) {
if(secondary) {int i=usb_print_set_default_flush(0);
DumpStringToUSB("{1:");
DumpUIntToUSB(rx_pdc->PDC_RNCR);
@@ -192,6 +197,7 @@ static int __ramfunc __ssc_rx_load(int secondary)
DumpUIntToUSB(rx_pdc->PDC_RPR);
DumpStringToUSB("} ");
usb_print_set_default_flush(i);}
+ }
return 0;
}
@@ -215,6 +221,7 @@ static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary)
ssc_dma_rx_buffer_t *buffer = ssc_state.buffer[secondary];
if(buffer == NULL) return NULL;
+ if(DEBUG_LOAD_AND_UNLOAD) {
if(secondary) {int i=usb_print_set_default_flush(0);
DumpStringToUSB("(1:");
DumpUIntToUSB(rx_pdc->PDC_RNCR);
@@ -229,6 +236,7 @@ static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary)
DumpUIntToUSB(rx_pdc->PDC_RPR);
DumpStringToUSB(") ");
usb_print_set_default_flush(i);}
+ }
u_int16_t remaining_transfers = (secondary ? rx_pdc->PDC_RNCR : rx_pdc->PDC_RCR);
u_int8_t* next_transfer_location = (u_int8_t*)(secondary ? rx_pdc->PDC_RNPR : rx_pdc->PDC_RPR);
@@ -264,6 +272,7 @@ static ssc_dma_rx_buffer_t* __ramfunc __ssc_rx_unload(int secondary)
}
if(buffer->state == PENDING || buffer->state==FULL) {
buffer->len_transfers = elapsed_transfers;
+ if(DEBUG_LOAD_AND_UNLOAD)
{int i=usb_print_set_default_flush(0);
DumpStringToUSB("<");
DumpUIntToUSB((unsigned int)buffer);
@@ -329,7 +338,7 @@ void ssc_rx_mode_set(enum ssc_mode ssc_mode)
sync_len = ISO14443A_EOF_LEN;
ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE << (ISO14443A_EOF_LEN-ISO14443A_SOF_LEN);
ssc->SSC_RC1R = ISO14443A_EOF_SAMPLE;
- data_len = ISO14443A_SAMPLE_LEN;
+ data_len = ssc_sizes[SSC_MODE_14443A].transfersize_ssc;
num_data = 16; /* Start with 16, then switch to continuous in the IRQ handler */
stop = 1; /* Actually the documentation indicates that setting STOP makes switching to continuous unnecessary */
clock_gating = (0x0 << 6);
personal git repositories of Harald Welte. Your mileage may vary