From 29ea5bbf5b9c3b3679aa40e4ee7029284cb424c6 Mon Sep 17 00:00:00 2001 From: henryk Date: Sat, 24 Nov 2007 07:59:42 +0000 Subject: Add load modulation and encoding/decoding code from harald git-svn-id: https://svn.openpcd.org:2342/trunk@351 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/Makefile | 5 ++ openpicc/application/decoder.c | 81 +++++++++++++++++ openpicc/application/decoder.h | 32 +++++++ openpicc/application/decoder_miller.c | 130 +++++++++++++++++++++++++++ openpicc/application/decoder_nrzl.c | 111 +++++++++++++++++++++++ openpicc/application/iso14443_layer3a.c | 15 +++- openpicc/application/iso14443a_manchester.c | 134 ++++++++++++++++++++++++++++ openpicc/application/load_modulation.c | 49 ++++++++++ openpicc/application/load_modulation.h | 7 ++ openpicc/application/main.c | 2 + openpicc/config/board.h | 3 + 11 files changed, 566 insertions(+), 3 deletions(-) create mode 100644 openpicc/application/decoder.c create mode 100644 openpicc/application/decoder.h create mode 100644 openpicc/application/decoder_miller.c create mode 100644 openpicc/application/decoder_nrzl.c create mode 100644 openpicc/application/iso14443a_manchester.c create mode 100644 openpicc/application/load_modulation.c create mode 100644 openpicc/application/load_modulation.h (limited to 'openpicc') diff --git a/openpicc/Makefile b/openpicc/Makefile index bea0f40..2b08878 100644 --- a/openpicc/Makefile +++ b/openpicc/Makefile @@ -84,6 +84,11 @@ ARM_SRC= \ application/tc_cdiv.c \ application/usb_print.c \ application/iso14443_layer3a.c \ + application/iso14443a_manchester.c \ + application/load_modulation.c \ + application/decoder_miller.c \ + application/decoder_nrzl.c \ + application/decoder.c \ os/boot/Cstartup_SAM7.c \ os/core/list.c \ os/core/queue.c \ diff --git a/openpicc/application/decoder.c b/openpicc/application/decoder.c new file mode 100644 index 0000000..a4287fd --- /dev/null +++ b/openpicc/application/decoder.c @@ -0,0 +1,81 @@ +/* Decoder Core for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include "openpicc.h" +#include "dbgu.h" +#include "decoder.h" + +static struct decoder_algo *decoder_algo[DECODER_NUM_ALGOS]; + +static int get_next_data(struct decoder_state *st, u_int8_t *data) +{ + u_int8_t parity_sample; + u_int32_t bytesample; + + bytesample = st->algo->get_next_bytesample(st, &parity_sample); + + return st->algo->decode_sample(bytesample, data); +} + +/* iterate over sample buffer (size N bytes) and decode data */ +int decoder_decode(u_int8_t algo, const char *sample_buf, + int sample_buf_size, unsigned char *data_buf) +{ + int i, ret; + struct decoder_state st; + + if (algo >= DECODER_NUM_ALGOS) + return -EINVAL; + + st.buf = sample_buf; + st.buf32 = (u_int32_t *) st.buf; + st.bit_ofs = 0; + st.algo = decoder_algo[algo]; + + for (i = 0; i < (sample_buf_size*8)/st.algo->bits_per_sampled_char; + i++) { + ret = get_next_data(&st, &data_buf[i]); + if (ret < 0) { + DEBUGPCR("decoder error %d at data byte %u", + ret, i); + return ret; + } + } + + return i+1; +} + +int decoder_register(int algnum, struct decoder_algo *algo) +{ + if (algnum >= DECODER_NUM_ALGOS) + return -EINVAL; + + decoder_algo[algnum] = algo; + + return 0; +} + +void decoder_init(void) +{ + decoder_register(DECODER_MILLER, &miller_decoder); + decoder_register(DECODER_NRZL, &nrzl_decoder); +} diff --git a/openpicc/application/decoder.h b/openpicc/application/decoder.h new file mode 100644 index 0000000..bd25777 --- /dev/null +++ b/openpicc/application/decoder.h @@ -0,0 +1,32 @@ +#ifndef _DECODER_H +#define _DECODER_H + +struct decoder_state; + +struct decoder_algo { + u_int8_t oversampling_rate; + u_int8_t bits_per_sampled_char; + u_int32_t bytesample_mask; + int (*decode_sample)(const u_int32_t sample, u_int8_t *data); + u_int32_t (*get_next_bytesample)(struct decoder_state *st, u_int8_t *parity_sample); +}; + +struct decoder_state { + struct decoder_algo *algo; + u_int8_t bit_ofs; + const char *buf; + const u_int32_t *buf32; +}; + +extern int decoder_register(int algnum, struct decoder_algo *algo); +extern int decoder_decode(u_int8_t algo, const char *sample_buf, + int sample_buf_size, unsigned char *data_buf); + +#define DECODER_MILLER 0 +#define DECODER_NRZL 1 +#define DECODER_NUM_ALGOS 2 + +extern struct decoder_algo nrzl_decoder; +extern struct decoder_algo miller_decoder; + +#endif diff --git a/openpicc/application/decoder_miller.c b/openpicc/application/decoder_miller.c new file mode 100644 index 0000000..aa3a669 --- /dev/null +++ b/openpicc/application/decoder_miller.c @@ -0,0 +1,130 @@ +/* + * ISO14443A modified Miller decoder for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * LSB First LSB hex + * Sequence X 0010 0100 0x4 + * Sequence Y 0000 0000 0x0 + * Sequence Z 1000 0001 0x1 + * + * Logic 1 Sequence X + * Logic 0 Sequence Y with two exceptions: + * - if there are more contiguous 0, Z used from second one + * - if the first bit after SOF is 0, sequence Z used for all contig 0's + * SOF Sequence Z + * EOF Logic 0 followed by Sequence Y + * + * cmd hex bits symbols hex (quad-sampled) + * + * REQA 0x26 S 0110010 E Z ZXXYZXY ZY 0x10410441 + * WUPA 0x52 S 0100101 E Z ZXYZXYX YY 0x04041041 + * + * SOF is 'eaten' by SSC start condition (Compare 0). Remaining bits are + * mirrored, e.g. samples for LSB of first byte are & 0xf + * + */ + +#include + +#include "openpicc.h" +#include "dbgu.h" +#include "decoder.h" + + +#define OVERSAMPLING_RATE 4 + +/* definitions for four-times oversampling */ +#define SEQ_X 0x4 +#define SEQ_Y 0x0 +#define SEQ_Z 0x1 + +/* decode a single sampled bit */ +static u_int8_t miller_decode_sampled_bit(u_int32_t sampled_bit) +{ + switch (sampled_bit) { + case SEQ_X: + return 1; + break; + case SEQ_Z: + case SEQ_Y: + return 0; + break; + default: + DEBUGP("unknown sequence sample `%x' ", sampled_bit); + return 2; + break; + } +} + +/* decode a single 32bit data sample of an 8bit miller encoded word */ +static int miller_decode_sample(u_int32_t sample, u_int8_t *data) +{ + u_int8_t ret = 0; + unsigned int i; + + for (i = 0; i < sizeof(sample)/OVERSAMPLING_RATE; i++) { + u_int8_t bit = miller_decode_sampled_bit(sample & 0xf); + + if (bit == 1) + ret |= 1; + /* else do nothing since ret was initialized with 0 */ + + /* skip shifting in case of last data bit */ + if (i == sizeof(sample)/OVERSAMPLING_RATE) + break; + + sample = sample >> OVERSAMPLING_RATE; + ret = ret << 1; + } + + *data = ret; + + return ret; +} + +static u_int32_t get_next_bytesample(struct decoder_state *ms, + u_int8_t *parity_sample) +{ + u_int32_t ret = 0; + + /* get remaining bits from the current word */ + ret = *(ms->buf32) >> ms->bit_ofs; + /* move to next word */ + ms->buf32++; + + /* if required, get remaining bits from next word */ + if (ms->bit_ofs) + ret |= *(ms->buf32) << (32 - ms->bit_ofs); + + *parity_sample = (*(ms->buf32) >> ms->bit_ofs & 0xf); + + /* increment bit offset (modulo 32) */ + ms->bit_ofs = (ms->bit_ofs + OVERSAMPLING_RATE) % 32; + + return ret; +} + +struct decoder_algo miller_decoder = { + .oversampling_rate = OVERSAMPLING_RATE, + .bits_per_sampled_char = 9 * OVERSAMPLING_RATE, + .bytesample_mask = 0xffffffff, + .decode_sample = &miller_decode_sample, + .get_next_bytesample = &get_next_bytesample, +}; diff --git a/openpicc/application/decoder_nrzl.c b/openpicc/application/decoder_nrzl.c new file mode 100644 index 0000000..6ffbb45 --- /dev/null +++ b/openpicc/application/decoder_nrzl.c @@ -0,0 +1,111 @@ +/* NRZ-L decoder implementation for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * speed(kbps) 106 212 424 848 + * etu 128/fc 64/fc 32/fc 16/fc + * etu(usec) 9.4 4.7 2.35 1.18 + * + * NRZ-L coding with logic level + * + * logic 1: carrier high field amplitude (no modulation) + * logic 0: carrier low field amplitude + * + * Character transmission format: + * start bit: logic 0 + * data: eight bits, lsb first + * stop bit logic 1 + * + * Frame Format: + * + * SOF char [EGT char, ...] EOF + * + * SOF: falling edge, 10..11 etu '0', rising edge in 1etu, 2..3etu '1' + * EGT: between 0 and 57uS + * EOF: falling edge, 10..11 etu '0', rising edge in 1etu + * + * + * Sampling + * - sample once per bit clock, exactly in the middle of it + * - synchronize CARRIER_DIV TC0 to first falling edge + * - Configure CARRIER_DIV RA compare (rising edge) to be at + * etu/2 carrier clocks. + * - problem: SOF 12..14etu length, therefore we cannot specify + * SOF as full start condition and then sample with 10bit + * frames :( + * + */ + +#include +#include + +#include "openpicc.h" +#include "dbgu.h" +#include "decoder.h" + +/* currently this code will only work with oversampling_rate == 1 */ +#define OVERSAMPLING_RATE 1 + +static u_int32_t get_next_bytesample(struct decoder_state *st, + u_int8_t *parity_sample) +{ + u_int32_t ret = 0; + u_int8_t bits_per_sampled_char = st->algo->bits_per_sampled_char; + u_int8_t bytesample_mask = st->algo->bytesample_mask; + + /* FIXME: shift start and stop bit into parity_sample and just + * return plain 8-bit data word */ + (void)parity_sample; + + /* first part of 10-databit bytesample */ + ret = (*(st->buf32) >> st->bit_ofs) & bytesample_mask; + + if (st->bit_ofs > 32 - bits_per_sampled_char) { + /* second half of 10-databit bytesample */ + st->buf32++; + ret |= (*(st->buf32) << (32 - st->bit_ofs)); + } + st->bit_ofs = (st->bit_ofs + bits_per_sampled_char) % 32; + + return ret & bytesample_mask; +} + +static int nrzl_decode_sample(const u_int32_t sample, u_int8_t *data) +{ + *data = (sample >> 1) & 0xff; + + if (!(sample & 0x01)) { + DEBUGPCRF("invalid start bit 0!"); + return -EIO; + } + if (sample & 0x20) { + DEBUGPCRF("invalid stop bit 1!"); + return -EIO; + } + + return 0; +} + +struct decoder_algo nrzl_decoder = { + .oversampling_rate = OVERSAMPLING_RATE, + .bits_per_sampled_char = 10 * OVERSAMPLING_RATE, + .bytesample_mask = 0x3ff, + .decode_sample = &nrzl_decode_sample, + .get_next_bytesample = &get_next_bytesample, +}; diff --git a/openpicc/application/iso14443_layer3a.c b/openpicc/application/iso14443_layer3a.c index 8dd9cd2..841ad14 100644 --- a/openpicc/application/iso14443_layer3a.c +++ b/openpicc/application/iso14443_layer3a.c @@ -130,17 +130,26 @@ void iso14443_layer3a_state_machine (void *pvParameters) portENTER_CRITICAL(); buffer->state = PROCESSING; portEXIT_CRITICAL(); + u_int32_t first_sample = *(u_int32_t*)buffer->data; DumpStringToUSB("Frame: "); - DumpUIntToUSB(*(u_int32_t*)buffer->data); + DumpUIntToUSB(first_sample); DumpStringToUSB(" "); main_help_print_buffer(buffer, &pktcount); switch(state) { case IDLE: case HALT: - ssc_rx_mode_set(SSC_MODE_14443A_SHORT); - ssc_rx_start(); + if(first_sample == WUPA || (state==IDLE && first_sample==REQA)) { + /* Need to transmit ATQA */ + LAYER3_DEBUG("Received "); + LAYER3_DEBUG(first_sample == WUPA ? "WUPA" : "REQA"); + LAYER3_DEBUG(" waking up to send ATQA\n\r"); + } else { + /* Wait for another frame */ + ssc_rx_mode_set(SSC_MODE_14443A_SHORT); + ssc_rx_start(); + } break; default: break; diff --git a/openpicc/application/iso14443a_manchester.c b/openpicc/application/iso14443a_manchester.c new file mode 100644 index 0000000..efc4baf --- /dev/null +++ b/openpicc/application/iso14443a_manchester.c @@ -0,0 +1,134 @@ +/* ISO14443A Manchester encoder for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +/* + * Definitions for 106kBps, at sampling clock 1695kHz + * + * bit sample pattern for one bit cycle + * MSB first LSB first hex LSB first + * Sequence D 1010101000000000 0000000001010101 0x0055 + * Sequence E 0000000010101010 0101010100000000 0x5500 + * Sequence F 1010101010101010 0101010101010101 0x5555 + * + * Logic 1 Sequence D + * Logic 0 Sequence E + * SOF Sequence D + * EOF Sequence F + * + * 212/424/848kBps: BPSK. + * + * SOF: 32 subcarrier clocks + bit '0' + * + * SOF: hex LSB first: 0x55555555 55555555 + bit '0' + * + * EOF: even parity of last byte (!) + * + */ + +#define MANCHESTER_SEQ_D 0x0055 +#define MANCHESTER_SEQ_E 0x5500 +#define MANCHESTER_SEQ_F 0x5555 + +#include +#include +#include "openpicc.h" + +static u_int32_t manchester_sample_size(u_int8_t frame_bytelen) __attribute__((unused)); +static u_int32_t manchester_sample_size(u_int8_t frame_bytelen) +{ + /* 16 bits (2 bytes) per bit => 16 bytes samples per data byte, + * plus 16bit (2 bytes) parity per data byte + * plus 16bit (2 bytes) SOF plus 16bit (2 bytes) EOF */ + return (frame_bytelen*18) + 2 + 2; + + /* this results in a maximum samples-per-frame size of 4612 bytes + * for a 256byte frame */ +} + +struct manch_enc_state { + const char *data; + char *samples; + u_int16_t *samples16; +}; + +static void manchester_enc_byte(struct manch_enc_state *mencs, u_int8_t data) __attribute__((unused)); +static void manchester_enc_byte(struct manch_enc_state *mencs, u_int8_t data) +{ + int i; + u_int8_t sum_1 = 0; + + /* append 8 sample blobs, one for each bit */ + for (i = 0; i < 8; i++) { + if (data & (1 << i)) { + *(mencs->samples16) = MANCHESTER_SEQ_D; + sum_1++; + } else { + *(mencs->samples16) = MANCHESTER_SEQ_E; + } + mencs->samples16++; + } + /* append odd parity */ + if (sum_1 & 0x01) + *(mencs->samples16) = MANCHESTER_SEQ_E; + else + *(mencs->samples16) = MANCHESTER_SEQ_D; + mencs->samples16++; +} + +#if 0 +/* Broken? */ +int manchester_encode(char *sample_buf, u_int16_t sample_buf_len, + const char *data, u_int8_t data_len) +{ + int i, enc_size; + struct manch_enc_state mencs; + + enc_size = manchester_sample_size(data_len); + + if (sample_buf_len < enc_size) + return -EINVAL; + + /* SOF */ + *(mencs.samples16++) = MANCHESTER_SEQ_D; + + for (i = 0; i < data_len; i++) + manchester_enc_byte(&mencs, data[i]); + + /* EOF */ + *(mencs.samples16++) = MANCHESTER_SEQ_F; + + return enc_size; +} +#endif +#if 0 +/* Broken? */ +#define BPSK_SPEED_212 + + +static u_int32_t bpsk_sample_size(u_int8_t frame_bytelen); + +int bpsk_encode(char *sample_buf, u_int16_t sample_buf_len, + const char *data, u_int8_t data_len) +{ + /* burst of 32 sub carrier cycles */ + memset(sample_buf, 0x55, 8); + +} +#endif diff --git a/openpicc/application/load_modulation.c b/openpicc/application/load_modulation.c new file mode 100644 index 0000000..976d57f --- /dev/null +++ b/openpicc/application/load_modulation.c @@ -0,0 +1,49 @@ +/* AT91SAM7 PWM routines for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include + +#include "openpicc.h" + +void load_mod_level(u_int8_t level) +{ + if (level > 3) + level = 3; + + if (level & 0x1) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD1); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD1); + + if (level & 0x2) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD2); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD2); +} + +void load_mod_init(void) +{ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD1); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD2); + + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD1); + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_LOAD2); +} diff --git a/openpicc/application/load_modulation.h b/openpicc/application/load_modulation.h new file mode 100644 index 0000000..71f9d6f --- /dev/null +++ b/openpicc/application/load_modulation.h @@ -0,0 +1,7 @@ +#ifndef _LOAD_MODULATION_H +#define _LOAD_MODULATION_H + +extern void load_mod_level(u_int8_t level); +extern void load_mod_init(void); + +#endif diff --git a/openpicc/application/main.c b/openpicc/application/main.c index 37cc24a..48e9ab2 100644 --- a/openpicc/application/main.c +++ b/openpicc/application/main.c @@ -102,6 +102,8 @@ void main_help_print_buffer(ssc_dma_buffer_t *buffer, int *pktcount) DumpStringToUSB(" "); } dumped = 1; + DumpUIntToUSB(i); + DumpStringToUSB(": "); for(j=0; j> j) & 0x1) ? '1' : '_' , 0); } diff --git a/openpicc/config/board.h b/openpicc/config/board.h index 18cfe9e..61eab3c 100644 --- a/openpicc/config/board.h +++ b/openpicc/config/board.h @@ -73,6 +73,9 @@ #define OPENPICC_ADC_FIELD_STRENGTH AT91C_ADC_CH4 +#define OPENPICC_PIO_LOAD1 AT91C_PIO_PA2 +#define OPENPICC_PIO_LOAD2 AT91C_PIO_PA3 + #define OPENPICC_PIO_CARRIER_IN AT91C_PA28_TCLK1 #define OPENPICC_PIO_CARRIER_DIV_OUT AT91C_PA1_TIOB0 #define OPENPICC_PIO_CDIV_HELP_OUT AT91C_PA0_TIOA0 -- cgit v1.2.3