From: Benjamin Larsson Date: Tue, 15 Dec 2015 00:00:01 +0000 (+0100) Subject: Add RFID EM4100 protocol decoding X-Git-Tag: libsigrokdecode-0.4.0~14 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=8f26590799306bf7e13241c345adbf1fde811ec7;hp=033e7d4db76f2e2a289d5567e9532f26201cfa74 Add RFID EM4100 protocol decoding --- diff --git a/decoders/em4100/__init__.py b/decoders/em4100/__init__.py new file mode 100644 index 0000000..cff361f --- /dev/null +++ b/decoders/em4100/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +''' +EM4100 is a biphase/manchester/PSK based 100-150kHz RFID protocol. +''' + +from .pd import Decoder diff --git a/decoders/em4100/pd.py b/decoders/em4100/pd.py new file mode 100644 index 0000000..a870874 --- /dev/null +++ b/decoders/em4100/pd.py @@ -0,0 +1,242 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Benjamin Larsson +## +## 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 data 2 of the License, or +## (at your option) any later data. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 2 + id = 'em4100' + name = 'EM4100' + longname = 'RFID EM4100' + desc = 'EM4100 100-150kHz RFID protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['em4100'] + channels = ( + {'id': 'data', 'name': 'Data', 'desc': 'Data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', + 'values': ('active-low', 'active-high')}, + {'id': 'datarate' , 'desc': 'Data rate', 'default': '64', + 'values': ('64', '32', '16')}, +# {'id': 'coding', 'desc': 'Bit coding', 'default': 'biphase', +# 'values': ('biphase', 'manchester', 'psk')}, + {'id': 'coilfreq', 'desc': 'Coil frequency', 'default': '125000'}, + ) + annotations = ( + ('headerbit', 'Header bit'), + ('databit', 'Version bit'), + ('rowparity', 'Row Parity'), + ('databit', 'Data bit'), + ('colparity', 'Column Parity'), + ('stopbit', 'Stop bit'), + ('rowparity_check', 'Row Parity Check'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('fields', 'Fields', (1, 2, 4, 7)), + ('value', 'Value', (3, 5, 6, 8)), + ) + + def __init__(self, **kwargs): + self.samplerate = None + self.oldpin = None + self.last_samplenum = None + self.lastlast_samplenum = None + self.last_edge = 0 + self.bit_width = 0 + self.halfbit_limit = 0 + self.oldpp = 0 + self.oldpl = 0 + self.oldsamplenum = 0 + self.last_bit_pos = 0 + self.first_start = 0 + self.first_one = 0 + self.state = 'HEADER' + self.data = 0 + self.data_bits = 0 + self.data_start = 0 + self.data_parity = 0 + self.payload_cnt = 0 + self.data_col_parity = [0, 0, 0, 0, 0, 0] + self.col_parity = [0, 0, 0, 0, 0, 0] + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + self.bit_width = (self.samplerate / (int(self.options['coilfreq']))) * int(self.options['datarate']) + self.halfbit_limit = self.bit_width/2 + self.bit_width/4 + self.polarity = 0 if self.options['polarity'] == 'active-low' else 1 + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def add_bit(self, bit, bit_start, bit_stop): + if self.state == 'HEADER': + if bit == 1: + if self.first_one > 0: + self.first_one += 1 + if self.first_one == 9: + self.put(int(self.first_start), int(bit_stop), self.out_ann, + [1, ['Header', 'Head', 'He', 'H']]) + self.first_one = 0 + self.state = 'PAYLOAD' + return + if self.first_one == 0: + self.first_one = 1 + self.first_start = bit_start + + if bit == 0: + self.first_one = 0 + return + + if self.state == 'PAYLOAD': + self.payload_cnt += 1 + if self.data_bits == 0: + self.data_start = bit_start + self.data = 0 + self.data_parity = 0 + self.data_bits += 1 + if self.data_bits == 5: + self.put(int(self.data_start), int(bit_start), self.out_ann, + [2, ['Data', 'Da', 'D']]) + self.put(int(bit_start), int(bit_stop), self.out_ann, + [4, ['Parity', 'Par', 'Pa', 'P']]) + self.put(int(self.data_start), int(bit_start), self.out_ann, + [3, [str("%X" % self.data)]]) + if self.data_parity == bit: + p_string = ['OK', 'O'] + else: + p_string = ['ERROR', 'ERR', 'ER', 'E'] + self.put(int(bit_start), int(bit_stop), self.out_ann, + [6, p_string]) + self.data_bits = 0 + if self.payload_cnt == 50: + self.state = 'TRAILER' + self.payload_cnt = 0 + + self.data_parity ^= bit + self.data_col_parity[self.data_bits] ^= bit + self.data = (self.data << 1) | bit + return + + if self.state == 'TRAILER': + self.payload_cnt += 1 + if self.data_bits == 0: + self.data_start = bit_start + self.data = 0 + self.data_parity = 0 + self.data_bits += 1 + self.col_parity[self.data_bits] = bit + + if self.data_bits == 5: + p_string = ['ERROR', 'ERR', 'ER', 'E'] + if self.data_col_parity[1] == self.col_parity[1]: + if self.data_col_parity[2] == self.col_parity[2]: + if self.data_col_parity[3] == self.col_parity[3]: + if self.data_col_parity[4] == self.col_parity[4]: + p_string = ['OK', 'O'] + + self.put(int(self.data_start), int(bit_start), self.out_ann, + [4, ['Column parity', 'Col par', 'CP', 'P']]) + self.put(int(bit_start), int(bit_stop), self.out_ann, + [4, ['Stop bit', 'St bi', 'SB', 'S']]) + self.put(int(self.data_start), int(bit_start), self.out_ann, + [6, p_string]) + + self.data_bits = 0 + if self.payload_cnt == 5: + self.state = 'HEADER' + self.payload_cnt = 0 + self.data_col_parity = [0, 0, 0, 0, 0, 0] + self.col_parity = [0, 0, 0, 0, 0, 0] + + def putbit(self, bit, bit_start, bit_stop): + self.put(int(bit_start), int(bit_stop), self.out_ann, + [0, [str(bit)]]) + self.add_bit(bit, bit_start, bit_stop) + + def manchester_decode(self, samplenum, pl, pp, pin): + bit_start = 0 + bit_stop = 0 + bit = self.oldpin ^ self.polarity + if pl > self.halfbit_limit: + samples = samplenum - self.oldsamplenum + t = samples / self.samplerate + + if self.oldpl > self.halfbit_limit: + bit_start = int(self.oldsamplenum - self.oldpl/2) + bit_stop = int(samplenum - pl/2) + self.putbit(bit, bit_start, bit_stop) + if self.oldpl <= self.halfbit_limit: + bit_start = int(self.oldsamplenum - self.oldpl) + bit_stop = int(samplenum - pl/2) + self.putbit(bit, bit_start, bit_stop) + self.last_bit_pos = int(samplenum - pl/2) + + if pl < self.halfbit_limit: + samples = samplenum - self.oldsamplenum + t = samples / self.samplerate + + if self.oldpl > self.halfbit_limit: + bit_start = self.oldsamplenum - self.oldpl/2 + bit_stop = int(samplenum) + self.putbit(bit, bit_start, bit_stop) + self.last_bit_pos = int(samplenum) + if self.oldpl <= self.halfbit_limit: + if self.last_bit_pos <= self.oldsamplenum - self.oldpl: + bit_start = self.oldsamplenum - self.oldpl + bit_stop = int(samplenum) + self.putbit(bit, bit_start, bit_stop) + self.last_bit_pos = int(samplenum) + + def decode(self, ss, es, data): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + for (samplenum, (pin,)) in data: + # Ignore identical samples early on (for performance reasons). + if self.oldpin == pin: + continue + + if self.oldpin is None: + self.oldpin = pin + self.last_samplenum = samplenum + self.lastlast_samplenum = samplenum + self.last_edge = samplenum + self.oldpl = 0 + self.oldpp = 0 + self.oldsamplenum = 0 + self.last_bit_pos = 0 + continue + + if self.oldpin != pin: + pl = samplenum - self.oldsamplenum + pp = pin + + self.manchester_decode(samplenum, pl, pp, pin) + + self.oldpl = pl + self.oldpp = pp + self.oldsamplenum = samplenum + self.oldpin = pin