1 |
3ee3c4a6
|
henryk
|
/***************************************************************
|
2 |
|
|
*
|
3 |
|
|
* OpenPICC - T/C based dumb sniffer
|
4 |
|
|
*
|
5 |
|
|
* TC2 will reset its value on each falling edge of SSC_DATA, we
|
6 |
|
|
* will have the FIQ store the TC2 value on each rising edge of
|
7 |
|
|
* SSC_DATA. This will give us a count of carrier cycles between
|
8 |
|
|
* modulation pauses which should be enough information to decode
|
9 |
|
|
* the modified miller encoding.
|
10 |
|
|
*
|
11 |
|
|
* Copyright 2008 Henryk Plötz <henryk@ploetzli.ch>
|
12 |
|
|
*
|
13 |
|
|
***************************************************************
|
14 |
|
|
|
15 |
|
|
This program is free software; you can redistribute it and/or modify
|
16 |
|
|
it under the terms of the GNU General Public License as published by
|
17 |
|
|
the Free Software Foundation; version 2.
|
18 |
|
|
|
19 |
|
|
This program is distributed in the hope that it will be useful,
|
20 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
21 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
22 |
|
|
GNU General Public License for more details.
|
23 |
|
|
|
24 |
|
|
You should have received a copy of the GNU General Public License along
|
25 |
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
26 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
27 |
|
|
|
28 |
|
|
*/
|
29 |
|
|
|
30 |
|
|
#include <FreeRTOS.h>
|
31 |
|
|
#include <openpicc.h>
|
32 |
|
|
#include <task.h>
|
33 |
9cde1dd0
|
henryk
|
#include <semphr.h>
|
34 |
3ee3c4a6
|
henryk
|
#include <string.h>
|
35 |
|
|
|
36 |
|
|
#include <USB-CDC.h>
|
37 |
|
|
|
38 |
|
|
#include "tc_sniffer.h"
|
39 |
|
|
#include "load_modulation.h"
|
40 |
|
|
#include "pll.h"
|
41 |
|
|
#include "tc_fdt.h"
|
42 |
|
|
#include "usb_print.h"
|
43 |
|
|
#include "cmd.h"
|
44 |
|
|
#include "pio_irq.h"
|
45 |
6304718e
|
henryk
|
#include "led.h"
|
46 |
|
|
#include "clock_switch.h"
|
47 |
9cde1dd0
|
henryk
|
#include "performance.h"
|
48 |
6304718e
|
henryk
|
|
49 |
|
|
#include "iso14443a_diffmiller.h"
|
50 |
3ee3c4a6
|
henryk
|
|
51 |
|
|
/* Problem: We want to receive data from the FIQ without locking (the FIQ must not be blocked ever)
|
52 |
|
|
* Strategy: Double buffering.
|
53 |
|
|
*/
|
54 |
|
|
|
55 |
9cde1dd0
|
henryk
|
static xSemaphoreHandle data_semaphore;
|
56 |
6304718e
|
henryk
|
struct diffmiller_state *decoder;
|
57 |
|
|
iso14443_frame rx_frame;
|
58 |
|
|
|
59 |
3ee3c4a6
|
henryk
|
#define WAIT_TICKS (20*portTICK_RATE_MS)
|
60 |
|
|
|
61 |
|
|
portBASE_TYPE currently_sniffing = 0;
|
62 |
6304718e
|
henryk
|
enum { NONE, REQUEST_START, REQUEST_STOP } request_change = REQUEST_START;
|
63 |
|
|
|
64 |
|
|
//#define PRINT_TIMES
|
65 |
|
|
//#define USE_BINARY_PROTOCOL
|
66 |
3ee3c4a6
|
henryk
|
|
67 |
|
|
#define MIN(a, b) ((a)>(b)?(b):(a))
|
68 |
6304718e
|
henryk
|
static int overruns = 0;
|
69 |
9cde1dd0
|
henryk
|
static void handle_buffer(u_int32_t data[], unsigned int count)
|
70 |
3ee3c4a6
|
henryk
|
{
|
71 |
6304718e
|
henryk
|
#ifdef USE_BINARY_PROTOCOL
|
72 |
9cde1dd0
|
henryk
|
vUSBSendBuffer_blocking((unsigned char*)(&data[0]), 0, MIN(count,BUFSIZE)*4, WAIT_TICKS);
|
73 |
|
|
if(count >= BUFSIZE)
|
74 |
3ee3c4a6
|
henryk
|
vUSBSendBuffer_blocking((unsigned char*)"////", 0, 4, WAIT_TICKS);
|
75 |
|
|
else
|
76 |
|
|
vUSBSendBuffer_blocking((unsigned char*)"____", 0, 4, WAIT_TICKS);
|
77 |
6304718e
|
henryk
|
#elif defined(PRINT_TIMES)
|
78 |
|
|
unsigned int i=0;
|
79 |
9cde1dd0
|
henryk
|
for(i=0; i<count; i++) {
|
80 |
|
|
DumpUIntToUSB(data[i]);
|
81 |
6304718e
|
henryk
|
DumpStringToUSB(" ");
|
82 |
|
|
}
|
83 |
|
|
DumpStringToUSB("\n\r");
|
84 |
|
|
#else
|
85 |
|
|
unsigned int offset = 0;
|
86 |
9cde1dd0
|
henryk
|
while(offset < count) {
|
87 |
|
|
int ret = iso14443a_decode_diffmiller(decoder, &rx_frame, data, &offset, count);
|
88 |
|
|
/*
|
89 |
6304718e
|
henryk
|
DumpStringToUSB("\n\r");
|
90 |
|
|
if(ret < 0) {
|
91 |
|
|
DumpStringToUSB("-");
|
92 |
|
|
DumpUIntToUSB(-ret);
|
93 |
|
|
} else {
|
94 |
|
|
DumpUIntToUSB(ret);
|
95 |
|
|
}
|
96 |
|
|
DumpStringToUSB(" ");
|
97 |
9cde1dd0
|
henryk
|
DumpUIntToUSB(offset); DumpStringToUSB(" "); DumpUIntToUSB(count); DumpStringToUSB(" "); DumpUIntToUSB(overruns);
|
98 |
6304718e
|
henryk
|
DumpStringToUSB("\n\r");
|
99 |
|
|
if(ret >= 0) {
|
100 |
|
|
DumpStringToUSB("Frame finished, ");
|
101 |
|
|
DumpUIntToUSB(rx_frame.numbytes);
|
102 |
|
|
DumpStringToUSB(" bytes, ");
|
103 |
|
|
DumpUIntToUSB(rx_frame.numbits);
|
104 |
|
|
DumpStringToUSB(" bits\n\r");
|
105 |
|
|
switch(rx_frame.parameters.a.crc) {
|
106 |
|
|
case CRC_OK: DumpStringToUSB("CRC OK\n\r"); break;
|
107 |
|
|
case CRC_ERROR: DumpStringToUSB("CRC ERROR\n\r"); break;
|
108 |
|
|
case CRC_UNCALCULATED: DumpStringToUSB("CRC UNCALCULATED\n\r"); break;
|
109 |
|
|
}
|
110 |
9cde1dd0
|
henryk
|
}*/
|
111 |
|
|
(void)ret;
|
112 |
6304718e
|
henryk
|
}
|
113 |
|
|
#endif
|
114 |
9cde1dd0
|
henryk
|
}
|
115 |
|
|
|
116 |
|
|
void flush_buffer(fiq_buffer_t *buffer)
|
117 |
|
|
{
|
118 |
|
|
/* Write all data from the given buffer out, then zero the count */
|
119 |
|
|
if(buffer->count > 0) {
|
120 |
|
|
if(buffer->count >= BUFSIZE) {
|
121 |
|
|
DumpStringToUSB("Warning: Possible buffer overrun detected\n\r");
|
122 |
|
|
overruns++;
|
123 |
|
|
}
|
124 |
|
|
buffer->count = MIN(buffer->count, BUFSIZE);
|
125 |
|
|
handle_buffer(buffer->data, buffer->count);
|
126 |
3ee3c4a6
|
henryk
|
buffer->count = 0;
|
127 |
|
|
}
|
128 |
|
|
}
|
129 |
|
|
|
130 |
|
|
void start_stop_sniffing(void)
|
131 |
|
|
{
|
132 |
|
|
if(currently_sniffing)
|
133 |
|
|
request_change = REQUEST_STOP;
|
134 |
|
|
else
|
135 |
|
|
request_change = REQUEST_START;
|
136 |
|
|
}
|
137 |
|
|
|
138 |
9cde1dd0
|
henryk
|
static portBASE_TYPE tc_sniffer_irq(u_int32_t pio, portBASE_TYPE xTaskWoken)
|
139 |
|
|
{
|
140 |
|
|
(void)pio;
|
141 |
|
|
usb_print_string_f("?", 0);
|
142 |
|
|
xTaskWoken = xSemaphoreGiveFromISR(data_semaphore, xTaskWoken);
|
143 |
|
|
return xTaskWoken;
|
144 |
|
|
}
|
145 |
|
|
|
146 |
|
|
static void main_loop(void)
|
147 |
|
|
{
|
148 |
|
|
int current = 0;
|
149 |
|
|
|
150 |
|
|
while(1) {
|
151 |
|
|
/* Main loop of the sniffer */
|
152 |
|
|
//vTaskDelay(1000 * portTICK_RATE_MS);
|
153 |
|
|
|
154 |
|
|
u_int32_t start = *AT91C_TC2_CV;
|
155 |
|
|
int next = (current+1)%(sizeof(fiq_buffers)/sizeof(fiq_buffers[0]));
|
156 |
|
|
flush_buffer( &fiq_buffers[next] );
|
157 |
|
|
/* The buffer designated by next is now empty, give it to the fiq,
|
158 |
|
|
* we'll just guess that this write is atomic */
|
159 |
|
|
tc_sniffer_next_buffer_for_fiq = &fiq_buffers[current=next];
|
160 |
|
|
u_int32_t stop = *AT91C_TC2_CV;
|
161 |
|
|
|
162 |
|
|
DumpStringToUSB("{"); DumpUIntToUSB(start); DumpStringToUSB(":"); DumpUIntToUSB(stop); DumpStringToUSB("}");
|
163 |
|
|
if(*AT91C_TC2_CV > 2*128) {
|
164 |
|
|
u_int32_t dummybuf[1] = {*AT91C_TC2_CV};
|
165 |
|
|
handle_buffer(dummybuf, 1);
|
166 |
|
|
|
167 |
|
|
usb_print_string_f("[", 0);
|
168 |
|
|
while(xSemaphoreTake(data_semaphore, portMAX_DELAY) == pdFALSE) ;
|
169 |
|
|
usb_print_string_f("]", 0);
|
170 |
|
|
}
|
171 |
|
|
}
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
static u_int32_t testdata[] = {65535, 75, 138, 75, 138, 139, 139, 300};
|
175 |
|
|
static u_int32_t testdata2[] = {65535, 80, 144, 208, 208, 208, 80, 80, 208, 208, 208, 208, 80, 144, 80, 144, 144, 80, 144, 208, 81, 80, 80, 81, 80, 81, 209, 209, 209, 80, 81, 145, 81, 300};
|
176 |
|
|
|
177 |
|
|
static void timing_loop(void)
|
178 |
|
|
{
|
179 |
|
|
while(1) {
|
180 |
|
|
vTaskDelay(5000*portTICK_RATE_MS);
|
181 |
|
|
performance_start();
|
182 |
|
|
handle_buffer(testdata, sizeof(testdata)/sizeof(testdata[0]));
|
183 |
|
|
performance_set_checkpoint("end of first buffer");
|
184 |
|
|
handle_buffer(testdata2, sizeof(testdata2)/sizeof(testdata2[0]));
|
185 |
|
|
performance_stop_report();
|
186 |
7f0e2816
|
henryk
|
DumpStringToUSB("Produced frame of "); DumpUIntToUSB(rx_frame.numbytes);
|
187 |
|
|
DumpStringToUSB(" bytes and "); DumpUIntToUSB(rx_frame.numbits);
|
188 |
|
|
DumpStringToUSB(" bits: "); DumpBufferToUSB((char*)rx_frame.data, rx_frame.numbytes + (rx_frame.numbits+7)/8 );
|
189 |
|
|
DumpStringToUSB(" CRC "); if(rx_frame.parameters.a.crc) DumpStringToUSB("OK"); else DumpStringToUSB("ERROR");
|
190 |
|
|
DumpStringToUSB("\n\r");
|
191 |
9cde1dd0
|
henryk
|
}
|
192 |
|
|
}
|
193 |
|
|
|
194 |
3ee3c4a6
|
henryk
|
void tc_sniffer (void *pvParameters)
|
195 |
|
|
{
|
196 |
|
|
(void)pvParameters;
|
197 |
|
|
/* Disable load modulation circuitry
|
198 |
|
|
* (Must be done explicitly, because the default state is pull-up high, leading
|
199 |
|
|
* to a constant modulation output which prevents reception. I've been bitten by
|
200 |
|
|
* this more than once.)
|
201 |
|
|
*/
|
202 |
|
|
load_mod_init();
|
203 |
|
|
load_mod_level(0);
|
204 |
|
|
|
205 |
6304718e
|
henryk
|
clock_switch_init();
|
206 |
|
|
|
207 |
3ee3c4a6
|
henryk
|
pll_init();
|
208 |
|
|
pll_inhibit(0);
|
209 |
|
|
|
210 |
|
|
tc_fdt_init();
|
211 |
|
|
|
212 |
|
|
memset(fiq_buffers, 0, sizeof(fiq_buffers));
|
213 |
|
|
|
214 |
|
|
/* Wait for the USB and CMD threads to start up */
|
215 |
|
|
vTaskDelay(1000 * portTICK_RATE_MS);
|
216 |
|
|
|
217 |
6304718e
|
henryk
|
if(OPENPICC->features.clock_switching) {
|
218 |
|
|
clock_switch(CLOCK_SELECT_CARRIER);
|
219 |
|
|
decoder = iso14443a_init_diffmiller(0);
|
220 |
|
|
} else {
|
221 |
|
|
switch(OPENPICC->default_clock) {
|
222 |
|
|
case CLOCK_SELECT_CARRIER:
|
223 |
|
|
decoder = iso14443a_init_diffmiller(0);
|
224 |
|
|
break;
|
225 |
|
|
case CLOCK_SELECT_PLL:
|
226 |
|
|
decoder = iso14443a_init_diffmiller(1);
|
227 |
|
|
break;
|
228 |
|
|
}
|
229 |
|
|
}
|
230 |
|
|
|
231 |
|
|
if(!decoder) vLedHaltBlinking(1);
|
232 |
9cde1dd0
|
henryk
|
vSemaphoreCreateBinary(data_semaphore);
|
233 |
|
|
if(data_semaphore == NULL) vLedHaltBlinking(3);
|
234 |
6304718e
|
henryk
|
|
235 |
3ee3c4a6
|
henryk
|
// The change interrupt is going to be handled by the FIQ
|
236 |
|
|
AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_DATA);
|
237 |
9cde1dd0
|
henryk
|
if( pio_irq_register(OPENPICC_SSC_DATA, &tc_sniffer_irq) < 0)
|
238 |
|
|
vLedHaltBlinking(2);
|
239 |
3ee3c4a6
|
henryk
|
pio_irq_enable(OPENPICC_SSC_DATA);
|
240 |
|
|
|
241 |
9cde1dd0
|
henryk
|
//main_loop();
|
242 |
|
|
timing_loop();
|
243 |
|
|
|
244 |
|
|
(void)main_loop; (void)timing_loop;
|
245 |
3ee3c4a6
|
henryk
|
}
|