diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py b/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py
new file mode 100644
index 00000000..b6bbff60
--- /dev/null
+++ b/libsigrokdecode4DSL/decoders/ir_irmp/__init__.py
@@ -0,0 +1,25 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2019 Rene Staffen
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+'''
+IRMP is a multi protocol infrared remote protocol decoder. See
+https://www.mikrocontroller.net/articles/IRMP for details.
+'''
+
+from .pd import Decoder
diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py
new file mode 100644
index 00000000..5ec65222
--- /dev/null
+++ b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py
@@ -0,0 +1,137 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2019 Rene Staffen
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+'''
+Python binding for the IRMP library.
+'''
+
+import ctypes
+import platform
+
+class IrmpLibrary:
+ '''
+ Library instance for an infrared protocol detector.
+ '''
+
+ __usable_instance = None
+
+ class ResultData(ctypes.Structure):
+ _fields_ = [
+ ( 'protocol', ctypes.c_uint32, ),
+ ( 'protocol_name', ctypes.c_char_p, ),
+ ( 'address', ctypes.c_uint32, ),
+ ( 'command', ctypes.c_uint32, ),
+ ( 'flags', ctypes.c_uint32, ),
+ ( 'start_sample', ctypes.c_uint32, ),
+ ( 'end_sample', ctypes.c_uint32, ),
+ ]
+
+ FLAG_REPETITION = 1 << 0
+ FLAG_RELEASE = 1 << 1
+
+ def _library_filename(self):
+ '''
+ Determine the library filename depending on the platform.
+ '''
+
+ if platform.uname()[0] == 'Linux':
+ return 'libirmp.so'
+ if platform.uname()[0] == 'Darwin':
+ return 'libirmp.dylib'
+ return 'irmp.dll'
+
+ def _library_setup_api(self):
+ '''
+ Lookup the C library's API routines. Declare their prototypes.
+ '''
+
+ if not self._lib:
+ return False
+
+ self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32
+ self._lib.irmp_get_sample_rate.argtypes = []
+
+ self._lib.irmp_reset_state.restype = None
+ self._lib.irmp_reset_state.argtypes = []
+
+ self._lib.irmp_add_one_sample.restype = ctypes.c_int
+ self._lib.irmp_add_one_sample.argtypes = [ ctypes.c_int, ]
+
+ if False:
+ self._lib.irmp_detect_buffer.restype = self.ResultData
+ self._lib.irmp_detect_buffer.argtypes = [ ctypes.POINTER(ctypes.c_uint8), ctypes.c_size_t, ]
+
+ self._lib.irmp_get_result_data.restype = ctypes.c_int
+ self._lib.irmp_get_result_data.argtypes = [ ctypes.POINTER(self.ResultData), ]
+
+ self._lib.irmp_get_protocol_name.restype = ctypes.c_char_p
+ self._lib.irmp_get_protocol_name.argtypes = [ ctypes.c_uint32, ]
+
+ # Create a result buffer that's local to the library instance.
+ self._data = self.ResultData()
+
+ return True
+
+ def __init__(self):
+ '''
+ Create a library instance.
+ '''
+
+ # Only create a working instance for the first invocation.
+ # Degrade all other instances, make them fail "late" during
+ # execution, so that users will see the errors.
+ self._lib = None
+ self._data = None
+ if IrmpLibrary.__usable_instance is None:
+ filename = self._library_filename()
+ self._lib = ctypes.cdll.LoadLibrary(filename)
+ self._library_setup_api()
+ IrmpLibrary.__usable_instance = self
+
+ def get_sample_rate(self):
+ if not self._lib:
+ return None
+ return self._lib.irmp_get_sample_rate()
+
+ def reset_state(self):
+ if not self._lib:
+ return None
+ self._lib.irmp_reset_state()
+
+ def add_one_sample(self, level):
+ if not self._lib:
+ raise Exception("IRMP library limited to a single instance.")
+ if not self._lib.irmp_add_one_sample(int(level)):
+ return False
+ self._lib.irmp_get_result_data(ctypes.byref(self._data))
+ return True
+
+ def get_result_data(self):
+ if not self._data:
+ return None
+ return {
+ 'proto_nr': self._data.protocol,
+ 'proto_name': self._data.protocol_name.decode('UTF-8', 'ignore'),
+ 'address': self._data.address,
+ 'command': self._data.command,
+ 'repeat': bool(self._data.flags & self.FLAG_REPETITION),
+ 'release': bool(self._data.flags & self.FLAG_RELEASE),
+ 'start': self._data.start_sample,
+ 'end': self._data.end_sample,
+ }
diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/pd.py b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py
new file mode 100644
index 00000000..979c1e01
--- /dev/null
+++ b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py
@@ -0,0 +1,137 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2014 Gump Yang
+## Copyright (C) 2019 Rene Staffen
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see .
+##
+
+from . import irmp_library
+import sigrokdecode as srd
+
+class SamplerateError(Exception):
+ pass
+
+class LibraryError(Exception):
+ pass
+
+class Decoder(srd.Decoder):
+ api_version = 3
+ id = 'ir_irmp'
+ name = 'IR IRMP'
+ longname = 'IR IRMP'
+ desc = 'IRMP infrared remote control multi protocol.'
+ license = 'gplv2+'
+ inputs = ['logic']
+ outputs = []
+ tags = ['IR']
+ channels = (
+ {'id': 'ir', 'name': 'IR', 'desc': 'Data line'},
+ )
+ options = (
+ {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low',
+ 'values': ('active-low', 'active-high')},
+ )
+ annotations = (
+ ('packet', 'Packet'),
+ )
+ annotation_rows = (
+ ('packets', 'IR Packets', (0,)),
+ )
+
+ def putframe(self, data):
+ '''Emit annotation for an IR frame.'''
+
+ # Cache result data fields in local variables. Get the ss/es
+ # timestamps, scaled to sample numbers.
+ nr = data['proto_nr']
+ name = data['proto_name']
+ addr = data['address']
+ cmd = data['command']
+ repeat = data['repeat']
+ release = data['release']
+ ss = data['start'] * self.rate_factor
+ es = data['end'] * self.rate_factor
+
+ # Prepare display texts for several zoom levels.
+ # Implementor's note: Keep list lengths for flags aligned during
+ # maintenance. Make sure there are as many flags text variants
+ # as are referenced by annotation text variants. Differing list
+ # lengths or dynamic refs will severely complicate the logic.
+ rep_txts = ['repeat', 'rep', 'r']
+ rel_txts = ['release', 'rel', 'R']
+ flag_txts = [None,] * len(rep_txts)
+ for zoom in range(len(flag_txts)):
+ flag_txts[zoom] = []
+ if repeat:
+ flag_txts[zoom].append(rep_txts[zoom])
+ if release:
+ flag_txts[zoom].append(rel_txts[zoom])
+ flag_txts = [' '.join(t) or '-' for t in flag_txts]
+ flg = flag_txts # Short name for .format() references.
+ txts = [
+ 'Protocol: {name} ({nr}), Address 0x{addr:04x}, Command: 0x{cmd:04x}, Flags: {flg[0]}'.format(**locals()),
+ 'P: {name} ({nr}), Addr: 0x{addr:x}, Cmd: 0x{cmd:x}, Flg: {flg[1]}'.format(**locals()),
+ 'P: {nr} A: 0x{addr:x} C: 0x{cmd:x} F: {flg[1]}'.format(**locals()),
+ 'C:{cmd:x} A:{addr:x} {flg[2]}'.format(**locals()),
+ 'C:{cmd:x}'.format(**locals()),
+ ]
+
+ # Emit the annotation from details which were constructed above.
+ self.put(ss, es, self.out_ann, [0, txts])
+
+ def __init__(self):
+ self.irmp = None
+ self.reset()
+
+ def reset(self):
+ self.want_reset = True
+
+ def start(self):
+ self.out_ann = self.register(srd.OUTPUT_ANN)
+
+ def metadata(self, key, value):
+ if key == srd.SRD_CONF_SAMPLERATE:
+ self.samplerate = value
+
+ def decode(self):
+ if not self.irmp:
+ try:
+ self.irmp = irmp_library.IrmpLibrary()
+ except Exception as e:
+ txt = e.args[0]
+ raise LibraryError(txt)
+ if self.irmp:
+ self.lib_rate = self.irmp.get_sample_rate()
+ if not self.irmp or not self.lib_rate:
+ raise LibraryError('Cannot access IRMP library. One instance limit exceeded?')
+ if not self.samplerate:
+ raise SamplerateError('Cannot decode without samplerate.')
+ if self.samplerate % self.lib_rate:
+ raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(self.lib_rate))
+ self.rate_factor = int(self.samplerate / self.lib_rate)
+ if self.want_reset:
+ self.irmp.reset_state()
+ self.want_reset = False
+
+ self.active = 0 if self.options['polarity'] == 'active-low' else 1
+ ir, = self.wait()
+ while True:
+ if self.active == 1:
+ ir = 1 - ir
+ if self.irmp.add_one_sample(ir):
+ data = self.irmp.get_result_data()
+ self.putframe(data)
+ ir, = self.wait([{'skip': self.rate_factor}])