diff options
-rw-r--r-- | decoders/onewire_link/__init__.py | 25 | ||||
-rw-r--r-- | decoders/onewire_link/pd.py | 440 |
2 files changed, 259 insertions, 206 deletions
diff --git a/decoders/onewire_link/__init__.py b/decoders/onewire_link/__init__.py index 28b0194..69b570f 100644 --- a/decoders/onewire_link/__init__.py +++ b/decoders/onewire_link/__init__.py @@ -2,6 +2,7 @@ ## This file is part of the libsigrokdecode project. ## ## Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de> +## Copyright (C) 2017 Kevin Redon <kingkevin@cuvoodoo.info> ## ## 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 @@ -39,29 +40,17 @@ overdrive communication speed. The following minimal values should be used: Channels: 1-Wire requires a single signal, but some master implementations might have a separate signal used to deliver power to the bus during temperature conversion -as an example. This power signal is currently not used. +as an example. - owr (1-Wire signal line) - - pwr (optional, dedicated power supply pin) Options: -1-Wire is an asynchronous protocol, so the decoder must know the samplerate. -The timing for sampling bits, presence, and reset is calculated by the decoder, -but in case the user wishes to use different values, it is possible to -configure the following timing values (number of samplerate periods): +1-Wire is an asynchronous protocol with fixed timing values, so the decoder must +know the samplerate. +Two speeds are available: normal and overdrive. The decoder detects when +switching from one to another but the user can set which to start decoding with: - - overdrive (if active the decoder will be prepared for overdrive) - - cnt_normal_bit (time for normal mode sample bit) - - cnt_normal_slot (time for normal mode data slot) - - cnt_normal_presence (time for normal mode sample presence) - - cnt_normal_reset (time for normal mode reset) - - cnt_overdrive_bit (time for overdrive mode sample bit) - - cnt_overdrive_slot (time for overdrive mode data slot) - - cnt_overdrive_presence (time for overdrive mode sample presence) - - cnt_overdrive_reset (time for overdrive mode reset) - -These options should be configured only on very rare cases and the user should -read the decoder source code to understand them correctly. + - overdrive (to decode starting with overdrive speed) ''' from .pd import Decoder diff --git a/decoders/onewire_link/pd.py b/decoders/onewire_link/pd.py index 3974c45..d33d6d0 100644 --- a/decoders/onewire_link/pd.py +++ b/decoders/onewire_link/pd.py @@ -1,7 +1,7 @@ ## ## This file is part of the libsigrokdecode project. ## -## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com> +## Copyright (C) 2017 Kevin Redon <kingkevin@cuvoodoo.info> ## ## 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,8 +22,74 @@ import sigrokdecode as srd class SamplerateError(Exception): pass +# Timing values in us for the signal at regular and overdrive speed. +timing = { + 'RSTL': { + 'min': { + False: 480.0, + True: 48.0, + }, + 'max': { + False: 960.0, + True: 80.0, + }, + }, + 'RSTH': { + 'min': { + False: 480.0, + True: 48.0, + }, + }, + 'PDH': { + 'min': { + False: 15.0, + True: 2.0, + }, + 'max': { + False: 60.0, + True: 6.0, + }, + }, + 'PDL': { + 'min': { + False: 60.0, + True: 8.0, + }, + 'max': { + False: 240.0, + True: 24.0, + }, + }, + 'SLOT': { + 'min': { + False: 60.0, + True: 6.0, + }, + 'max': { + False: 120.0, + True: 16.0, + }, + }, + 'REC': { + 'min': { + False: 1.0, + True: 1.0, + }, + }, + 'LOWR': { + 'min': { + False: 1.0, + True: 1.0, + }, + 'max': { + False: 15.0, + True: 2.0, + }, + }, +} + class Decoder(srd.Decoder): - api_version = 3 + api_version = 2 id = 'onewire_link' name = '1-Wire link layer' longname = '1-Wire serial communication bus (link layer)' @@ -34,36 +100,16 @@ class Decoder(srd.Decoder): channels = ( {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'}, ) - optional_channels = ( - {'id': 'pwr', 'name': 'PWR', 'desc': '1-Wire power supply pin'}, - ) options = ( - {'id': 'overdrive', - 'desc': 'Overdrive mode', 'default': 'no', 'values': ('yes', 'no')}, - # Time options (specified in microseconds): - {'id': 'cnt_normal_bit', - 'desc': 'Normal mode sample bit time (μs)', 'default': 15}, - {'id': 'cnt_normal_slot', - 'desc': 'Normal mode data slot time (μs)', 'default': 60}, - {'id': 'cnt_normal_presence', - 'desc': 'Normal mode sample presence time (μs)', 'default': 75}, - {'id': 'cnt_normal_reset', - 'desc': 'Normal mode reset time (μs)', 'default': 480}, - {'id': 'cnt_overdrive_bit', - 'desc': 'Overdrive mode sample bit time (μs)', 'default': 2}, - {'id': 'cnt_overdrive_slot', - 'desc': 'Overdrive mode data slot time (μs)', 'default': 7.3}, - {'id': 'cnt_overdrive_presence', - 'desc': 'Overdrive mode sample presence time (μs)', 'default': 10}, - {'id': 'cnt_overdrive_reset', - 'desc': 'Overdrive mode reset time (μs)', 'default': 48}, + {'id': 'overdrive', 'desc': 'Start in overdrive speed', + 'default': 'no', 'values': ('yes', 'no')}, ) annotations = ( ('bit', 'Bit'), ('warnings', 'Warnings'), ('reset', 'Reset'), ('presence', 'Presence'), - ('overdrive', 'Overdrive mode notifications'), + ('overdrive', 'Overdrive speed notifications'), ) annotation_rows = ( ('bits', 'Bits', (0, 2, 3)), @@ -71,43 +117,25 @@ class Decoder(srd.Decoder): ('warnings', 'Warnings', (1,)), ) - def putm(self, data): - self.put(0, 0, self.out_ann, data) - - def putpb(self, data): - self.put(self.fall, self.samplenum, self.out_python, data) - - def putb(self, data): - self.put(self.fall, self.samplenum, self.out_ann, data) - - def putx(self, data): - self.put(self.fall, self.cnt_bit[self.overdrive], self.out_ann, data) - - def putfr(self, data): - self.put(self.fall, self.rise, self.out_ann, data) - - def putprs(self, data): - self.put(self.rise, self.samplenum, self.out_python, data) - - def putrs(self, data): - self.put(self.rise, self.samplenum, self.out_ann, data) - def __init__(self): self.samplerate = None - self.state = 'WAIT FOR FALLING EDGE' + self.samplenum = 0 + self.state = 'INITIAL' self.present = 0 self.bit = 0 - self.bit_cnt = 0 + self.bit_count = -1 self.command = 0 - self.overdrive = 0 + self.overdrive = False self.fall = 0 self.rise = 0 def start(self): self.out_python = self.register(srd.OUTPUT_PYTHON) self.out_ann = self.register(srd.OUTPUT_ANN) - - self.initial_pins = [1, 1] + self.overdrive = (self.options['overdrive'] == 'yes') + self.fall = 0 + self.rise = 0 + self.bit_count = -1 def checks(self): # Check if samplerate is appropriate. @@ -126,155 +154,191 @@ class Decoder(srd.Decoder): self.putm([1, ['Sampling rate is suggested to be above ' + '1MHz for proper normal mode decoding.']]) - # Check if sample times are in the allowed range. - - time_min = float(self.cnt_normal_bit) / self.samplerate - time_max = float(self.cnt_normal_bit + 1) / self.samplerate - if (time_min < 0.000005) or (time_max > 0.000015): - self.putm([1, ['The normal mode data sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (5.0us, 15.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_normal_presence) / self.samplerate - time_max = float(self.cnt_normal_presence + 1) / self.samplerate - if (time_min < 0.0000681) or (time_max > 0.000075): - self.putm([1, ['The normal mode presence sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (68.1us, 75.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_overdrive_bit) / self.samplerate - time_max = float(self.cnt_overdrive_bit + 1) / self.samplerate - if (time_min < 0.000001) or (time_max > 0.000002): - self.putm([1, ['The overdrive mode data sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (1.0us, 2.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - time_min = float(self.cnt_overdrive_presence) / self.samplerate - time_max = float(self.cnt_overdrive_presence + 1) / self.samplerate - if (time_min < 0.0000073) or (time_max > 0.000010): - self.putm([1, ['The overdrive mode presence sample time interval ' + - '(%2.1fus-%2.1fus) should be inside (7.3us, 10.0us).' - % (time_min * 1000000, time_max * 1000000)]]) - - def metadata(self, key, value): if key != srd.SRD_CONF_SAMPLERATE: return self.samplerate = value - # The default 1-Wire time base is 30us. This is used to calculate - # sampling times. - samplerate = float(self.samplerate) - - x = float(self.options['cnt_normal_bit']) / 1000000.0 - self.cnt_normal_bit = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_slot']) / 1000000.0 - self.cnt_normal_slot = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_presence']) / 1000000.0 - self.cnt_normal_presence = int(samplerate * x) - 1 - x = float(self.options['cnt_normal_reset']) / 1000000.0 - self.cnt_normal_reset = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_bit']) / 1000000.0 - self.cnt_overdrive_bit = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_slot']) / 1000000.0 - self.cnt_overdrive_slot = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_presence']) / 1000000.0 - self.cnt_overdrive_presence = int(samplerate * x) - 1 - x = float(self.options['cnt_overdrive_reset']) / 1000000.0 - self.cnt_overdrive_reset = int(samplerate * x) - 1 - - # Organize values into lists. - self.cnt_bit = [self.cnt_normal_bit, self.cnt_overdrive_bit] - self.cnt_presence = [self.cnt_normal_presence, self.cnt_overdrive_presence] - self.cnt_reset = [self.cnt_normal_reset, self.cnt_overdrive_reset] - self.cnt_slot = [self.cnt_normal_slot, self.cnt_overdrive_slot] - - def decode(self): + def decode(self, ss, es, data): if not self.samplerate: raise SamplerateError('Cannot decode without samplerate.') - self.checks() - while True: + for (self.samplenum, (owr,)) in data: + if self.samplenum == 0: + self.checks() + # State machine. - if self.state == 'WAIT FOR FALLING EDGE': - # The start of a cycle is a falling edge on OWR. - self.wait({0: 'f'}) - # Save the sample number for the falling edge. + if self.state == 'INITIAL': # Unknown initial state. + # Wait until we reach the idle high state. + if owr == 0: + continue + self.rise = self.samplenum + self.state = 'IDLE' + elif self.state == 'IDLE': # Idle high state. + # Wait for falling edge. + if owr != 0: + continue self.fall = self.samplenum - self.state = 'WAIT FOR DATA SAMPLE' - elif self.state == 'WAIT FOR DATA SAMPLE': - # Sample data bit. - t = self.fall + self.cnt_bit[self.overdrive] - self.bit, pwr = self.wait({'skip': t - self.samplenum}) - self.state = 'WAIT FOR DATA SLOT END' - elif self.state == 'WAIT FOR DATA SLOT END': - # A data slot ends in a recovery period, otherwise, this is - # probably a reset. - t = self.fall + self.cnt_slot[self.overdrive] - owr, pwr = self.wait({'skip': t - self.samplenum}) - + # Get time since last rising edge. + time = ((self.fall - self.rise) / self.samplerate) * 1000000.0 + if self.rise > 0 and \ + time < timing['REC']['min'][self.overdrive]: + self.put(self.fall, self.rise, self.out_ann, + [1, ['Recovery time not long enough' + 'Recovery too short', + 'REC < ' + str(timing['REC']['min'][self.overdrive])]]) + # A reset pulse or slot can start on a falling edge. + self.state = 'LOW' + # TODO: Check minimum recovery time. + elif self.state == 'LOW': # Reset pulse or slot. + # Wait for rising edge. if owr == 0: - # This seems to be a reset slot, wait for its end. - self.state = 'WAIT FOR RISING EDGE' continue - - self.putb([0, ['Bit: %d' % self.bit, '%d' % self.bit]]) - self.putpb(['BIT', self.bit]) - - # Checking the first command to see if overdrive mode - # should be entered. - if self.bit_cnt <= 8: - self.command |= (self.bit << self.bit_cnt) - elif self.bit_cnt == 8 and self.command in [0x3c, 0x69]: - self.putx([4, ['Entering overdrive mode', 'Overdrive on']]) - # Increment the bit counter. - self.bit_cnt += 1 - # Wait for next slot. - self.state = 'WAIT FOR FALLING EDGE' - elif self.state == 'WAIT FOR RISING EDGE': - # The end of a cycle is a rising edge. - self.wait({0: 'r'}) - - # Check if this was a reset cycle. - t = self.samplenum - self.fall - if t > self.cnt_normal_reset: - # Save the sample number for the rising edge. - self.rise = self.samplenum - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'WAIT FOR PRESENCE DETECT' - # Exit overdrive mode. + self.rise = self.samplenum + # Detect reset or slot base on timing. + time = ((self.rise - self.fall) / self.samplerate) * 1000000.0 + if time >= timing['RSTL']['min'][False]: # Normal reset pulse. + if time > timing['RSTL']['max'][False]: + self.put(self.fall, self.rise, self.out_ann, + [1, ['Too long reset pulse might mask interrupt ' + + 'signalling by other devices', + 'Reset pulse too long', + 'RST > ' + str(timing['RSTL']['max'][False])]]) + # Regular reset pulse clears overdrive speed. if self.overdrive: - self.putx([4, ['Exiting overdrive mode', 'Overdrive off']]) - self.overdrive = 0 - # Clear command bit counter and data register. - self.bit_cnt = 0 - self.command = 0 - elif (t > self.cnt_overdrive_reset) and self.overdrive: - # Save the sample number for the rising edge. - self.rise = self.samplenum - self.putfr([2, ['Reset', 'Rst', 'R']]) - self.state = 'WAIT FOR PRESENCE DETECT' - # Otherwise this is assumed to be a data bit. + self.put(self.fall, self.rise, self.out_ann, + [4, ['Exiting overdrive mode', 'Overdrive off']]) + self.overdrive = False + self.put(self.fall, self.rise, self.out_ann, + [2, ['Reset', 'Rst', 'R']]) + self.state = 'PRESENCE DETECT HIGH' + elif self.overdrive == True and \ + time >= timing['RSTL']['min'][self.overdrive] and \ + time < timing['RSTL']['max'][self.overdrive]: + # Overdrive reset pulse. + self.put(self.fall, self.rise, self.out_ann, + [2, ['Reset', 'Rst', 'R']]) + self.state = 'PRESENCE DETECT HIGH' + elif time < timing['SLOT']['max'][self.overdrive]: + # Read/write time slot. + if time < timing['LOWR']['min'][self.overdrive]: + self.put(self.fall, self.rise, self.out_ann, + [1, ['Low signal not long enough', + 'Low too short', + 'LOW < ' + str(timing['LOWR']['min'][self.overdrive])]]) + if time < timing['LOWR']['max'][self.overdrive]: + self.bit = 1 # Short pulse is a 1 bit. + else: + self.bit = 0 # Long pulse is a 0 bit. + # Wait for end of slot. + self.state = 'SLOT' else: - self.state = 'WAIT FOR FALLING EDGE' - elif self.state == 'WAIT FOR PRESENCE DETECT': - # Sample presence status. - t = self.rise + self.cnt_presence[self.overdrive] - owr, pwr = self.wait({'skip': t - self.samplenum}) - self.present = owr - self.state = 'WAIT FOR RESET SLOT END' - elif self.state == 'WAIT FOR RESET SLOT END': - # A reset slot ends in a long recovery period. - t = self.rise + self.cnt_reset[self.overdrive] - owr, pwr = self.wait({'skip': t - self.samplenum}) - + # Timing outside of known states. + self.put(self.fall, self.rise, self.out_ann, + [1, ['Erroneous signal', 'Error', 'Err', 'E']]) + self.state = 'IDLE' + elif self.state == 'PRESENCE DETECT HIGH': # Wait for slave presence signal. + # Calculate time since rising edge. + time = ((self.samplenum - self.rise) / self.samplerate) * 1000000.0 + if owr != 0 and time < timing['PDH']['max'][self.overdrive]: + continue + elif owr == 0: # Presence detected. + if time < timing['PDH']['min'][self.overdrive]: + self.put(self.rise, self.samplenum, self.out_ann, + [1, ['Presence detect signal is too early', + 'Presence detect too early', + 'PDH < ' + str(timing['PDH']['min'][self.overdrive])]]) + self.fall = self.samplenum + self.state = 'PRESENCE DETECT LOW' + else: # No presence detected. + self.put(self.rise, self.samplenum, self.out_ann, + [3, ['Presence: false', 'Presence', 'Pres', 'P']]) + self.put(self.rise, self.samplenum, self.out_python, + ['RESET/PRESENCE', False]) + self.state = 'IDLE' + elif self.state == 'PRESENCE DETECT LOW': # Slave presence signalled. + # Wait for end of presence signal (on rising edge). if owr == 0: - # This seems to be a reset slot, wait for its end. - self.state = 'WAIT FOR RISING EDGE' continue - - p = 'false' if self.present else 'true' - self.putrs([3, ['Presence: %s' % p, 'Presence', 'Pres', 'P']]) - self.putprs(['RESET/PRESENCE', not self.present]) - - # Wait for next slot. - self.state = 'WAIT FOR FALLING EDGE' + # Calculate time since start of presence signal. + time = ((self.samplenum - self.fall) / self.samplerate) * 1000000.0 + if time < timing['PDL']['min'][self.overdrive]: + self.put(self.fall, self.samplenum, self.out_ann, + [1, ['Presence detect signal is too short', + 'Presence detect too short', + 'PDL < ' + str(timing['PDL']['min'][self.overdrive])]]) + elif time > timing['PDL']['max'][self.overdrive]: + self.put(self.fall, self.samplenum, self.out_ann, + [1, ['Presence detect signal is too long', + 'Presence detect too long', + 'PDL > ' + str(timing['PDL']['max'][self.overdrive])]]) + if time > timing['RSTH']['min'][self.overdrive]: + self.rise = self.samplenum + # Wait for end of presence detect. + self.state = 'PRESENCE DETECT' + + # End states (for additional checks). + if self.state == 'SLOT': # Wait for end of time slot. + # Calculate time since falling edge. + time = ((self.samplenum - self.fall) / self.samplerate) * 1000000.0 + if owr != 0 and time < timing['SLOT']['min'][self.overdrive]: + continue + elif owr == 0: # Low detected before end of slot. + # Warn about irregularity. + self.put(self.fall, self.samplenum, self.out_ann, + [1, ['Time slot not long enough', + 'Slot too short', + 'SLOT < ' + str(timing['SLOT']['min'][self.overdrive])]]) + # Don't output invalid bit. + self.fall = self.samplenum + self.state = 'LOW' + else: # End of time slot. + # Output bit. + self.put(self.fall, self.samplenum, self.out_ann, + [0, ['Bit: %d' % self.bit, '%d' % self.bit]]) + self.put(self.fall, self.samplenum, self.out_python, + ['BIT', self.bit]) + # Save command bits. + if self.bit_count >= 0: + self.command += (self.bit << self.bit_count) + self.bit_count += 1 + # Check for overdrive ROM command. + if self.bit_count >= 8: + if self.command == 0x3c or self.command == 0x69: + self.overdrive = True + self.put(self.samplenum, self.samplenum, + self.out_ann, + [4, ['Entering overdrive mode', 'Overdrive on']]) + self.bit_count = -1 + self.state = 'IDLE' + + if self.state == 'PRESENCE DETECT': + # Wait for end of presence detect. + # Calculate time since falling edge. + time = ((self.samplenum - self.rise) / self.samplerate) * 1000000.0 + if owr != 0 and time < timing['RSTH']['min'][self.overdrive]: + continue + elif owr == 0: # Low detected before end of presence detect. + # Warn about irregularity. + self.put(self.fall, self.samplenum, self.out_ann, + [1, ['Presence detect not long enough', + 'Presence detect too short', + 'RTSH < ' + str(timing['RSTH']['min'][self.overdrive])]]) + # Inform about presence detected. + self.put(self.rise, self.samplenum, self.out_ann, + [3, ['Slave presence detected', 'Slave present', + 'Present', 'P']]) + self.put(self.rise, self.samplenum, self.out_python, + ['RESET/PRESENCE', True]) + self.fall = self.samplenum + self.state = 'LOW' + else: # End of time slot. + # Inform about presence detected. + self.put(self.rise, self.samplenum, self.out_ann, + [3, ['Presence: true', 'Presence', 'Pres', 'P']]) + self.put(self.rise, self.samplenum, self.out_python, + ['RESET/PRESENCE', True]) + self.rise = self.samplenum + # Start counting the first 8 bits to get the ROM command. + self.bit_count = 0 + self.command = 0 + self.state = 'IDLE' |