Hi Uwe,

sorry for my long time silence.

I've merged meter decoder into fresh timing decoder. So, here it is.

2016-04-13 10:47 GMT+03:00 Uwe Hermann <u...@hermann-uwe.de>:
> Hi,
>
> On Fri, Mar 18, 2016 at 03:57:46PM +0200, Andriy Trotsenko wrote:
>> I would like to submit my small decoder 'meter'. It was helpful for me in
>> some protocols decoding, and seems to be some more functional than 'timing'
>> decoder.
>>
>> Here is patch generated from latest git clone of libsigrokdecode repository
>> and screenshot showing decoder options.
>
> Looks great, this seems useful indeed, thanks!
>
> While some of the functionality could also (and probably will) be
> implemented in frontends directly (e.g. in PulseView) such a decoder is
> still useful for other reasons and purposes, e.g. when used with
> sigrok-cli or for scripting / automation etc.
>
> However, it does indeed seem that the functionality should be integrated
> into the 'timing' decoder, which already has a very similar purpose.
> It's getting confusing for users if we merge too many PDs with different
> names but similar purpose.
>
> Could you please add your copyright line to the timing decoder and merge
> your functionality into that decoder please? That would be great!
>
>
> Cheers, Uwe.
> --
> http://hermann-uwe.de | http://randomprojects.org | http://sigrok.org
commit 70b174c065b821990d9617f669125c88c08c19fd
Author: Andriy Trotsenko <andriy.trotse...@gmail.com>
Date:   Sun Aug 28 15:40:31 2016 +0300

    Timing decoder rework. Merging timing and new meter decoders

diff --git a/decoders/timing/__init__.py b/decoders/timing/__init__.py
index ee31509..1f08a74 100644
--- a/decoders/timing/__init__.py
+++ b/decoders/timing/__init__.py
@@ -2,6 +2,8 @@
 ## This file is part of the libsigrokdecode project.
 ##
 ## Copyright (C) 2014 Torsten Duwe <d...@suse.de>
+## Copyright (C) 2014 Sebastien Bourdelin <sebastien.bourde...@savoirfairelinux.com>
+## Copyright (C) 2015 Andriy Trotsenko <andriy.trotse...@gmail.com>
 ##
 ## 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
diff --git a/decoders/timing/pd.py b/decoders/timing/pd.py
index 98677b9..fae3909 100644
--- a/decoders/timing/pd.py
+++ b/decoders/timing/pd.py
@@ -3,6 +3,7 @@
 ##
 ## Copyright (C) 2014 Torsten Duwe <d...@suse.de>
 ## Copyright (C) 2014 Sebastien Bourdelin <sebastien.bourde...@savoirfairelinux.com>
+## Copyright (C) 2015 Andriy Trotsenko <andriy.trotse...@gmail.com>
 ##
 ## 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
@@ -22,42 +23,62 @@
 import sigrokdecode as srd
 from collections import deque
 
-class SamplerateError(Exception):
+class SampleRateError(Exception):
     pass
 
-def normalize_time(t):
-    if t >= 1.0:
-        return '%.3f s  (%.3f Hz)' % (t, (1/t))
-    elif t >= 0.001:
-        if 1/t/1000 < 1:
-            return '%.3f ms (%.3f Hz)' % (t * 1000.0, (1/t))
-        else:
-            return '%.3f ms (%.3f kHz)' % (t * 1000.0, (1/t)/1000)
-    elif t >= 0.000001:
-        if 1/t/1000/1000 < 1:
-            return '%.3f μs (%.3f kHz)' % (t * 1000.0 * 1000.0, (1/t)/1000)
-        else:
-            return '%.3f μs (%.3f MHz)' % (t * 1000.0 * 1000.0, (1/t)/1000/1000)
-    elif t >= 0.000000001:
-        if 1/t/1000/1000/1000:
-            return '%.3f ns (%.3f MHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000)
-        else:
-            return '%.3f ns (%.3f GHz)' % (t * 1000.0 * 1000.0 * 1000.0, (1/t)/1000/1000/1000)
+def format_number(n, units):
+
+    extra_digits = 0                    # Const. Precision. Number of extra digits at the end of number
+
+    for u in units:
+        if n < 10**(extra_digits + 4):  # Prefer 1234 over 1.23
+            break
+        n /= 1000
+
+    if n < 1:
+        digits = 3                      # .123
+    elif n < 10:
+        digits = 2                      # 1.23
+    elif n < 100:
+        digits = 1                      # 12.3
     else:
-        return '%f' % t
+        digits = 0                      # 123
+                                        # 1234
+    n = "%.*f" % (digits + extra_digits, n)
+
+    if digits + extra_digits > 0:       # Strip meaningless 0s after decimal point and decimal point itself if alone
+        n = n.rstrip("0").rstrip(".")
+
+    return n + u                        # Add measurement units
 
 class Decoder(srd.Decoder):
+
     api_version = 2
     id = 'timing'
     name = 'Timing'
     longname = 'Timing calculation with frequency and averaging'
     desc = 'Calculate time between edges.'
     license = 'gplv2+'
