]> sigrok.org Git - libsigrokdecode.git/blob - decoders/ir_irmp/irmp_library.py
ir_irmp: Python binding, support instance locking and context manager
[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 ## Copyright (C) 2020-2021 Gerhard Sittig <gerhard.sittig@gmx.net>
6 ##
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
21 '''
22 Python binding for the IRMP library.
23 '''
24
25 import ctypes
26 import platform
27
28 class IrmpLibrary:
29     '''
30     Library instance for an infrared protocol detector.
31     '''
32
33     __usable_instance = None
34
35     class ResultData(ctypes.Structure):
36         _fields_ = [
37             ( 'protocol', ctypes.c_uint32, ),
38             ( 'protocol_name', ctypes.c_char_p, ),
39             ( 'address', ctypes.c_uint32, ),
40             ( 'command', ctypes.c_uint32, ),
41             ( 'flags', ctypes.c_uint32, ),
42             ( 'start_sample', ctypes.c_uint32, ),
43             ( 'end_sample', ctypes.c_uint32, ),
44         ]
45
46     FLAG_REPETITION = 1 << 0
47     FLAG_RELEASE = 1 << 1
48
49     def _library_filename(self):
50         '''
51         Determine the library filename depending on the platform.
52         '''
53
54         if platform.uname()[0] == 'Linux':
55             return 'libirmp.so'
56         if platform.uname()[0] == 'Darwin':
57             return 'libirmp.dylib'
58         return 'irmp.dll'
59
60     def _library_setup_api(self):
61         '''
62         Lookup the C library's API routines. Declare their prototypes.
63         '''
64
65         self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32
66         self._lib.irmp_get_sample_rate.argtypes = []
67
68         self._lib.irmp_instance_alloc.restype = ctypes.c_void_p
69         self._lib.irmp_instance_alloc.argtypes = []
70
71         self._lib.irmp_instance_free.restype = None
72         self._lib.irmp_instance_free.argtypes = [ ctypes.c_void_p, ]
73
74         self._lib.irmp_instance_id.restype = ctypes.c_size_t
75         self._lib.irmp_instance_id.argtypes = [ ctypes.c_void_p, ]
76
77         self._lib.irmp_instance_lock.restype = ctypes.c_int
78         self._lib.irmp_instance_lock.argtypes = [ ctypes.c_void_p, ctypes.c_int, ]
79
80         self._lib.irmp_instance_unlock.restype = None
81         self._lib.irmp_instance_unlock.argtypes = [ ctypes.c_void_p, ]
82
83         self._lib.irmp_reset_state.restype = None
84         self._lib.irmp_reset_state.argtypes = []
85
86         self._lib.irmp_add_one_sample.restype = ctypes.c_int
87         self._lib.irmp_add_one_sample.argtypes = [ ctypes.c_int, ]
88
89         if False:
90             self._lib.irmp_detect_buffer.restype = self.ResultData
91             self._lib.irmp_detect_buffer.argtypes = [ ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ]
92
93         self._lib.irmp_get_result_data.restype = ctypes.c_int
94         self._lib.irmp_get_result_data.argtypes = [ ctypes.POINTER(self.ResultData), ]
95
96         self._lib.irmp_get_protocol_name.restype = ctypes.c_char_p
97         self._lib.irmp_get_protocol_name.argtypes = [ ctypes.c_uint32, ]
98
99         # Create a result buffer that's local to the library instance.
100         self._data = self.ResultData()
101         self._inst = None
102
103         return True
104
105     def __init__(self):
106         '''
107         Create a library instance.
108         '''
109
110         filename = self._library_filename()
111         self._lib = ctypes.cdll.LoadLibrary(filename)
112         self._library_setup_api()
113
114     def __del__(self):
115         '''
116         Release a disposed library instance.
117         '''
118
119         if self._inst:
120             self._lib.irmp_instance_free(self._inst)
121         self._inst = None
122
123     def __enter__(self):
124         '''
125         Enter a context (lock management).
126         '''
127
128         if self._inst is None:
129             self._inst = self._lib.irmp_instance_alloc()
130         self._lib.irmp_instance_lock(self._inst, 1)
131         return self
132
133     def __exit__(self, extype, exvalue, trace):
134         '''
135         Leave a context (lock management).
136         '''
137
138         self._lib.irmp_instance_unlock(self._inst)
139         return False
140
141     def client_id(self):
142         return self._lib.irmp_instance_id(self._inst)
143
144     def get_sample_rate(self):
145         return self._lib.irmp_get_sample_rate()
146
147     def reset_state(self):
148         self._lib.irmp_reset_state()
149
150     def add_one_sample(self, level):
151         if not self._lib.irmp_add_one_sample(int(level)):
152             return False
153         self._lib.irmp_get_result_data(ctypes.byref(self._data))
154         return True
155
156     def get_result_data(self):
157         if not self._data:
158             return None
159         return {
160             'proto_nr': self._data.protocol,
161             'proto_name': self._data.protocol_name.decode('UTF-8', 'ignore'),
162             'address': self._data.address,
163             'command': self._data.command,
164             'repeat': bool(self._data.flags & self.FLAG_REPETITION),
165             'release': bool(self._data.flags & self.FLAG_RELEASE),
166             'start': self._data.start_sample,
167             'end': self._data.end_sample,
168         }