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