Hi.

I've written a basic PS/2 protocol decoder.
It still has some issues decoding keyboard initialization sequences but
works fine for normal keyboard to host communication.

I've attached the commit adding the decoder against libsigrokdecode
master to this email.

Regards
Daniel
>From ac1e0bad67bc58706071399bfc917ffa5e326d16 Mon Sep 17 00:00:00 2001
From: Daniel Schulte <trila...@schroedingers-bit.net>
Date: Wed, 12 Oct 2016 23:26:19 +0200
Subject: [PATCH] Add initial version of PS/2 decoder

---
 decoders/ps2/__init__.py |  30 +++++++++++
 decoders/ps2/pd.py       | 132 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+)
 create mode 100644 decoders/ps2/__init__.py
 create mode 100644 decoders/ps2/pd.py

diff --git a/decoders/ps2/__init__.py b/decoders/ps2/__init__.py
new file mode 100644
index 0000000..1821fb4
--- /dev/null
+++ b/decoders/ps2/__init__.py
@@ -0,0 +1,30 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2016 Daniel Schulte <trila...@schroedingers-bit.net>
+##
+## 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
+##
+
+'''
+This protocol decoder can decode PS/2 Keyboard <-> Host communication.
+
+This decoder checks for coreect start and stop bits as well as parity
+errors.
+
+Host to device communication is currently untested.
+'''
+
+from .pd import Decoder
diff --git a/decoders/ps2/pd.py b/decoders/ps2/pd.py
new file mode 100644
index 0000000..0bab07e
--- /dev/null
+++ b/decoders/ps2/pd.py
@@ -0,0 +1,132 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2016 Daniel Schulte <trila...@schroedingers-bit.net>
+##
+## 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
+##
+
+import sigrokdecode as srd
+
+
+def channel_list(num_channels):
+    return ({'id': 'clk', 'name': 'Clock', 'desc': 'Clock line'},
+            {'id': 'data', 'name': 'Data', 'desc': 'Data line'})
+
+
+class ChannelError(Exception):
+    pass
+
+
+class AnnotationTypes:
+    START, STOP, PARITY, WORD = range(4)
+
+
+class Decoder(srd.Decoder):
+    api_version = 2
+    id = 'ps2'
+    name = 'PS/2'
+    longname = 'PS/2'
+    desc = 'PS/2 Keyboard interface.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['ps2']
+    optional_channels = channel_list(2)
+    annotations = (
+        ('start-bit', 'Start Bit'),
+        ('stop-bit', 'Stop Bit'),
+        ('parity', 'Parity'),
+        ('word', 'Word')
+    )
+
+    def __init__(self):
+        self.bits = []
+        self.prev_pins = None
+        self.prev_clock = None
+
+        self.current_sample_index = 0
+        self.bits_start_on_sample = None
+        self.clock_was_high = False
+
+    def start(self):
+        self.out_ann = self.register(srd.OUTPUT_ANN)
+
+    def handle_bits(self, datapin):
+
+        # Ignore non start condition bits (useful during keyboard init)
+        if len(self.bits) == 0 and datapin == 1:
+            return
+
+        # If this is the first bit in a word, save its sample number.
+        if len(self.bits) == 0:
+            self.bits_start_on_sample = self.current_sample_index
+
+        self.bits.append(datapin)
+
+        # Find all 11 bits. Start + 8 Data + odd Parity + Stop
+        if len(self.bits) < 11:
+            return
+
+        # Extract data word
+        word = 0
+        for i in range(8):
+            word |= self.bits[i + 1] << i
+
+        bit_start, bit_stop, bit_parity = self.bits[
+            0], self.bits[10], self.bits[9]
+
+        bitstring = "".join([str(i) for i in self.bits])
+        parity_ok = (bin(word).count('1') + bit_parity) % 2 == 1
+
+        if bit_start == 0 and bit_stop == 1 and parity_ok:
+            self.put(self.bits_start_on_sample, self.current_sample_index,
+                     self.out_ann, [AnnotationTypes.WORD, ['OK: %X (%s)' % (word, bitstring)]])
+        else:
+            self.put(self.bits_start_on_sample, self.current_sample_index,
+                     self.out_ann, [AnnotationTypes.WORD, ['Fail: %X (%s)' % (word, bitstring)]])
+
+        self.bits, self.bits_start_on_sample = [], 0
+
+    def find_clk_edge(self, clock_pin, data_pin):
+        # Ignore sample if the clock pin hasn't changed.
+        if clock_pin == self.prev_clock:
+            return
+        self.prev_clock = clock_pin
+
+        # Sample on falling clock edge.
+        # So return as long as the Clock line is high
+        if clock_pin == 1:
+            return
+
+        # Found the correct clock edge, now get the bits.
+        self.handle_bits(data_pin)
+
+    def decode(self, sample_from, sample_to, data):
+        for (self.current_sample_index, pins) in data:
+            clock_pin, data_pin = pins[0], pins[1]
+
+            # Ignore identical samples. Nothing happend
+            if self.prev_pins == pins:
+                continue
+            self.prev_pins = pins
+
+            if clock_pin == 0 and not self.clock_was_high:
+                continue
+            self.clock_was_high = True
+
+            # if clock_pin not in (0, 1):
+            #    self.handle_bits(data_pin)
+            # else:
+            self.find_clk_edge(clock_pin, data_pin)
-- 
2.10.0

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to