summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openpcd/firmware/src/picc/decoder.c62
-rw-r--r--openpcd/firmware/src/picc/decoder.h32
-rw-r--r--openpcd/firmware/src/picc/decoder_miller.c111
-rw-r--r--openpcd/firmware/src/picc/decoder_nrzl.c89
-rw-r--r--openpcd/firmware/src/picc/iso14443a_manchester.c106
-rw-r--r--openpcd/firmware/src/picc/piccsim.h23
6 files changed, 423 insertions, 0 deletions
diff --git a/openpcd/firmware/src/picc/decoder.c b/openpcd/firmware/src/picc/decoder.c
new file mode 100644
index 0000000..2ca051f
--- /dev/null
+++ b/openpcd/firmware/src/picc/decoder.c
@@ -0,0 +1,62 @@
+/* Decoder Core for OpenPCD / OpenPICC
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ */
+
+#include <sys/types.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, char *data_buf)
+{
+ int 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 algo, struct decoder_algo *algo)
+{
+ if (algo >= DECODER_NUM_ALGOS)
+ return -EINVAL;
+
+ decoder_algos[algo] = algo;
+
+ return 0;
+}
+
+int decoder_init(void)
+{
+ decoder_register(DECODER_MILLER, &miller_decoder);
+ decoder_register(DECODER_NRZL, &nrzl_decoder);
+}
diff --git a/openpcd/firmware/src/picc/decoder.h b/openpcd/firmware/src/picc/decoder.h
new file mode 100644
index 0000000..950efd2
--- /dev/null
+++ b/openpcd/firmware/src/picc/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_int8_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 algo, struct decoder_algo *algo);
+extern int decoder_decode(u_int8_t algo, const char *sample_buf,
+ int sample_buf_size, 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/openpcd/firmware/src/picc/decoder_miller.c b/openpcd/firmware/src/picc/decoder_miller.c
new file mode 100644
index 0000000..4036511
--- /dev/null
+++ b/openpcd/firmware/src/picc/decoder_miller.c
@@ -0,0 +1,111 @@
+/*
+ * ISO14443A modified Miller decoder
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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 <sys/types.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' ", bit_sample);
+ 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;
+ int err, 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;
+ u_int8_t parity_sample;
+
+ /* 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 (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;
+}
+
+static 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/openpcd/firmware/src/picc/decoder_nrzl.c b/openpcd/firmware/src/picc/decoder_nrzl.c
new file mode 100644
index 0000000..bb297db
--- /dev/null
+++ b/openpcd/firmware/src/picc/decoder_nrzl.c
@@ -0,0 +1,89 @@
+/* ISO 14443 B Rx (PCD->PICC) implementation
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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 <sys/types.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 */
+
+ /* 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;
+}
+
+static 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/openpcd/firmware/src/picc/iso14443a_manchester.c b/openpcd/firmware/src/picc/iso14443a_manchester.c
new file mode 100644
index 0000000..aca832c
--- /dev/null
+++ b/openpcd/firmware/src/picc/iso14443a_manchester.c
@@ -0,0 +1,106 @@
+/*
+ * ISO14443A Manchester encoder
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * 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
+
+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)
+{
+ 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++
+}
+
+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;
+}
+
+#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);
+
+}
diff --git a/openpcd/firmware/src/picc/piccsim.h b/openpcd/firmware/src/picc/piccsim.h
new file mode 100644
index 0000000..34c7bf0
--- /dev/null
+++ b/openpcd/firmware/src/picc/piccsim.h
@@ -0,0 +1,23 @@
+
+#include <librfdi/rfid_layer2_iso14443a.h>
+
+struct piccsim_state {
+ enum rfid_layer2_id l2prot;
+ unsigned char uid[10];
+ u_int8_t uid_len;
+ union {
+ struct {
+ enum iso14443a_state state;
+ enum iso14443a_level level;
+ u_int32_t flags;
+ } iso14443a;
+ struct {
+ } iso14443b;
+ } l2;
+
+ union {
+ u_int32_t flags;
+ } proto;
+}
+
+#define PICCSIM_PROT_F_AUTO_WTX 0x01
personal git repositories of Harald Welte. Your mileage may vary