From 23a8a38357ed6917d2471f46f65b158379ad564e Mon Sep 17 00:00:00 2001 From: Jeremy Swanson Date: Thu, 16 Feb 2017 16:29:47 +0000 Subject: Add a DSI protocol decoder. --- decoders/dsi/__init__.py | 24 +++++++ decoders/dsi/pd.py | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 decoders/dsi/__init__.py create mode 100644 decoders/dsi/pd.py (limited to 'decoders/dsi') diff --git a/decoders/dsi/__init__.py b/decoders/dsi/__init__.py new file mode 100644 index 0000000..bfba867 --- /dev/null +++ b/decoders/dsi/__init__.py @@ -0,0 +1,24 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +''' +DSI is a biphase/manchester based lighting control protocol. +''' + +from .pd import Decoder diff --git a/decoders/dsi/pd.py b/decoders/dsi/pd.py new file mode 100644 index 0000000..dc19ba2 --- /dev/null +++ b/decoders/dsi/pd.py @@ -0,0 +1,164 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2015 Jeremy Swanson +## +## 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, see . +## + +import sigrokdecode as srd + +class SamplerateError(Exception): + pass + +class Decoder(srd.Decoder): + api_version = 2 + id = 'dsi' + name = 'DSI' + longname = 'Digital Serial Interface Lighting' + desc = 'DSI lighting control protocol.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['dsi'] + channels = ( + {'id': 'dsi', 'name': 'DSI', 'desc': 'DSI data line'}, + ) + options = ( + {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-high', + 'values': ('active-low', 'active-high')}, + ) + annotations = ( + ('bit', 'Bit'), + ('startbit', 'Startbit'), + ('Level', 'Dimmer level'), + ('raw', 'Raw data'), + ) + annotation_rows = ( + ('bits', 'Bits', (0,)), + ('raw', 'Raw Data',(3,)), + ('fields', 'Fields', (1, 2,)), + ) + + def __init__(self): + self.samplerate = None + self.samplenum = None + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + self.nextSamplePoint = None + self.nextSample = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.old_ir = 1 if self.options['polarity'] == 'active-low' else 0 + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + # One bit: 1666.7us (one half low, one half high). + # This is how many samples are in 1TE. + self.halfbit = int((self.samplerate * 0.0016667) / 2.0) + + def putb(self, bit1, bit2, data): + ss, es = self.ss_es_bits[bit1][0], self.ss_es_bits[bit2][1] + self.put(ss, es, self.out_ann, data) + + def handle_bits(self, length): + a, c, f, g, b = 0, 0, 0, 0, self.bits + # Individual raw bits. + for i in range(length): + if i == 0: + ss = max(0, self.bits[0][0]) + else: + ss = self.ss_es_bits[i - 1][1] + es = self.bits[i][0] + (self.halfbit * 2) + self.ss_es_bits.append([ss, es]) + self.putb(i, i, [0, ['%d' % self.bits[i][1]]]) + # Bits[0:0]: Startbit + s = ['Startbit: %d' % b[0][1], 'ST: %d' % b[0][1], 'ST', 'S', 'S'] + self.putb(0, 0, [1, s]) + self.putb(0, 0, [3, s]) + # Bits[1:8] + for i in range(8): + f |= (b[1 + i][1] << (7 - i)) + g = f / 2.55 + if length == 9: # BACKWARD Frame + s = ['Data: %02X' % f, 'Dat: %02X' % f, + 'Dat: %02X' % f, 'D: %02X' % f, 'D'] + self.putb(1, 8, [3, s]) + s = ['Level: %d%%' % g, 'Lev: %d%%' % g, + 'Lev: %d%%' % g, 'L: %d' % g, 'D'] + self.putb(1, 8, [2, s]) + return + + def reset_decoder_state(self): + self.edges, self.bits, self.ss_es_bits = [], [], [] + self.state = 'IDLE' + + def decode(self, ss, es, data): + if not self.samplerate: + raise SamplerateError('Cannot decode without samplerate.') + bit = 0; + for (self.samplenum, pins) in data: + self.ir = pins[0] + # data.itercnt += 1 + if self.options['polarity'] == 'active-high': + self.ir ^= 1 # Invert. + + # State machine. + if self.state == 'IDLE': + # Wait for any edge (rising or falling). + if self.old_ir == self.ir: + continue + # Add in the first half of the start bit. + self.edges.append(self.samplenum - int(self.halfbit)) + self.edges.append(self.samplenum) + # Start bit is 0->1. + self.phase0 = self.ir ^ 1 + self.state = 'PHASE1' + self.old_ir = self.ir + # Get the next sample point. + # self.nextSamplePoint = self.samplenum + int(self.halfbit / 2) + self.old_ir = self.ir + # bit = self.ir + continue + + # if(self.samplenum == self.nextSamplePoint): + # bit = self.ir + # continue + + if self.old_ir != self.ir: + self.edges.append(self.samplenum) + elif self.samplenum == (self.edges[-1] + int(self.halfbit * 1.5)): + self.edges.append(self.samplenum - int(self.halfbit * 0.5)) + else: + continue + + bit = self.old_ir + if self.state == 'PHASE0': + self.phase0 = bit + self.state = 'PHASE1' + elif self.state == 'PHASE1': + if (bit == 1) and (self.phase0 == 1): # Stop bit + if len(self.bits) == 17 or len(self.bits) == 9: + # Forward or Backward + self.handle_bits(len(self.bits)) + self.reset_decoder_state() # Reset upon errors. + continue + else: + self.bits.append([self.edges[-3], bit]) + self.state = 'PHASE0' + + # self.nextSamplePoint = self.edges[-1] + int(self.halfbit / 2) + + self.old_ir = self.ir -- cgit v1.2.3-70-g09d2