]> sigrok.org Git - libsigrokdecode.git/blame - decoders/ir_irmp/irmp_library.py
ir_irmp: wrapper lib, add locking and Python threading support
[libsigrokdecode.git] / decoders / ir_irmp / irmp_library.py
CommitLineData
31b646e2
GS
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'''
21Python binding for the IRMP library.
22'''
23
24import ctypes
25import platform
26
27class IrmpLibrary:
28 '''
29 Library instance for an infrared protocol detector.
30 '''
31
f8c62753
GS
32 __usable_instance = None
33
31b646e2
GS
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
8c3291c7 46 FLAG_RELEASE = 1 << 1
31b646e2
GS
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'
02993c7a
GS
55 if platform.uname()[0] == 'Darwin':
56 return 'libirmp.dylib'
31b646e2
GS
57 return 'irmp.dll'
58
f8c62753 59 def _library_setup_api(self):
31b646e2 60 '''
f8c62753 61 Lookup the C library's API routines. Declare their prototypes.
31b646e2
GS
62 '''
63
f8c62753
GS
64 if not self._lib:
65 return False
31b646e2
GS
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
f8c62753
GS
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
31b646e2 107 def get_sample_rate(self):
f8c62753
GS
108 if not self._lib:
109 return None
31b646e2
GS
110 return self._lib.irmp_get_sample_rate()
111
112 def reset_state(self):
f8c62753
GS
113 if not self._lib:
114 return None
31b646e2
GS
115 self._lib.irmp_reset_state()
116
117 def add_one_sample(self, level):
f8c62753
GS
118 if not self._lib:
119 raise Exception("IRMP library limited to a single instance.")
31b646e2
GS
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):
f8c62753
GS
126 if not self._data:
127 return None
128 return {
31b646e2
GS
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),
8c3291c7 134 'release': bool(self._data.flags & self.FLAG_RELEASE),
31b646e2
GS
135 'start': self._data.start_sample,
136 'end': self._data.end_sample,
137 }