]> sigrok.org Git - libsigrokdecode.git/blob - decoders/ir_irmp/irmp_library.py
ir_irmp: wrapper lib, add locking and Python threading support
[libsigrokdecode.git] / decoders / ir_irmp / irmp_library.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2019 Rene Staffen
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 '''
21 Python binding for the IRMP library.
22 '''
23
24 import ctypes
25 import platform
26
27 class IrmpLibrary:
28     '''
29     Library instance for an infrared protocol detector.
30     '''
31
32     __usable_instance = None
33
34     class ResultData(ctypes.Structure):
35         _fields_ = [
36             ( 'protocol', ctypes.c_uint32, ),
37             ( 'protocol_name', ctypes.c_char_p, ),
38             ( 'address', ctypes.c_uint32, ),
39             ( 'command', ctypes.c_uint32, ),
40             ( 'flags', ctypes.c_uint32, ),
41             ( 'start_sample', ctypes.c_uint32, ),
42             ( 'end_sample', ctypes.c_uint32, ),
43         ]
44
45     FLAG_REPETITION = 1 << 0
46     FLAG_RELEASE = 1 << 1
47
48     def _library_filename(self):
49         '''
50         Determine the library filename depending on the platform.
51         '''
52
53         if platform.uname()[0] == 'Linux':
54             return 'libirmp.so'
55         if platform.uname()[0] == 'Darwin':
56             return 'libirmp.dylib'
57         return 'irmp.dll'
58
59     def _library_setup_api(self):
60         '''
61         Lookup the C library's API routines. Declare their prototypes.
62         '''
63
64         if not self._lib:
65             return False
66
67         self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32
68         self._lib.irmp_get_sample_rate.argtypes = []
69
70         self._lib.irmp_reset_state.restype = None
71         self._lib.irmp_reset_state.argtypes = []
72
73         self._lib.irmp_add_one_sample.restype = ctypes.c_int
74         self._lib.irmp_add_one_sample.argtypes = [ ctypes.c_int, ]
75
76         if False:
77             self._lib.irmp_detect_buffer.restype = self.ResultData
78             self._lib.irmp_detect_buffer.argtypes = [ ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ]
79
80         self._lib.irmp_get_result_data.restype = ctypes.c_int
81         self._lib.irmp_get_result_data.argtypes = [ ctypes.POINTER(self.ResultData), ]
82
83         self._lib.irmp_get_protocol_name.restype = ctypes.c_char_p
84         self._lib.irmp_get_protocol_name.argtypes = [ ctypes.c_uint32, ]
85
86         # Create a result buffer that's local to the library instance.
87         self._data = self.ResultData()
88
89         return True
90
91     def __init__(self):
92         '''
93         Create a library instance.
94         '''
95
96         # Only create a working instance for the first invocation.
97         # Degrade all other instances, make them fail "late" during
98         # execution, so that users will see the errors.
99         self._lib = None
100         self._data = None
101         if IrmpLibrary.__usable_instance is None:
102             filename = self._library_filename()
103             self._lib = ctypes.cdll.LoadLibrary(filename)
104             self._library_setup_api()
105             IrmpLibrary.__usable_instance = self
106
107     def get_sample_rate(self):
108         if not self._lib:
109             return None
110         return self._lib.irmp_get_sample_rate()
111
112     def reset_state(self):
113         if not self._lib:
114             return None
115         self._lib.irmp_reset_state()
116
117     def add_one_sample(self, level):
118         if not self._lib:
119             raise Exception("IRMP library limited to a single instance.")
120         if not self._lib.irmp_add_one_sample(int(level)):
121             return False
122         self._lib.irmp_get_result_data(ctypes.byref(self._data))
123         return True
124
125     def get_result_data(self):
126         if not self._data:
127             return None
128         return {
129             'proto_nr': self._data.protocol,
130             'proto_name': self._data.protocol_name.decode('UTF-8', 'ignore'),
131             'address': self._data.address,
132             'command': self._data.command,
133             'repeat': bool(self._data.flags & self.FLAG_REPETITION),
134             'release': bool(self._data.flags & self.FLAG_RELEASE),
135             'start': self._data.start_sample,
136             'end': self._data.end_sample,
137         }