+
+    CONST_0 = '- 0 -'
+    CONST_1 = '- 1 -'
+    CONST_01 = '0 & 1'
+    CONST_0_1 = '0 - 1'
+    CONST_1_0 = '1 - 0'
+
     inputs = ['logic']
     outputs = ['timing']
     channels = (
         {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
     )
+    #optional_channels = ()
+    options = (
+        {'id': 'metering', 'desc': 'Metering', 'default': CONST_0_1,
+            'values': (CONST_0, CONST_1, CONST_01, CONST_0_1, CONST_1_0)},
+        {'id': 'units', 'desc': 'Units', 'default': 'samples',
+            'values': ('samples', 'seconds', 'hertz')},
+        {'id': 'avg_period', 'desc': 'Averaging period', 'default': 100 },
+    )
     annotations = (
         ('time', 'Time'),
         ('average', 'Average'),
@@ -66,58 +87,73 @@ class Decoder(srd.Decoder):
         ('time', 'Time', (0,)),
         ('average', 'Average', (1,)),
     )
-    options = (
-        { 'id': 'avg_period', 'desc': 'Averaging period', 'default': 100 },
-    )
 
-    def __init__(self):
+
+    def __init__(self, **kwargs):
+
         self.samplerate = None
-        self.oldpin = None
-        self.last_samplenum = None
-        self.last_n = deque()
-        self.chunks = 0
 
     def metadata(self, key, value):
+
         if key == srd.SRD_CONF_SAMPLERATE:
             self.samplerate = value
 
     def start(self):
+
         self.out_ann = self.register(srd.OUTPUT_ANN)
 
+    def normalize_number(self, n):
+
+        if self.options['units'] == 'seconds':
+            return format_number(n * 1000000 / self.samplerate, ("µ", "m", ""))
+
+        elif self.options['units'] == 'hertz':
+            return format_number(self.samplerate / n, ("", "K", "M", "G"))
+
+        else: # Samples
+            return "%d" % n
+
     def decode(self, ss, es, data):
-        if not self.samplerate:
-            raise SamplerateError('Cannot decode without samplerate.')
 
-        for (self.samplenum, (pin,)) in data:
-            if self.oldpin is None:
-                self.oldpin = pin
-                self.last_samplenum = self.samplenum
+        if not self.samplerate or self.samplerate < 1:
+            raise SampleRateError('Cannot decode without samplerate.')
+
+        lb = rb = ""
+        if self.options['units'] == 'hertz' and self.options['metering'] not in (self.CONST_0_1, self.CONST_1_0):
+            #self.options['metering'] = self.CONST_0_1
+            lb = "("
+            rb = ")"
+
+        prev_pin = prev_samplenum = avg_prev_samplenum = None
+        prev_n = deque()
+
+        for (samplenum, (pin, )) in data:
+
+            # Ignore identical samples early on (for performance reasons)
+            if prev_pin == pin:
+                continue
+
+            # Initialize previous values on the very first loop execution
+            if prev_pin is None:
+                prev_pin = pin
+                #if (self.options['metering'] in (self.CONST_0_1, self.CONST_1_0)):
+                prev_samplenum = samplenum
+                #self.prev_samplenum = self.avg_prev_samplenum = self.samplenum
                 continue
 
-            if self.oldpin != pin:
-                samples = self.samplenum - self.last_samplenum
-                t = samples / self.samplerate
-                self.chunks += 1
-
-                # Don't insert the first chunk into the averaging as it is
-                # not complete probably.
-                if self.last_samplenum is None or self.chunks < 2:
-                    # Report the timing normalized.
-                    self.put(self.last_samplenum, self.samplenum, self.out_ann,
-                             [0, [normalize_time(t)]])
-                else:
-                    if t > 0:
-                        self.last_n.append(t)
-
-                    if len(self.last_n) > self.options['avg_period']:
-                        self.last_n.popleft()
-
-                    # Report the timing normalized.
-                    self.put(self.last_samplenum, self.samplenum, self.out_ann,
-                             [0, [normalize_time(t)]])
-                    self.put(self.last_samplenum, self.samplenum, self.out_ann,
-                             [1, [normalize_time(sum(self.last_n) / len(self.last_n))]])
-
-                # Store data for next round.
-                self.last_samplenum = self.samplenum
-                self.oldpin = pin
+            # Averaging logic
+            if avg_prev_samplenum is not None: # Comment out this line and shift left following indented lines to count from the very begining, not from the first front change
+                prev_n.append(samplenum - avg_prev_samplenum)
+                if len(prev_n) > self.options['avg_period']:
+                    prev_n.popleft()
+                self.put(avg_prev_samplenum, samplenum, self.out_ann, [1, [self.normalize_number(sum(prev_n) / len(prev_n))]])
+            avg_prev_samplenum = samplenum
+
+            # Metering logic
+            if (prev_samplenum is not None) and ((pin == 0 and self.options['metering'] in (self.CONST_0_1, self.CONST_1, self.CONST_01)) or (pin == 1 and self.options['metering'] in (self.CONST_1_0, self.CONST_0, self.CONST_01))):
+                self.put(prev_samplenum, samplenum, self.out_ann, [0, [lb + self.normalize_number(samplenum - prev_samplenum) + rb]])
+
+            if (self.options['metering'] != self.CONST_0_1 or pin == 0) and (self.options['metering'] != self.CONST_1_0 or pin == 1):
+                prev_samplenum = samplenum
+
+            prev_pin = pin
------------------------------------------------------------------------------
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to