X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=decoders%2Fir_irmp%2Fpd.py;h=979c1e0129b63e7b43f94f6f8458f16a961d11cb;hb=8838d01886f056b20da458fe55ad977997739b0c;hp=343c068cb5b870df7532cea133a4a8e0f75d68bc;hpb=4032deddd46665c16254abfd7729753930f0c32e;p=libsigrokdecode.git diff --git a/decoders/ir_irmp/pd.py b/decoders/ir_irmp/pd.py index 343c068..979c1e0 100644 --- a/decoders/ir_irmp/pd.py +++ b/decoders/ir_irmp/pd.py @@ -1,4 +1,9 @@ ## +## 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 @@ -13,21 +18,21 @@ ## along with this program; if not, see . ## +from . import irmp_library import sigrokdecode as srd -#from .lists import * - -from .IrmpPythonWrap import IrmpWrap - class SamplerateError(Exception): pass +class LibraryError(Exception): + pass + class Decoder(srd.Decoder): api_version = 3 id = 'ir_irmp' name = 'IR IRMP' - longname = 'IR IRMP multi protocol decoder' - desc = 'IRMP - multi protocol infrared decoder with support for many IR protocols by Frank M. (ukw)' + longname = 'IR IRMP' + desc = 'IRMP infrared remote control multi protocol.' license = 'gplv2+' inputs = ['logic'] outputs = [] @@ -38,44 +43,61 @@ class Decoder(srd.Decoder): options = ( {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', 'values': ('active-low', 'active-high')}, -# -# {'id': 'cd_freq', 'desc': 'Carrier Frequency', 'default': 0}, ) annotations = ( ('packet', 'Packet'), - ('debug', 'Debug'), ) annotation_rows = ( ('packets', 'IR Packets', (0,)), - ('debug', 'Debug', (1,)), ) - irmp = IrmpWrap() - def putIr(self, data): - ss = data['start'] * self.subSample - es = data['end'] * self.subSample - ad = data['data']['address'] - pr = data['data']['protocol'] - pn = data['data']['protocolName'] - cm = data['data']['command'] - repeat = data['data']['repeat'] - - - # print(f" {self.samplenum} {ss} - {es} ({data['start']} - {data['end']})") - self.put(ss, es, self.out_ann, - [0, [ f"Protocol: {pn} ({pr}), Address 0x{ad:04x}, Command: 0x{cm:04x} {'repeated' if repeat else ''}", - f"P: {pn} ({pr}), Ad: 0x{ad:x}, Cmd: 0x{cm:x} {'rep' if repeat else ''}", - f"P: {pr} A: 0x{ad:x} C: 0x{cm:x} {'rep' if repeat else ''}", - f"C:{cm:x} A:{ad:x} {'r' if repeat else ''}", - f"C:{cm:x}", - ]]) + 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 = Decoder.irmp + self.irmp = None self.reset() def reset(self): - self.irmp.Reset() + self.want_reset = True def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) @@ -84,66 +106,32 @@ class Decoder(srd.Decoder): 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 - - if (self.samplerate % self.irmp.GetSampleRate()) != 0: - raise SamplerateError(f'samplerate has to be multple of {self.irmp.GetSampleRate()}' ) - - self.subSample = int(self.samplerate / self.irmp.GetSampleRate()) - sampleSkip = self.subSample - #self.reset() - #print (f" startdecode: samplenum {self.samplenum} rate: {self.samplerate} subsample {self.subSample}") - # cd_count = None - # if self.options['cd_freq']: - # cd_count = int(self.samplerate / self.options['cd_freq']) + 1 - self.active = 0 if self.options['polarity'] == 'active-low' else 1 - - (ir,) = self.wait([{'skip' : sampleSkip}]) - i = 0 - + ir, = self.wait() while True: - ##### todo: check if ir carrier frequency detection can be used - # - # Detect changes in the presence of an active input signal. - # The decoder can either be fed an already filtered RX signal - # or optionally can detect the presence of a carrier. Periods - # of inactivity (signal changes slower than the carrier freq, - # if specified) pass on the most recently sampled level. This - # approach works for filtered and unfiltered input alike, and - # only slightly extends the active phase of input signals with - # carriers included by one period of the carrier frequency. - # IR based communication protocols can cope with this slight - # inaccuracy just fine by design. Enabling carrier detection - # on already filtered signals will keep the length of their - # active period, but will shift their signal changes by one - # carrier period before they get passed to decoding logic. - # if cd_count: - # (cur_ir,) = self.wait([{0: 'e'}, {'skip': cd_count}]) - # if self.matched[0]: - # cur_ir = self.active - # if cur_ir == prev_ir: - # continue - # prev_ir = cur_ir - # self.ir = cur_ir - # else: - # (self.ir,) = self.wait({0: 'e'}) - # - #print (f"samplenum {self.samplenum}") - #if i%100 == 0: - # self.put(self.samplenum, self.samplenum+10, self.out_ann, - # [1, [ f"{self.samplenum} - {i}",]]) - if self.active == 1: ir = 1 - ir - - if self.irmp.AddSample(ir): - data = self.irmp.GetData() - self.putIr(data) - i = i + 1 - (ir,) = self.wait([{'skip' : sampleSkip}]) - + if self.irmp.add_one_sample(ir): + data = self.irmp.get_result_data() + self.putframe(data) + ir, = self.wait([{'skip': self.rate_factor}])