+//-----------------------------------------------------------------------------
+// Wait for commands from reader
+// Stop when button is pressed (return 1) or field was gone (return 2)
+// Or return 0 when command is captured
+//-----------------------------------------------------------------------------
+static int EmGetCmd(uint8_t *received, int *len, int maxLen)
+{
+ *len = 0;
+
+ uint32_t timer = 0, vtime = 0;
+ int analogCnt = 0;
+ int analogAVG = 0;
+
+ // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
+ // only, since we are receiving, not transmitting).
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+
+ // Set ADC to read field strength
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
+ AT91C_BASE_ADC->ADC_MR =
+ ADC_MODE_PRESCALE(32) |
+ ADC_MODE_STARTUP_TIME(16) |
+ ADC_MODE_SAMPLE_HOLD_TIME(8);
+ AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF);
+ // start ADC
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
+
+ // Now run a 'software UART' on the stream of incoming samples.
+ Uart.output = received;
+ Uart.byteCntMax = maxLen;
+ Uart.state = STATE_UNSYNCD;
+
+ for(;;) {
+ WDT_HIT();
+
+ if (BUTTON_PRESS()) return 1;
+
+ // test if the field exists
+ if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) {
+ analogCnt++;
+ analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF];
+ AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
+ if (analogCnt >= 32) {
+ if ((33000 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
+ vtime = GetTickCount();
+ if (!timer) timer = vtime;
+ // 50ms no field --> card to idle state
+ if (vtime - timer > 50) return 2;
+ } else
+ if (timer) timer = 0;
+ analogCnt = 0;
+ analogAVG = 0;
+ }
+ }
+ // transmit none
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ }
+ // receive and test the miller decoding
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+ if(MillerDecoding((b & 0xf0) >> 4)) {
+ *len = Uart.byteCnt;
+ if (tracing) LogTrace(received, *len, GetDeltaCountUS(), Uart.parityBits, TRUE);
+ return 0;
+ }
+ if(MillerDecoding(b & 0x0f)) {
+ *len = Uart.byteCnt;
+ if (tracing) LogTrace(received, *len, GetDeltaCountUS(), Uart.parityBits, TRUE);
+ return 0;
+ }
+ }
+ }
+}
+
+static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded)
+{
+ int i, u = 0;
+ uint8_t b = 0;
+
+ // Modulate Manchester
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
+ AT91C_BASE_SSC->SSC_THR = 0x00;
+ FpgaSetupSsc();
+
+ // include correction bit
+ i = 1;
+ if((Uart.parityBits & 0x01) || correctionNeeded) {
+ // 1236, so correction bit needed
+ i = 0;
+ }
+
+ // send cycle
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+ (void)b;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ if(i > respLen) {
+ b = 0xff; // was 0x00
+ u++;
+ } else {
+ b = resp[i];
+ i++;
+ }
+ AT91C_BASE_SSC->SSC_THR = b;
+
+ if(u > 4) break;
+ }
+ if(BUTTON_PRESS()) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int EmSend4bitEx(uint8_t resp, int correctionNeeded){
+ Code4bitAnswerAsTag(resp);
+ int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded);
+ if (tracing) LogTrace(&resp, 1, GetDeltaCountUS(), GetParity(&resp, 1), FALSE);
+ return res;
+}
+
+int EmSend4bit(uint8_t resp){
+ return EmSend4bitEx(resp, 0);
+}
+
+int EmSendCmdExPar(uint8_t *resp, int respLen, int correctionNeeded, uint32_t par){
+ CodeIso14443aAsTagPar(resp, respLen, par);
+ int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded);
+ if (tracing) LogTrace(resp, respLen, GetDeltaCountUS(), par, FALSE);
+ return res;
+}
+
+int EmSendCmdEx(uint8_t *resp, int respLen, int correctionNeeded){
+ return EmSendCmdExPar(resp, respLen, correctionNeeded, GetParity(resp, respLen));
+}
+
+int EmSendCmd(uint8_t *resp, int respLen){
+ return EmSendCmdExPar(resp, respLen, 0, GetParity(resp, respLen));
+}
+
+int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par){
+ return EmSendCmdExPar(resp, respLen, 0, par);
+}
+