1
|
#include <AT91SAM7.h>
|
2
|
#include <FreeRTOS.h>
|
3
|
#include <task.h>
|
4
|
#include <semphr.h>
|
5
|
#include <queue.h>
|
6
|
#include <USB-CDC.h>
|
7
|
#include <board.h>
|
8
|
#include <compile.h>
|
9
|
#include <string.h>
|
10
|
|
11
|
#include "env.h"
|
12
|
#include "cmd.h"
|
13
|
#include "openpicc.h"
|
14
|
#include "led.h"
|
15
|
#include "da.h"
|
16
|
#include "adc.h"
|
17
|
#include "pll.h"
|
18
|
#include "tc_cdiv.h"
|
19
|
#include "tc_cdiv_sync.h"
|
20
|
#include "pio_irq.h"
|
21
|
#include "ssc.h"
|
22
|
#include "clock_switch.h"
|
23
|
#include "usb_print.h"
|
24
|
#include "load_modulation.h"
|
25
|
#include "tc_sniffer.h"
|
26
|
#include "iso14443a_pretender.h"
|
27
|
|
28
|
xQueueHandle xCmdQueue;
|
29
|
xTaskHandle xCmdTask;
|
30
|
xTaskHandle xCmdRecvUsbTask;
|
31
|
xTaskHandle xFieldMeterTask;
|
32
|
xSemaphoreHandle xFieldMeterMutex;
|
33
|
|
34
|
volatile int fdt_offset=-20 -16; // -16 for the SSC Tx set to continous bug
|
35
|
volatile int load_mod_level_set=3;
|
36
|
|
37
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
38
|
static signed portCHAR pcWriteBuffer[512];
|
39
|
#endif
|
40
|
|
41
|
/* Whether to require a colon (':') be typed before long commands, similar to e.g. vi
|
42
|
* This makes a distinction between long commands and short commands: long commands may be
|
43
|
* longer than one character and/or accept optional parameters, short commands are only one
|
44
|
* character with no arguments (typically some toggling command). Short commands execute
|
45
|
* immediately when the character is pressed, long commands must be completed with return.
|
46
|
* */
|
47
|
static const portBASE_TYPE USE_COLON_FOR_LONG_COMMANDS = 0;
|
48
|
/* When not USE_COLON_FOR_LONG_COMMANDS then short commands will be recognized by including
|
49
|
* their character in the string SHORT_COMMANDS
|
50
|
* */
|
51
|
static const char *SHORT_COMMANDS = "!prc+-l?hq9fjka#i";
|
52
|
/* Note that the long/short command distinction only applies to the USB serial console
|
53
|
* */
|
54
|
|
55
|
/**********************************************************************/
|
56
|
void DumpUIntToUSB(unsigned int data)
|
57
|
{
|
58
|
int i=0;
|
59
|
unsigned char buffer[10],*p=&buffer[sizeof(buffer)];
|
60
|
|
61
|
do {
|
62
|
*--p='0'+(unsigned char)(data%10);
|
63
|
data/=10;
|
64
|
i++;
|
65
|
} while(data);
|
66
|
|
67
|
while(i--)
|
68
|
usb_print_char(*p++);
|
69
|
}
|
70
|
/**********************************************************************/
|
71
|
|
72
|
void DumpStringToUSB(const char* text)
|
73
|
{
|
74
|
usb_print_string(text);
|
75
|
}
|
76
|
/**********************************************************************/
|
77
|
|
78
|
static inline unsigned char HexChar(unsigned char nibble)
|
79
|
{
|
80
|
return nibble + ((nibble<0x0A) ? '0':('A'-0xA));
|
81
|
}
|
82
|
|
83
|
void DumpBufferToUSB(char* buffer, int len)
|
84
|
{
|
85
|
int i;
|
86
|
|
87
|
for(i=0; i<len; i++) {
|
88
|
usb_print_char(HexChar( *buffer >> 4));
|
89
|
usb_print_char(HexChar( *buffer++ & 0xf));
|
90
|
}
|
91
|
}
|
92
|
/**********************************************************************/
|
93
|
|
94
|
void DumpTimeToUSB(long ticks)
|
95
|
{
|
96
|
int h, s, m, ms;
|
97
|
ms = ticks;
|
98
|
|
99
|
s=ms/1000;
|
100
|
ms%=1000;
|
101
|
h=s/3600;
|
102
|
s%=3600;
|
103
|
m=s/60;
|
104
|
s%=60;
|
105
|
DumpUIntToUSB(h);
|
106
|
DumpStringToUSB("h:");
|
107
|
if(m < 10) DumpStringToUSB("0");
|
108
|
DumpUIntToUSB(m);
|
109
|
DumpStringToUSB("m:");
|
110
|
if(s < 10) DumpStringToUSB("0");
|
111
|
DumpUIntToUSB(s);
|
112
|
DumpStringToUSB("s.");
|
113
|
if(ms < 10) DumpStringToUSB("0");
|
114
|
if(ms < 100) DumpStringToUSB("0");
|
115
|
DumpUIntToUSB(ms);
|
116
|
DumpStringToUSB("ms");
|
117
|
}
|
118
|
|
119
|
/*
|
120
|
* Convert a string to an integer. Ignores leading spaces.
|
121
|
* Optionally returns a pointer to the end of the number in the string */
|
122
|
int atoiEx(const char * nptr, char * * eptr)
|
123
|
{
|
124
|
portBASE_TYPE sign = 1, i=0;
|
125
|
int curval = 0;
|
126
|
while(nptr[i] == ' ' && nptr[i] != 0) i++;
|
127
|
if(nptr[i] == 0) goto out;
|
128
|
if(nptr[i] == '-') {sign *= -1; i++; }
|
129
|
else if(nptr[i] == '+') { i++; }
|
130
|
while(nptr[i] != 0 && nptr[i] >= '0' && nptr[i] <= '9')
|
131
|
curval = curval * 10 + (nptr[i++] - '0');
|
132
|
|
133
|
out:
|
134
|
if(eptr != NULL) *eptr = (char*)nptr+i;
|
135
|
return sign * curval;
|
136
|
}
|
137
|
|
138
|
/* Common code between increment/decrement UID/nonce */
|
139
|
static int change_value( int(* const getter)(u_int8_t*, size_t), int(* const setter)(u_int8_t*, size_t),
|
140
|
const s_int32_t increment, const char *name )
|
141
|
{
|
142
|
u_int8_t uid[4];
|
143
|
int ret;
|
144
|
if( getter(uid, sizeof(uid)) >= 0) {
|
145
|
(*((u_int32_t*)uid)) += increment;
|
146
|
taskENTER_CRITICAL();
|
147
|
ret = setter(uid, sizeof(uid));
|
148
|
taskEXIT_CRITICAL();
|
149
|
if(ret < 0) {
|
150
|
DumpStringToUSB("Failed to set the ");
|
151
|
DumpStringToUSB(name);
|
152
|
DumpStringToUSB("\n\r");
|
153
|
} else {
|
154
|
DumpStringToUSB("Successfully set ");
|
155
|
DumpStringToUSB(name);
|
156
|
DumpStringToUSB(" to ");
|
157
|
DumpBufferToUSB((char*)uid, sizeof(uid));
|
158
|
DumpStringToUSB("\n\r");
|
159
|
}
|
160
|
} else {
|
161
|
DumpStringToUSB("Couldn't get ");
|
162
|
DumpStringToUSB(name);
|
163
|
DumpStringToUSB("\n\r");
|
164
|
ret = -1;
|
165
|
}
|
166
|
return ret;
|
167
|
}
|
168
|
|
169
|
#define DYNAMIC_PIN_PLL_LOCK 1
|
170
|
static struct { int pin; int dynpin; char * description; } PIO_PINS[] = {
|
171
|
{0,DYNAMIC_PIN_PLL_LOCK, "pll lock "},
|
172
|
{OPENPICC_PIO_FRAME,0, "frame start"},
|
173
|
};
|
174
|
void print_pio(void)
|
175
|
{
|
176
|
int data = *AT91C_PIOA_PDSR;
|
177
|
unsigned int i;
|
178
|
DumpStringToUSB(
|
179
|
" *****************************************************\n\r"
|
180
|
" * Current PIO readings: *\n\r"
|
181
|
" *****************************************************\n\r"
|
182
|
" *\n\r");
|
183
|
for(i=0; i<sizeof(PIO_PINS)/sizeof(PIO_PINS[0]); i++) {
|
184
|
if(PIO_PINS[i].dynpin != 0) continue;
|
185
|
DumpStringToUSB(" * ");
|
186
|
DumpStringToUSB(PIO_PINS[i].description);
|
187
|
DumpStringToUSB(": ");
|
188
|
DumpUIntToUSB((data & PIO_PINS[i].pin) ? 1 : 0 );
|
189
|
DumpStringToUSB("\n\r");
|
190
|
}
|
191
|
DumpStringToUSB(" *****************************************************\n\r");
|
192
|
}
|
193
|
|
194
|
|
195
|
static const AT91PS_SPI spi = AT91C_BASE_SPI;
|
196
|
#define SPI_MAX_XFER_LEN 33
|
197
|
|
198
|
static int clock_select=0;
|
199
|
void startstop_field_meter(void);
|
200
|
extern volatile unsigned portLONG ulCriticalNesting;
|
201
|
void prvExecCommand(u_int32_t cmd, portCHAR *args) {
|
202
|
static int led = 0;
|
203
|
portCHAR cByte = cmd & 0xff;
|
204
|
int i,ms;
|
205
|
if(cByte>='A' && cByte<='Z')
|
206
|
cByte-=('A'-'a');
|
207
|
|
208
|
DumpStringToUSB("Got command ");
|
209
|
DumpUIntToUSB(cmd);
|
210
|
DumpStringToUSB(" with args ");
|
211
|
DumpStringToUSB(args);
|
212
|
DumpStringToUSB("\n\r");
|
213
|
|
214
|
i=0;
|
215
|
// Note: Commands have been uppercased when this code is called
|
216
|
switch(cmd)
|
217
|
{
|
218
|
case 'THRU': {
|
219
|
/*char buffer[64];
|
220
|
memset(buffer, 'A', sizeof(buffer));
|
221
|
usb_print_flush();
|
222
|
while(1) usb_print_buffer(buffer, 0, sizeof(buffer));*/
|
223
|
while(1) vUSBSendBuffer((unsigned char*)"AAAAAABCDEBBBBB", 0, 15);
|
224
|
}
|
225
|
break;
|
226
|
case 'Z':
|
227
|
i=atoiEx(args, &args);
|
228
|
if(i==0) {
|
229
|
tc_cdiv_sync_disable();
|
230
|
DumpStringToUSB("cdiv_sync disabled \n\r");
|
231
|
} else {
|
232
|
tc_cdiv_sync_enable();
|
233
|
DumpStringToUSB("cdiv_sync enabled \n\r");
|
234
|
}
|
235
|
break;
|
236
|
case 'G':
|
237
|
if(!OPENPICC->features.data_gating) {
|
238
|
DumpStringToUSB("This hardware does not have data gating capability\n\r");
|
239
|
break;
|
240
|
}
|
241
|
i=atoiEx(args, &args);
|
242
|
ssc_set_gate(i);
|
243
|
if(i==0) {
|
244
|
DumpStringToUSB("SSC_DATA disabled \n\r");
|
245
|
} else {
|
246
|
DumpStringToUSB("SSC_DATA enabled \n\r");
|
247
|
}
|
248
|
break;
|
249
|
case 'D':
|
250
|
i=atoiEx(args, &args);
|
251
|
tc_cdiv_set_divider(i);
|
252
|
DumpStringToUSB("tc_cdiv set to ");
|
253
|
DumpUIntToUSB(i);
|
254
|
DumpStringToUSB("\n\r");
|
255
|
break;
|
256
|
case 'P':
|
257
|
print_pio();
|
258
|
break;
|
259
|
/* case 'R':
|
260
|
start_stop_sniffing();
|
261
|
break;*/
|
262
|
case 'C':
|
263
|
DumpStringToUSB(
|
264
|
" *****************************************************\n\r"
|
265
|
" * Current configuration: *\n\r"
|
266
|
" *****************************************************\n\r"
|
267
|
" * Version " COMPILE_SVNREV "\n\r"
|
268
|
" * compiled " COMPILE_DATE " by " COMPILE_BY "\n\r"
|
269
|
" * running on ");
|
270
|
DumpStringToUSB(OPENPICC->release_name);
|
271
|
DumpStringToUSB("\n\r *\n\r");
|
272
|
DumpStringToUSB(" * Uptime is ");
|
273
|
ms=xTaskGetTickCount();
|
274
|
DumpTimeToUSB(ms);
|
275
|
DumpStringToUSB("\n\r");
|
276
|
DumpStringToUSB(" * The comparator threshold is ");
|
277
|
DumpUIntToUSB(da_get_value());
|
278
|
DumpStringToUSB("\n\r");
|
279
|
DumpStringToUSB(" * Number of PIO IRQs handled: ");
|
280
|
i = pio_irq_get_count() & (~(unsigned int)0);
|
281
|
DumpUIntToUSB(i);
|
282
|
DumpStringToUSB("\n\r");
|
283
|
DumpStringToUSB(" * current field strength: ");
|
284
|
DumpUIntToUSB(adc_get_field_strength());
|
285
|
DumpStringToUSB("\n\r");
|
286
|
DumpStringToUSB(" * fdt_offset: ");
|
287
|
if(fdt_offset < 0) {
|
288
|
DumpStringToUSB("-");
|
289
|
DumpUIntToUSB(-fdt_offset);
|
290
|
} else DumpUIntToUSB(fdt_offset);
|
291
|
DumpStringToUSB("\n\r");
|
292
|
DumpStringToUSB(" * load_mod_level: ");
|
293
|
DumpUIntToUSB(load_mod_level_set);
|
294
|
DumpStringToUSB("\n\r");
|
295
|
DumpStringToUSB(" * SSC performance metrics:\n\r");
|
296
|
for(i=0; i<_MAX_METRICS; i++) {
|
297
|
char *name;
|
298
|
int value;
|
299
|
if(ssc_get_metric(i, &name, &value)) {
|
300
|
DumpStringToUSB(" * \t");
|
301
|
DumpStringToUSB(name);
|
302
|
DumpStringToUSB(": ");
|
303
|
DumpUIntToUSB(value);
|
304
|
DumpStringToUSB("\n\r");
|
305
|
}
|
306
|
}
|
307
|
DumpStringToUSB(" * SSC status: ");
|
308
|
DumpUIntToUSB(AT91C_BASE_SSC->SSC_SR);
|
309
|
DumpStringToUSB("\n\r");
|
310
|
DumpStringToUSB(" * TC0_CV value: ");
|
311
|
DumpUIntToUSB(*AT91C_TC0_CV);
|
312
|
DumpStringToUSB("\n\r");
|
313
|
DumpStringToUSB(" * TC2_CV value: ");
|
314
|
DumpUIntToUSB(*AT91C_TC2_CV);
|
315
|
DumpStringToUSB("\n\r");
|
316
|
DumpStringToUSB(" * TC2_IMR value: ");
|
317
|
DumpUIntToUSB(*AT91C_TC2_IMR);
|
318
|
DumpStringToUSB("\n\r");
|
319
|
DumpStringToUSB(" * TC2_SR value: ");
|
320
|
DumpUIntToUSB(*AT91C_TC2_SR);
|
321
|
DumpStringToUSB("\n\r");
|
322
|
DumpStringToUSB(" * TC2_RB value: ");
|
323
|
DumpUIntToUSB(*AT91C_TC2_RB);
|
324
|
DumpStringToUSB("\n\r");
|
325
|
DumpStringToUSB(" * TC2_RC value: ");
|
326
|
DumpUIntToUSB(*AT91C_TC2_RC);
|
327
|
DumpStringToUSB("\n\r");
|
328
|
DumpStringToUSB(" * SSC_SR value: ");
|
329
|
DumpUIntToUSB(*AT91C_SSC_SR);
|
330
|
DumpStringToUSB("\n\r");
|
331
|
DumpStringToUSB(" * SSC_RCMR value: ");
|
332
|
DumpUIntToUSB(*AT91C_SSC_RCMR);
|
333
|
DumpStringToUSB("\n\r");
|
334
|
DumpStringToUSB(" * SSC_TCMR value: ");
|
335
|
DumpUIntToUSB(*AT91C_SSC_TCMR);
|
336
|
DumpStringToUSB("\n\r");
|
337
|
DumpStringToUSB(" * SSC_TFMR value: ");
|
338
|
DumpUIntToUSB(*AT91C_SSC_TFMR);
|
339
|
DumpStringToUSB("\n\r");
|
340
|
DumpStringToUSB(" * SSC_TPR value: ");
|
341
|
DumpUIntToUSB(*AT91C_SSC_TPR);
|
342
|
DumpStringToUSB("\n\r");
|
343
|
DumpStringToUSB(" * SSC_TCR value: ");
|
344
|
DumpUIntToUSB(*AT91C_SSC_TCR);
|
345
|
DumpStringToUSB("\n\r");
|
346
|
DumpStringToUSB(" * SSC_RPR value: ");
|
347
|
DumpUIntToUSB(*AT91C_SSC_RPR);
|
348
|
DumpStringToUSB("\n\r");
|
349
|
DumpStringToUSB(" * SSC_RCR value: ");
|
350
|
DumpUIntToUSB(*AT91C_SSC_RCR);
|
351
|
DumpStringToUSB("\n\r");
|
352
|
DumpStringToUSB(" * SSC_IMR value: ");
|
353
|
DumpUIntToUSB(*AT91C_SSC_IMR);
|
354
|
DumpStringToUSB("\n\r");
|
355
|
DumpStringToUSB(
|
356
|
" *\n\r"
|
357
|
" *****************************************************\n\r"
|
358
|
);
|
359
|
break;
|
360
|
case '+':
|
361
|
case '-':
|
362
|
if(cmd == '+')
|
363
|
{
|
364
|
if(da_get_value() < 255)
|
365
|
da_comp_carr(da_get_value()+1);
|
366
|
}
|
367
|
else
|
368
|
if(da_get_value() > 0)
|
369
|
da_comp_carr(da_get_value()-1);;
|
370
|
|
371
|
DumpStringToUSB(" * Comparator threshold set to ");
|
372
|
DumpUIntToUSB(da_get_value());
|
373
|
DumpStringToUSB("\n\r");
|
374
|
break;
|
375
|
case 'U+':
|
376
|
i=atoiEx(args, &args);
|
377
|
change_value(get_UID, set_UID, i==0 ? +1 : +i , "UID"); break;
|
378
|
case 'U-':
|
379
|
i=atoiEx(args, &args);
|
380
|
change_value(get_UID, set_UID, i==0 ? -1 : -i , "UID"); break;
|
381
|
case 'N+':
|
382
|
i=atoiEx(args, &args);
|
383
|
change_value(get_nonce, set_nonce, i==0 ? +1 : +i, "nonce"); break;
|
384
|
case 'N-':
|
385
|
i=atoiEx(args, &args);
|
386
|
change_value(get_nonce, set_nonce, i==0 ? -1 : -i, "nonce"); break;
|
387
|
case 'L':
|
388
|
led = (led+1)%4;
|
389
|
vLedSetRed( (led&1) );
|
390
|
vLedSetGreen( led&2 );
|
391
|
DumpStringToUSB(" * LEDs set to ");
|
392
|
vUSBSendByte( (char)led + '0' );
|
393
|
DumpStringToUSB("\n\r");
|
394
|
break;
|
395
|
case '!':
|
396
|
tc_cdiv_sync_reset();
|
397
|
break;
|
398
|
case '#':
|
399
|
if(!OPENPICC->features.clock_switching) {
|
400
|
DumpStringToUSB("* This hardware is not clock switching capable\n\r");
|
401
|
break;
|
402
|
}
|
403
|
clock_select = (clock_select+1) % 2;
|
404
|
clock_switch(clock_select);
|
405
|
DumpStringToUSB("Active clock is now ");
|
406
|
DumpUIntToUSB(clock_select);
|
407
|
DumpStringToUSB("\n\r");
|
408
|
break;
|
409
|
case 'J':
|
410
|
fdt_offset++;
|
411
|
DumpStringToUSB("fdt_offset is now ");
|
412
|
if(fdt_offset<0) { DumpStringToUSB("-"); DumpUIntToUSB(-fdt_offset); }
|
413
|
else { DumpStringToUSB("+"); DumpUIntToUSB(fdt_offset); }
|
414
|
DumpStringToUSB("\n\r");
|
415
|
break;
|
416
|
case 'K':
|
417
|
fdt_offset--;
|
418
|
DumpStringToUSB("fdt_offset is now ");
|
419
|
if(fdt_offset<0) { DumpStringToUSB("-"); DumpUIntToUSB(-fdt_offset); }
|
420
|
else { DumpStringToUSB("+"); DumpUIntToUSB(fdt_offset); }
|
421
|
DumpStringToUSB("\n\r");
|
422
|
break;
|
423
|
case 'F':
|
424
|
startstop_field_meter();
|
425
|
break;
|
426
|
case 'I':
|
427
|
pll_inhibit(!pll_is_inhibited());
|
428
|
if(pll_is_inhibited()) DumpStringToUSB(" * PLL is now inhibited\n\r");
|
429
|
else DumpStringToUSB(" * PLL is now running\n\r");
|
430
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
431
|
case 'T':
|
432
|
memset(pcWriteBuffer, 0, sizeof(pcWriteBuffer));
|
433
|
vTaskList(pcWriteBuffer);
|
434
|
DumpStringToUSB((char*)pcWriteBuffer);
|
435
|
break;
|
436
|
#endif
|
437
|
case 'Q':
|
438
|
//BROKEN new ssc code
|
439
|
//ssc_rx_start();
|
440
|
while(0) {
|
441
|
DumpUIntToUSB(AT91C_BASE_SSC->SSC_SR);
|
442
|
DumpStringToUSB("\n\r");
|
443
|
}
|
444
|
break;
|
445
|
case 'A':
|
446
|
load_mod_level_set = (load_mod_level_set+1) % 4;
|
447
|
load_mod_level(load_mod_level_set);
|
448
|
DumpStringToUSB("load_mod_level is now ");
|
449
|
DumpUIntToUSB(load_mod_level_set);
|
450
|
DumpStringToUSB("\n\r");
|
451
|
break;
|
452
|
case 'H':
|
453
|
case '?':
|
454
|
DumpStringToUSB(
|
455
|
" *****************************************************\n\r"
|
456
|
" * OpenPICC USB terminal *\n\r"
|
457
|
" * (C) 2007 Milosch Meriac <meriac@openbeacon.de> *\n\r"
|
458
|
" * (C) 2007 Henryk Plötz <henryk@ploetzli.ch> *\n\r"
|
459
|
" *****************************************************\n\r"
|
460
|
" * Version " COMPILE_SVNREV "\n\r"
|
461
|
" * compiled " COMPILE_DATE " by " COMPILE_BY "\n\r"
|
462
|
" * running on ");
|
463
|
DumpStringToUSB(OPENPICC->release_name);
|
464
|
DumpStringToUSB("\n\r *\n\r"
|
465
|
" * thru - test throughput\n\r"
|
466
|
#if ( configUSE_TRACE_FACILITY == 1 )
|
467
|
" * t - print task list and stack usage\n\r"
|
468
|
#endif
|
469
|
" * c - print configuration\n\r"
|
470
|
" * +,- - decrease/increase comparator threshold\n\r"
|
471
|
" * # - switch clock\n\r"
|
472
|
" * l - cycle LEDs\n\r"
|
473
|
" * p - print PIO pins\n\r"
|
474
|
" * r - start/stop receiving\n\r"
|
475
|
" * z 0/1- enable or disable tc_cdiv_sync\n\r"
|
476
|
" * i - inhibit/uninhibit PLL\n\r"
|
477
|
" * ! - reset tc_cdiv_sync\n\r"
|
478
|
" * q - start rx\n\r"
|
479
|
" * f - start/stop field meter\n\r"
|
480
|
" * d div- set tc_cdiv divider value 16, 32, 64, ...\n\r"
|
481
|
" * j,k - increase, decrease fdt_offset\n\r"
|
482
|
" * a - change load modulation level\n\r"
|
483
|
" * g 0/1- disable or enable SSC_DATA through gate\n\r"
|
484
|
" * 9 - reset CPU\n\r"
|
485
|
" * ?,h - display this help screen\n\r"
|
486
|
" *\n\r"
|
487
|
" *****************************************************\n\r"
|
488
|
);
|
489
|
break;
|
490
|
case '9':
|
491
|
AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
|
492
|
AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST);
|
493
|
break;
|
494
|
}
|
495
|
|
496
|
}
|
497
|
|
498
|
// A task to execute commands
|
499
|
void vCmdCode(void *pvParameters) {
|
500
|
(void) pvParameters;
|
501
|
u_int32_t cmd;
|
502
|
portBASE_TYPE i, j=0;
|
503
|
|
504
|
for(;;) {
|
505
|
cmd_type next_command;
|
506
|
cmd = j = 0;
|
507
|
if( xQueueReceive(xCmdQueue, &next_command, ( portTickType ) 100 ) ) {
|
508
|
DumpStringToUSB("Command received:");
|
509
|
DumpStringToUSB(next_command.command);
|
510
|
DumpStringToUSB("\n\r");
|
511
|
while(next_command.command[j] == ' ' && next_command.command[j] != 0) {
|
512
|
j++;
|
513
|
}
|
514
|
for(i=0;i<4;i++) {
|
515
|
portCHAR cByte = next_command.command[i+j];
|
516
|
if(next_command.command[i+j] == 0 || next_command.command[i+j] == ' ')
|
517
|
break;
|
518
|
if(cByte>='a' && cByte<='z') {
|
519
|
cmd = (cmd<<8) | (cByte+('A'-'a'));
|
520
|
} else cmd = (cmd<<8) | cByte;
|
521
|
}
|
522
|
while(next_command.command[i+j] == ' ' && next_command.command[i+j] != 0) {
|
523
|
i++;
|
524
|
}
|
525
|
prvExecCommand(cmd, next_command.command+i+j);
|
526
|
} else {
|
527
|
}
|
528
|
}
|
529
|
}
|
530
|
|
531
|
|
532
|
|
533
|
// A task to read commands from USB
|
534
|
void vCmdRecvUsbCode(void *pvParameters) {
|
535
|
portBASE_TYPE len=0;
|
536
|
portBASE_TYPE short_command=1, submit_it=0;
|
537
|
cmd_type next_command = { source: SRC_USB, command: ""};
|
538
|
(void) pvParameters;
|
539
|
|
540
|
for( ;; ) {
|
541
|
if(vUSBRecvByte(&next_command.command[len], 1, 100)) {
|
542
|
if(USE_COLON_FOR_LONG_COMMANDS) {
|
543
|
if(len == 0 && next_command.command[len] == ':')
|
544
|
short_command = 0;
|
545
|
} else {
|
546
|
if(strchr(SHORT_COMMANDS, next_command.command[len]) == NULL)
|
547
|
short_command = 0;
|
548
|
}
|
549
|
next_command.command[len+1] = 0;
|
550
|
DumpStringToUSB(next_command.command + len);
|
551
|
if(next_command.command[len] == '\n' || next_command.command[len] == '\r') {
|
552
|
next_command.command[len] = 0;
|
553
|
submit_it = 1;
|
554
|
}
|
555
|
if(short_command==1) {
|
556
|
submit_it = 1;
|
557
|
}
|
558
|
if(submit_it) {
|
559
|
if(len > 0 || short_command) {
|
560
|
if( xQueueSend(xCmdQueue, &next_command, 0) != pdTRUE) {
|
561
|
DumpStringToUSB("Queue full, command can't be processed.\n");
|
562
|
}
|
563
|
}
|
564
|
len=0;
|
565
|
submit_it=0;
|
566
|
short_command=1;
|
567
|
} else if( len>0 || next_command.command[len] != ':') len++;
|
568
|
if(len >= MAX_CMD_LEN-1) {
|
569
|
DumpStringToUSB("ERROR: Command too long. Ignored.");
|
570
|
len=0;
|
571
|
}
|
572
|
}
|
573
|
}
|
574
|
}
|
575
|
|
576
|
static portBASE_TYPE field_meter_enabled = 0;
|
577
|
#define FIELD_METER_WIDTH 80
|
578
|
#define FIELD_METER_MAX_VALUE 160
|
579
|
#define FIELD_METER_SCALE_FACTOR (FIELD_METER_MAX_VALUE/FIELD_METER_WIDTH)
|
580
|
// A task to print the field strength as a bar graph
|
581
|
void vFieldMeter(void *pvParameters) {
|
582
|
(void) pvParameters;
|
583
|
char meter_string[FIELD_METER_WIDTH+2];
|
584
|
|
585
|
while(1) {
|
586
|
if(xSemaphoreTake(xFieldMeterMutex, portMAX_DELAY)) {
|
587
|
int i,ad_value = adc_get_field_strength();
|
588
|
meter_string[0] = '\r';
|
589
|
|
590
|
for(i=0; i<FIELD_METER_WIDTH; i++)
|
591
|
meter_string[i+1] =
|
592
|
(ad_value / FIELD_METER_SCALE_FACTOR < i) ?
|
593
|
' ' :
|
594
|
((i*FIELD_METER_SCALE_FACTOR)%10==0 ?
|
595
|
(((i*FIELD_METER_SCALE_FACTOR)/10)%10)+'0' : '#' );
|
596
|
meter_string[i+1] = 0;
|
597
|
usb_print_string(meter_string);
|
598
|
|
599
|
vTaskDelay(100*portTICK_RATE_MS);
|
600
|
if(field_meter_enabled == 1) xSemaphoreGive(xFieldMeterMutex);
|
601
|
}
|
602
|
}
|
603
|
}
|
604
|
|
605
|
void startstop_field_meter(void) {
|
606
|
if(field_meter_enabled) {
|
607
|
field_meter_enabled = 0;
|
608
|
} else {
|
609
|
field_meter_enabled = 1;
|
610
|
xSemaphoreGive(xFieldMeterMutex);
|
611
|
}
|
612
|
}
|
613
|
|
614
|
portBASE_TYPE vCmdInit() {
|
615
|
unsigned int i;
|
616
|
for(i=0; i<sizeof(PIO_PINS)/sizeof(PIO_PINS[0]); i++) {
|
617
|
if(PIO_PINS[i].dynpin == DYNAMIC_PIN_PLL_LOCK) {
|
618
|
PIO_PINS[i].pin = OPENPICC->PLL_LOCK;
|
619
|
PIO_PINS[i].dynpin = 0;
|
620
|
}
|
621
|
}
|
622
|
|
623
|
/* FIXME Maybe modify to use pointers? */
|
624
|
xCmdQueue = xQueueCreate( 10, sizeof(cmd_type) );
|
625
|
if(xCmdQueue == 0) {
|
626
|
return 0;
|
627
|
}
|
628
|
vSemaphoreCreateBinary( xFieldMeterMutex );
|
629
|
if(xFieldMeterMutex == 0) {
|
630
|
return 0;
|
631
|
}
|
632
|
xSemaphoreTake(xFieldMeterMutex, portMAX_DELAY);
|
633
|
|
634
|
if(xTaskCreate(vCmdCode, (signed portCHAR *)"CMD", TASK_CMD_STACK, NULL,
|
635
|
TASK_CMD_PRIORITY, &xCmdTask) != pdPASS) {
|
636
|
return 0;
|
637
|
}
|
638
|
|
639
|
if(xTaskCreate(vCmdRecvUsbCode, (signed portCHAR *)"CMDUSB", 128, NULL,
|
640
|
TASK_CMD_PRIORITY, &xCmdRecvUsbTask) != pdPASS) {
|
641
|
return 0;
|
642
|
}
|
643
|
|
644
|
if(xTaskCreate(vFieldMeter, (signed portCHAR *)"FIELD METER", 128, NULL,
|
645
|
TASK_CMD_PRIORITY, &xFieldMeterTask) != pdPASS) {
|
646
|
return 0;
|
647
|
}
|
648
|
|
649
|
return 1;
|
650
|
}
|