22## This file is part of the libsigrokdecode project.
33##
44## Copyright (C) 2016 Daniel Schulte <[email protected] > 5+ ## Copyright (C) 2023 Marshal Horn <[email protected] > 56##
67## This program is free software; you can redistribute it and/or modify
78## it under the terms of the GNU General Public License as published by
1819##
1920
2021import sigrokdecode as srd
21- from collections import namedtuple
2222
2323class Ann :
24- BIT , START , STOP , PARITY_OK , PARITY_ERR , DATA , WORD = range (7 )
24+ BIT , START , WORD , PARITY_OK , PARITY_ERR , STOP , ACK , NACK = range (8 )
25+
26+ class Bit :
27+ def __init__ (self , val , ss , es ):
28+ self .val = val
29+ self .ss = ss
30+ self .es = es
31+
32+ class Ps2Packet :
33+ def __init__ (self , val , host = False , pok = False , ack = False ):
34+ self .val = val #byte value
35+ self .host = host #Host transmissions
36+ self .pok = pok #Parity ok
37+ self .ack = ack #Acknowlege ok for host transmission.
2538
26- Bit = namedtuple ('Bit' , 'val ss es' )
2739
2840class Decoder (srd .Decoder ):
2941 api_version = 3
3042 id = 'ps2'
3143 name = 'PS/2'
3244 longname = 'PS/2'
33- desc = 'PS/2 keyboard/mouse interface. '
45+ desc = 'PS/2 packet interface used by PC keyboards and mice '
3446 license = 'gplv2+'
3547 inputs = ['logic' ]
36- outputs = []
48+ outputs = ['ps2_packet' ]
3749 tags = ['PC' ]
3850 channels = (
3951 {'id' : 'clk' , 'name' : 'Clock' , 'desc' : 'Clock line' },
@@ -42,15 +54,22 @@ class Decoder(srd.Decoder):
4254 annotations = (
4355 ('bit' , 'Bit' ),
4456 ('start-bit' , 'Start bit' ),
45- ('stop-bit ' , 'Stop bit ' ),
57+ ('word ' , 'Word ' ),
4658 ('parity-ok' , 'Parity OK bit' ),
4759 ('parity-err' , 'Parity error bit' ),
48- ('data-bit' , 'Data bit' ),
60+ ('stop-bit' , 'Stop bit' ),
61+ ('ack' , 'Acknowledge' ),
62+ ('nack' , 'Not Acknowledge' ),
63+ ('start-bit' , 'Start bit' ),
4964 ('word' , 'Word' ),
65+ ('parity-ok' , 'Parity OK bit' ),
66+ ('parity-err' , 'Parity error bit' ),
67+ ('stop-bit' , 'Stop bit' ),
5068 )
5169 annotation_rows = (
5270 ('bits' , 'Bits' , (0 ,)),
53- ('fields' , 'Fields' , (1 , 2 , 3 , 4 , 5 , 6 )),
71+ ('fields' , 'Device' , (1 ,2 ,3 ,4 ,5 ,6 ,7 ,)),
72+ ('host' , 'Host' , (8 ,9 ,10 ,11 ,12 )),
5473 )
5574
5675 def __init__ (self ):
@@ -62,65 +81,87 @@ def reset(self):
6281
6382 def start (self ):
6483 self .out_ann = self .register (srd .OUTPUT_ANN )
65-
66- def putb (self , bit , ann_idx ):
67- b = self .bits [bit ]
68- self .put (b .ss , b .es , self .out_ann , [ann_idx , [str (b .val )]])
69-
70- def putx (self , bit , ann ):
84+ self .out_py = self .register (srd .OUTPUT_PYTHON )
85+
86+ def metadata (self ,key ,value ):
87+ if key == srd .SRD_CONF_SAMPLERATE :
88+ self .samplerate = value
89+
90+ def get_bits (self , n , edge :'r' , timeout = 100e-6 ):
91+ max_period = int (timeout * self .samplerate ) + 1
92+ for i in range (n ):
93+ _ , dat = self .wait ([{0 :edge },{'skip' :max_period }])
94+ if not self .matched [0 ]:
95+ break #Timed out
96+ self .bits .append (Bit (dat , self .samplenum , self .samplenum + max_period ))
97+ if i > 0 : #Fix the ending period
98+ self .bits [i - 1 ].es = self .samplenum
99+ if len (self .bits ) == n :
100+ self .wait ([{0 :'r' },{'skip' :max_period }])
101+ self .bits [- 1 ].es = self .samplenum
102+ self .bitcount = len (self .bits )
103+
104+ def putx (self , bit , ann , host = False ):
105+ if host :
106+ ann [0 ] += 7 #host annotation offset
71107 self .put (self .bits [bit ].ss , self .bits [bit ].es , self .out_ann , ann )
72108
73- def handle_bits (self , datapin ):
74- # Ignore non start condition bits (useful during keyboard init).
75- if self .bitcount == 0 and datapin == 1 :
76- return
77-
78- # Store individual bits and their start/end samplenumbers.
79- self .bits .append (Bit (datapin , self .samplenum , self .samplenum ))
80-
81- # Fix up end sample numbers of the bits.
82- if self .bitcount > 0 :
83- b = self .bits [self .bitcount - 1 ]
84- self .bits [self .bitcount - 1 ] = Bit (b .val , b .ss , self .samplenum )
85- if self .bitcount == 11 :
86- self .bitwidth = self .bits [1 ].es - self .bits [2 ].es
87- b = self .bits [- 1 ]
88- self .bits [- 1 ] = Bit (b .val , b .ss , b .es + self .bitwidth )
89-
90- # Find all 11 bits. Start + 8 data + odd parity + stop.
91- if self .bitcount < 11 :
92- self .bitcount += 1
93- return
94-
95- # Extract data word.
96- word = 0
97- for i in range (8 ):
98- word |= (self .bits [i + 1 ].val << i )
109+ def handle_bits (self , host = False ):
110+ # Annotate individual bits
111+ for b in self .bits :
112+ self .put (b .ss , b .es , self .out_ann , [Ann .BIT , [str (b .val )]])
113+
114+ packet = None
115+ # Annotate start bit
116+ if self .bitcount > 8 :
117+ self .putx (0 , [Ann .START , ['Start bit' , 'Start' , 'S' ]], host )
118+ # Annotate the data word
119+ word = 0
120+ for i in range (8 ):
121+ word |= (self .bits [i + 1 ].val << i )
122+ self .put (self .bits [1 ].ss , self .bits [8 ].es , self .out_ann ,
123+ [Ann .WORD + 7 if host else Ann .WORD ,
124+ ['Data: %02x' % word , 'D: %02x' % word , '%02x' % word ]])
125+ packet = Ps2Packet (val = word , host = host )
99126
100127 # Calculate parity.
101- parity_ok = (bin (word ).count ('1' ) + self .bits [9 ].val ) % 2 == 1
102-
103- # Emit annotations.
104- for i in range (11 ):
105- self .putb (i , Ann .BIT )
106- self .putx (0 , [Ann .START , ['Start bit' , 'Start' , 'S' ]])
107- self .put (self .bits [1 ].ss , self .bits [8 ].es , self .out_ann , [Ann .WORD ,
108- ['Data: %02x' % word , 'D: %02x' % word , '%02x' % word ]])
109- if parity_ok :
110- self .putx (9 , [Ann .PARITY_OK , ['Parity OK' , 'Par OK' , 'P' ]])
111- else :
112- self .putx (9 , [Ann .PARITY_ERR , ['Parity error' , 'Par err' , 'PE' ]])
113- self .putx (10 , [Ann .STOP , ['Stop bit' , 'Stop' , 'St' , 'T' ]])
114-
115- self .bits , self .bitcount = [], 0
128+ if self .bitcount > 9 :
129+ parity_ok = 0
130+ for bit in self .bits [1 :10 ]:
131+ parity_ok ^= bit .val
132+ if bool (parity_ok ):
133+ self .putx (9 , [Ann .PARITY_OK , ['Parity OK' , 'Par OK' , 'P' ]], host )
134+ packet .pok = True #Defaults to false in case packet was interrupted
135+ else :
136+ self .putx (9 , [Ann .PARITY_ERR , ['Parity error' , 'Par err' , 'PE' ]], host )
137+
138+ # Annotate stop bit
139+ if self .bitcount > 10 :
140+ self .putx (10 , [Ann .STOP + 7 if host else Ann .STOP , ['Stop bit' , 'Stop' , 'St' , 'T' ]])
141+ # Annotate ACK
142+ if host and self .bitcount > 11 :
143+ if self .bits [11 ].val == 0 :
144+ self .putx (11 , [Ann .ACK , ['Acknowledge' , 'Ack' , 'A' ]])
145+ else :
146+ self .putx (11 , [Ann .NACK , ['Not Acknowledge' , 'Nack' , 'N' ]])
147+ packet .ack = not bool (self .bits [11 ].val )
148+
149+ if (packet ):
150+ self .put (self .bits [0 ].ss , self .bits [- 1 ].ss , self .out_py ,packet )
151+ self .reset ()
152+
116153
117154 def decode (self ):
155+ if not self .samplerate :
156+ raise SamplerateError ("Cannot decode without samplerate" )
118157 while True :
119- # Sample data bits on the falling clock edge (assume the device
120- # is the transmitter). Expect the data byte transmission to end
121- # at the rising clock edge. Cope with the absence of host activity.
122- _ , data_pin = self .wait ({0 : 'f' })
123- self .handle_bits (data_pin )
124- if self .bitcount == 1 + 8 + 1 + 1 :
125- _ , data_pin = self .wait ({0 : 'r' })
126- self .handle_bits (data_pin )
158+ # Falling edge of data indicates start condition
159+ clk , dat = self .wait ({1 : 'l' })
160+ host = not bool (clk )
161+ if host :
162+ # Host emits bits on rising clk edge
163+ self .get_bits (12 , 'r' )
164+ else :
165+ # Client emits data on falling edge
166+ self .get_bits (11 , 'f' )
167+ self .handle_bits (host = host )
0 commit comments