]> sigrok.org Git - libsigrokdecode.git/blob - decoders/seven_segment/pd.py
seven_segment: document segment layout for awareness during maintenance
[libsigrokdecode.git] / decoders / seven_segment / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2019 Benedikt Otto <benedikt_o@web.de>
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
18 ##
19
20 import sigrokdecode as srd
21
22 class ChannelError(Exception):
23     pass
24
25 # This table is sorted by ASCII code numbers, with the exception
26 # of letters having their upper/lower case ignored.
27 #
28 # Traditional LED segment names and layout:
29 #
30 #      A
31 #    F   B
32 #      G
33 #    E   C
34 #      D
35 #
36 #    A  B  C  D  E  F  G
37 digits = {
38     (0, 0, 0, 0, 0, 0, 0): ' ',
39     (0, 1, 0, 0, 0, 1, 0): '"',
40     (1, 1, 0, 1, 1, 1, 1): "&",
41     (0, 0, 0, 0, 0, 1, 0): "'",
42     (0, 1, 0, 0, 0, 0, 0): "'",
43     (0, 0, 1, 1, 0, 0, 0): ',',
44     (0, 0, 0, 0, 0, 0, 1): '-',
45     (0, 0, 0, 0, 1, 0, 0): '.',
46     (1, 1, 1, 1, 1, 1, 0): '0',
47     (0, 1, 1, 0, 0, 0, 0): '1',
48     (1, 1, 0, 1, 1, 0, 1): '2',
49     (1, 1, 1, 1, 0, 0, 1): '3',
50     (0, 1, 1, 0, 0, 1, 1): '4',
51     (1, 0, 1, 1, 0, 1, 1): '5',
52     (1, 0, 1, 1, 1, 1, 1): '6',
53     (1, 1, 1, 0, 0, 1, 0): '7',
54     (1, 1, 1, 0, 0, 0, 0): '7',
55     (1, 1, 1, 1, 1, 1, 1): '8',
56     (1, 1, 1, 1, 0, 1, 1): '9',
57     (1, 0, 0, 0, 0, 0, 1): '=',
58     (0, 0, 0, 1, 0, 0, 1): '=',
59     (1, 1, 0, 0, 1, 0, 1): '?',
60     (1, 1, 1, 0, 1, 1, 1): 'A',
61     (1, 1, 1, 1, 1, 0, 1): 'a',
62     (0, 0, 1, 1, 1, 1, 1): 'b',
63     (1, 0, 0, 1, 1, 1, 0): 'C',
64     (0, 0, 0, 1, 1, 0, 1): 'c',
65     (0, 1, 1, 1, 1, 0, 1): 'd',
66     (1, 0, 0, 1, 1, 1, 1): 'E',
67     (1, 0, 0, 0, 1, 1, 1): 'F',
68     (1, 0, 1, 1, 1, 1, 0): 'G',
69     (0, 1, 1, 0, 1, 1, 1): 'H',
70     (0, 0, 1, 0, 1, 1, 1): 'h',
71     (0, 0, 0, 0, 1, 1, 0): 'I',
72     (1, 0, 0, 0, 1, 0, 0): 'i',
73     (0, 0, 1, 0, 0, 0, 0): 'i',
74     (0, 1, 1, 1, 1, 0, 0): 'J',
75     (0, 1, 1, 1, 0, 0, 0): 'J',
76     (1, 0, 1, 1, 0, 0, 0): 'j',
77     (1, 0, 1, 0, 1, 1, 1): 'K',
78     (0, 0 ,0, 1, 1, 1, 0): 'L',
79     (1, 0, 1, 0, 1, 0, 0): 'M',
80     (1, 0, 1, 0, 1, 0, 1): 'M',
81     (1, 1, 1, 0, 1, 1, 0): 'N',
82     (0, 0, 1, 0, 1, 0, 1): 'n',
83     (0, 0, 1, 1, 1, 0, 1): 'o',
84     (1, 1, 0, 0, 1, 1, 1): 'p',
85     (1, 1, 1, 0, 0, 1, 1): 'q',
86     (1, 1, 0, 0, 1, 1, 0): 'R',
87     (0, 0, 0, 0, 1, 0, 1): 'r',
88     (0, 0, 0, 1, 1, 1, 1): 't',
89     (0, 0, 1, 1, 1, 0, 0): 'u',
90     (0, 1, 0, 1, 0, 1, 0): 'V',
91     (0, 1, 0, 0, 1, 1, 1): 'V',
92     (0, 1, 1, 1, 1, 1, 0): 'V',
93     (0, 1, 0, 0, 0, 1, 1): 'v',
94     (0, 1, 0, 1, 0, 1, 1): 'W',
95     (0, 0, 1, 0, 1, 0, 0): 'x',
96     (0, 1, 1, 1, 0, 1, 1): 'y',
97     (1, 1, 0, 1, 1, 0, 0): 'Z',
98     (1, 1, 0, 0, 0, 1, 0): '^',
99     (0, 0, 0, 1, 0, 0, 0): '_',
100 }
101
102 class Decoder(srd.Decoder):
103     api_version = 3
104     id = 'seven_segment'
105     name = '7-segment'
106     longname = '7-segment display'
107     desc = '7-segment display protocol.'
108     license = 'gplv2+'
109     inputs = ['logic']
110     outputs = []
111     tags = ['Display']
112     channels = (
113         {'id': 'a', 'name': 'A', 'desc': 'Segment A'},
114         {'id': 'b', 'name': 'B', 'desc': 'Segment B'},
115         {'id': 'c', 'name': 'C', 'desc': 'Segment C'},
116         {'id': 'd', 'name': 'D', 'desc': 'Segment D'},
117         {'id': 'e', 'name': 'E', 'desc': 'Segment E'},
118         {'id': 'f', 'name': 'F', 'desc': 'Segment F'},
119         {'id': 'g', 'name': 'G', 'desc': 'Segment G'},
120     )
121     optional_channels = (
122         {'id': 'dp', 'name': 'DP', 'desc': 'Decimal point'},
123     )
124     options = (
125         {'id': 'polarity', 'desc': 'Expected polarity',
126             'default': 'common-cathode', 'values': ('common-cathode', 'common-anode')},
127         {'id': 'show_unknown', 'desc': 'Display Unknown characters as #',
128             'default': 'no', 'values': ('yes', 'no')},
129     )
130     annotations = (
131         ('decoded-digit', 'Decoded digit'),
132     )
133     annotation_rows = (
134         ('decoded-digits', 'Decoded digits', (0,)),
135     )
136
137     def __init__(self):
138         self.reset()
139
140     def reset(self):
141         pass
142
143     def start(self):
144         self.out_ann = self.register(srd.OUTPUT_ANN)
145
146     def putb(self, ss_block, es_block, data):
147         self.put(ss_block, es_block, self.out_ann, data)
148
149     def pins_to_hex(self, pins):
150         return digits.get(pins, None)
151
152     def decode(self):
153         oldpins = self.wait()
154
155         # Check if at least the 7 signals are present.
156         if False in [p in (0, 1) for p in oldpins[:7]]:
157             raise ChannelError('7 or 8 pins have to be present.')
158
159         lastpos = self.samplenum
160
161         self.have_dp = self.has_channel(7)
162
163         conditions = [{0: 'e'}, {1: 'e'}, {2: 'e'}, {3: 'e'}, {4: 'e'}, {5: 'e'}, {6: 'e'}]
164
165         if self.have_dp:
166             conditions.append({7: 'e'})
167
168         while True:
169             # Wait for any change.
170             pins = self.wait(conditions)
171
172             if self.options['polarity'] == 'common-anode':
173                 # Invert all data lines if a common anode display is used.
174                 if self.have_dp:
175                     oldpins = tuple((1 - state for state in oldpins))
176                 else:
177                     oldpins = tuple((1 - state for state in oldpins[:7]))
178
179             # Convert to character string.
180             digit = self.pins_to_hex(oldpins[:7])
181
182             if digit is None and self.options['show_unknown'] == 'yes':
183                 digit = '#'
184
185             if digit is not None:
186                 dp = oldpins[7]
187
188                 # Check if decimal point is present and active.
189                 if self.have_dp and dp == 1:
190                     digit += '.'
191
192                 self.putb(lastpos, self.samplenum, [0, [digit]])
193
194             lastpos = self.samplenum
195
196             oldpins = pins