]>
Commit | Line | Data |
---|---|---|
4032dedd | 1 | ## |
e8e8bec6 GS |
2 | ## This file is part of the libsigrokdecode project. |
3 | ## | |
4 | ## Copyright (C) 2014 Gump Yang <gump.yang@gmail.com> | |
5 | ## Copyright (C) 2019 Rene Staffen | |
6 | ## | |
4032dedd GS |
7 | ## This program is free software; you can redistribute it and/or modify |
8 | ## it under the terms of the GNU General Public License as published by | |
9 | ## the Free Software Foundation; either version 2 of the License, or | |
10 | ## (at your option) any later version. | |
11 | ## | |
12 | ## This program is distributed in the hope that it will be useful, | |
13 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ## GNU General Public License for more details. | |
16 | ## | |
17 | ## You should have received a copy of the GNU General Public License | |
18 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
19 | ## | |
20 | ||
e8e8bec6 | 21 | from . import irmp_library |
4032dedd GS |
22 | import sigrokdecode as srd |
23 | ||
4032dedd GS |
24 | class SamplerateError(Exception): |
25 | pass | |
26 | ||
f8c62753 GS |
27 | class LibraryError(Exception): |
28 | pass | |
29 | ||
4032dedd GS |
30 | class Decoder(srd.Decoder): |
31 | api_version = 3 | |
32 | id = 'ir_irmp' | |
33 | name = 'IR IRMP' | |
e8e8bec6 GS |
34 | longname = 'IR IRMP' |
35 | desc = 'IRMP infrared remote control multi protocol.' | |
4032dedd GS |
36 | license = 'gplv2+' |
37 | inputs = ['logic'] | |
38 | outputs = [] | |
39 | tags = ['IR'] | |
40 | channels = ( | |
41 | {'id': 'ir', 'name': 'IR', 'desc': 'Data line'}, | |
42 | ) | |
43 | options = ( | |
44 | {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', | |
45 | 'values': ('active-low', 'active-high')}, | |
4032dedd GS |
46 | ) |
47 | annotations = ( | |
48 | ('packet', 'Packet'), | |
4032dedd GS |
49 | ) |
50 | annotation_rows = ( | |
51 | ('packets', 'IR Packets', (0,)), | |
4032dedd | 52 | ) |
4032dedd | 53 | |
e8e8bec6 | 54 | def putframe(self, data): |
8c3291c7 GS |
55 | '''Emit annotation for an IR frame.''' |
56 | ||
57 | # Cache result data fields in local variables. Get the ss/es | |
58 | # timestamps, scaled to sample numbers. | |
e8e8bec6 GS |
59 | nr = data['proto_nr'] |
60 | name = data['proto_name'] | |
61 | addr = data['address'] | |
62 | cmd = data['command'] | |
63 | repeat = data['repeat'] | |
8c3291c7 | 64 | release = data['release'] |
e8e8bec6 GS |
65 | ss = data['start'] * self.rate_factor |
66 | es = data['end'] * self.rate_factor | |
8c3291c7 GS |
67 | |
68 | # Prepare display texts for several zoom levels. | |
69 | # Implementor's note: Keep list lengths for flags aligned during | |
70 | # maintenance. Make sure there are as many flags text variants | |
71 | # as are referenced by annotation text variants. Differing list | |
72 | # lengths or dynamic refs will severely complicate the logic. | |
73 | rep_txts = ['repeat', 'rep', 'r'] | |
74 | rel_txts = ['release', 'rel', 'R'] | |
75 | flag_txts = [None,] * len(rep_txts) | |
76 | for zoom in range(len(flag_txts)): | |
77 | flag_txts[zoom] = [] | |
78 | if repeat: | |
79 | flag_txts[zoom].append(rep_txts[zoom]) | |
80 | if release: | |
81 | flag_txts[zoom].append(rel_txts[zoom]) | |
82 | flag_txts = [' '.join(t) or '-' for t in flag_txts] | |
83 | flg = flag_txts # Short name for .format() references. | |
84 | txts = [ | |
85 | 'Protocol: {name} ({nr}), Address 0x{addr:04x}, Command: 0x{cmd:04x}, Flags: {flg[0]}'.format(**locals()), | |
86 | 'P: {name} ({nr}), Addr: 0x{addr:x}, Cmd: 0x{cmd:x}, Flg: {flg[1]}'.format(**locals()), | |
87 | 'P: {nr} A: 0x{addr:x} C: 0x{cmd:x} F: {flg[1]}'.format(**locals()), | |
88 | 'C:{cmd:x} A:{addr:x} {flg[2]}'.format(**locals()), | |
e8e8bec6 | 89 | 'C:{cmd:x}'.format(**locals()), |
8c3291c7 GS |
90 | ] |
91 | ||
92 | # Emit the annotation from details which were constructed above. | |
93 | self.put(ss, es, self.out_ann, [0, txts]) | |
4032dedd GS |
94 | |
95 | def __init__(self): | |
f8c62753 | 96 | self.irmp = None |
4032dedd GS |
97 | self.reset() |
98 | ||
99 | def reset(self): | |
f8c62753 | 100 | self.want_reset = True |
4032dedd GS |
101 | |
102 | def start(self): | |
103 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
104 | ||
105 | def metadata(self, key, value): | |
106 | if key == srd.SRD_CONF_SAMPLERATE: | |
107 | self.samplerate = value | |
108 | ||
4032dedd | 109 | def decode(self): |
f8c62753 GS |
110 | if not self.irmp: |
111 | try: | |
112 | self.irmp = irmp_library.IrmpLibrary() | |
113 | except Exception as e: | |
114 | txt = e.args[0] | |
115 | raise LibraryError(txt) | |
116 | if self.irmp: | |
117 | self.lib_rate = self.irmp.get_sample_rate() | |
118 | if not self.irmp or not self.lib_rate: | |
119 | raise LibraryError('Cannot access IRMP library. One instance limit exceeded?') | |
4032dedd GS |
120 | if not self.samplerate: |
121 | raise SamplerateError('Cannot decode without samplerate.') | |
e8e8bec6 | 122 | if self.samplerate % self.lib_rate: |
f8c62753 | 123 | raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(self.lib_rate)) |
e8e8bec6 | 124 | self.rate_factor = int(self.samplerate / self.lib_rate) |
f8c62753 GS |
125 | if self.want_reset: |
126 | self.irmp.reset_state() | |
127 | self.want_reset = False | |
4032dedd | 128 | |
4032dedd | 129 | self.active = 0 if self.options['polarity'] == 'active-low' else 1 |
e8e8bec6 | 130 | ir, = self.wait() |
4032dedd | 131 | while True: |
4032dedd GS |
132 | if self.active == 1: |
133 | ir = 1 - ir | |
e8e8bec6 GS |
134 | if self.irmp.add_one_sample(ir): |
135 | data = self.irmp.get_result_data() | |
136 | self.putframe(data) | |
137 | ir, = self.wait([{'skip': self.rate_factor}]) |