From 505f671151d2e2b0848306f46a37ac934c6da24c Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Wed, 10 Oct 2018 17:55:49 -0600 Subject: [PATCH 1/6] Add an indexable waveform sequence property (Issue #9). --- adafruit_drv2605.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/adafruit_drv2605.py b/adafruit_drv2605.py index 725fc61..732affc 100644 --- a/adafruit_drv2605.py +++ b/adafruit_drv2605.py @@ -122,6 +122,7 @@ def __init__(self, i2c, address=_DRV2605_ADDR): # Default to internal trigger mode and TS2200 A library. self.mode = MODE_INTTRIG self.library = LIBRARY_TS2200A + self._sequence = _DRV2605_Sequence(self) def _read_u8(self, address): # Read an 8-bit unsigned value from the specified 8-bit address. @@ -196,6 +197,17 @@ def library(self, val): raise ValueError('Library must be a value within 0-6!') self._write_u8(_DRV2605_REG_LIBRARY, val) + @property + def sequence(self): + """List-like sequence of waveform effects. + Get or set an effect waveform for slot 0-6 by indexing the sequence + property with the slot number. See the datasheet for a complete table + of effect ID values and the associated waveform / effect. + + E.g. 'slot_0_effect = drv.sequence[0]', 'drv.sequence[0] = 23' + """ + return self._sequence + def set_waveform(self, effect_id, slot=0): """Select an effect waveform for the specified slot (default is slot 0, but up to 7 effects can be combined with slot values 0 to 6). See the @@ -219,3 +231,35 @@ def use_LRM(self): """Use a linear resonance actuator motor.""" feedback = self._read_u8(_DRV2605_REG_FEEDBACK) self._write_u8(_DRV2605_REG_FEEDBACK, feedback | 0x80) + + + +class _DRV2605_Sequence: + """Class to enable List-like indexing of the waveform sequence slots.""" + def __init__(self, DRV2605_instance): + self._drv2605 = DRV2605_instance + + def __setitem__(self, slot, effect_id): + """Write an effect ID to a slot.""" + if not 0 <= slot <= 6: + raise IndexError('Slot must be a value within 0-6!') + if not 0 <= effect_id <= 123: + raise ValueError('Effect ID must be a value within 0-123!') + # pylint: disable=protected-access + self._drv2605._write_u8(_DRV2605_REG_WAVESEQ1 + slot, effect_id) + + def __getitem__(self, slot): + """Read an effect ID from a slot.""" + if not 0 <= slot <= 6: + raise IndexError('Slot must be a value within 0-6!') + # pylint: disable=protected-access + return self._drv2605._read_u8(_DRV2605_REG_WAVESEQ1 + slot) + + def __iter__(self): + """Return an iterator over the waveform sequence slots.""" + for slot in range(0, 7): + yield self[slot] + + def __repr__(self): + """Return a string representation of all slot's effect IDs.""" + return repr([eid for eid in self]) From f2d2fdd4b18ef797741303a6b4252aad39705ac6 Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Wed, 10 Oct 2018 17:57:32 -0600 Subject: [PATCH 2/6] Update the example to use the sequence property (Issue #9). --- examples/drv2605_simpletest.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/drv2605_simpletest.py b/examples/drv2605_simpletest.py index 0968cbe..8848c1d 100644 --- a/examples/drv2605_simpletest.py +++ b/examples/drv2605_simpletest.py @@ -19,11 +19,10 @@ effect = 1 while True: print('Playing effect #{0}'.format(effect)) - drv.set_waveform(effect) # Select the effect on slot 0. - # Optionally you can assign effects to up to 7 different slots to combine - # them in interesting ways. Use the slot keyword and specify a slot 0 to 6 - # (0 is the default). - #drv.set_waveform(effect, slot=1) + drv.sequence[0] = effect # Set the effect on slot 0. + # You can assign effects to up to 7 different slots to combine + # them in interesting ways. Index the sequence property with a + # slot number 0 to 6. drv.play() # Play the effect. time.sleep(0.5) # Increment effect ID and wrap back around to 1. From 87e03c561ff5fc55558d7f8725e6959c1bf0c982 Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Mon, 22 Oct 2018 20:09:09 -0600 Subject: [PATCH 3/6] Modify sequence property to only accept Pause or Effect (Issue #9). --- adafruit_drv2605.py | 89 +++++++++++++++++++++++++++++----- examples/drv2605_simpletest.py | 14 +++--- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/adafruit_drv2605.py b/adafruit_drv2605.py index 732affc..8f10e5c 100644 --- a/adafruit_drv2605.py +++ b/adafruit_drv2605.py @@ -201,10 +201,11 @@ def library(self, val): def sequence(self): """List-like sequence of waveform effects. Get or set an effect waveform for slot 0-6 by indexing the sequence - property with the slot number. See the datasheet for a complete table - of effect ID values and the associated waveform / effect. + property with the slot number. A slot must be set to either an Effect() + or Pause() class. See the datasheet for a complete table of effect ID + values and the associated waveform / effect. - E.g. 'slot_0_effect = drv.sequence[0]', 'drv.sequence[0] = 23' + E.g. 'slot_0_effect = drv.sequence[0]', 'drv.sequence[0] = Effect(88)' """ return self._sequence @@ -234,26 +235,90 @@ def use_LRM(self): +class Effect: + """Class for adding an effect to the DRV2605 waveform sequence.""" + def __init__(self, effect_id): + self._effect_id = 0 + self.id = effect_id + + @property + def raw_value(self): + """Return the raw effect ID.""" + return self._effect_id + + @property + def id(self): + """Return the effect ID.""" + return self._effect_id + + @id.setter + def id(self, effect_id): + """Set the effect ID.""" + if not 0 <= effect_id <= 123: + raise ValueError('Effect ID must be a value within 0-123!') + self._effect_id = effect_id + + def __repr__(self): + """Return a string representation of the Effect class.""" + return "{}({})".format(type(self).__qualname__, self.id) + + + +class Pause: + """Class for adding a pause to the DRV2605 waveform sequence. + Duration is specified in tens of milliseconds, as per page 35 + of the datasheet. I.e. Pause time = 10ms * duration + """ + def __init__(self, duration): + self._duration = 0x80 + self.duration = duration + + @property + def raw_value(self): + """Return the raw pause duration.""" + return self._duration + + @property + def duration(self): + """Return the pause duration.""" + return self._duration & 0x7f + + @duration.setter + def duration(self, duration): + """Set the pause duration.""" + if not 0 <= duration <= 127: + raise ValueError('Pause duration must be a value within 0-127!') + self._duration = 0x80 | duration + + def __repr__(self): + """Return a string representation of the Pause class.""" + return "{}({})".format(type(self).__qualname__, self.duration) + + + class _DRV2605_Sequence: """Class to enable List-like indexing of the waveform sequence slots.""" def __init__(self, DRV2605_instance): self._drv2605 = DRV2605_instance - def __setitem__(self, slot, effect_id): - """Write an effect ID to a slot.""" + def __setitem__(self, slot, effect): + """Write an Effect or Pause to a slot.""" if not 0 <= slot <= 6: raise IndexError('Slot must be a value within 0-6!') - if not 0 <= effect_id <= 123: - raise ValueError('Effect ID must be a value within 0-123!') + if not isinstance(effect, (Effect, Pause)): + raise TypeError('Effect must be either an Effect() or Pause()!') # pylint: disable=protected-access - self._drv2605._write_u8(_DRV2605_REG_WAVESEQ1 + slot, effect_id) + self._drv2605._write_u8(_DRV2605_REG_WAVESEQ1 + slot, effect.raw_value) def __getitem__(self, slot): - """Read an effect ID from a slot.""" + """Read an effect ID from a slot. Returns either a Pause or Effect class.""" if not 0 <= slot <= 6: raise IndexError('Slot must be a value within 0-6!') # pylint: disable=protected-access - return self._drv2605._read_u8(_DRV2605_REG_WAVESEQ1 + slot) + slot_contents = self._drv2605._read_u8(_DRV2605_REG_WAVESEQ1 + slot) + if slot_contents & 0x80: + return Pause(slot_contents & 0x7f) + return Effect(slot_contents) def __iter__(self): """Return an iterator over the waveform sequence slots.""" @@ -261,5 +326,5 @@ def __iter__(self): yield self[slot] def __repr__(self): - """Return a string representation of all slot's effect IDs.""" - return repr([eid for eid in self]) + """Return a string representation of all slot's effects.""" + return repr([effect for effect in self]) diff --git a/examples/drv2605_simpletest.py b/examples/drv2605_simpletest.py index 8848c1d..d0100f4 100644 --- a/examples/drv2605_simpletest.py +++ b/examples/drv2605_simpletest.py @@ -16,16 +16,18 @@ # Main loop runs forever trying each effect (1-117). # See table 11.2 in the datasheet for a list of all the effect names and IDs. # http://www.ti.com/lit/ds/symlink/drv2605.pdf -effect = 1 +effect_id = 1 while True: - print('Playing effect #{0}'.format(effect)) - drv.sequence[0] = effect # Set the effect on slot 0. + print('Playing effect #{0}'.format(effect_id)) + drv.sequence[0] = adafruit_drv2605.Effect(effect_id) # Set the effect on slot 0. # You can assign effects to up to 7 different slots to combine # them in interesting ways. Index the sequence property with a # slot number 0 to 6. + # Optionally, you can assign a pause to a slot. E.g. + # drv.sequence[1] = adafruit_drv2605.Pause(5) # Pause for 50 milliseconds drv.play() # Play the effect. time.sleep(0.5) # Increment effect ID and wrap back around to 1. - effect += 1 - if effect > 117: - effect = 1 + effect_id += 1 + if effect_id > 117: + effect_id = 1 From 5d929cbb9d57c965b83b14ea550925a7a2c39e41 Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Tue, 30 Oct 2018 20:50:11 -0600 Subject: [PATCH 4/6] Disable Pylint invalid-name for the Effect.id property (Issue #9) https://github.com/adafruit/Adafruit_CircuitPython_DRV2605/issues/9#issuecomment-432316608 --- adafruit_drv2605.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adafruit_drv2605.py b/adafruit_drv2605.py index 8f10e5c..c953fcb 100644 --- a/adafruit_drv2605.py +++ b/adafruit_drv2605.py @@ -239,6 +239,7 @@ class Effect: """Class for adding an effect to the DRV2605 waveform sequence.""" def __init__(self, effect_id): self._effect_id = 0 + # pylint: disable=invalid-name self.id = effect_id @property @@ -247,11 +248,13 @@ def raw_value(self): return self._effect_id @property + # pylint: disable=invalid-name def id(self): """Return the effect ID.""" return self._effect_id @id.setter + # pylint: disable=invalid-name def id(self, effect_id): """Set the effect ID.""" if not 0 <= effect_id <= 123: From 7f00c4c759d975a9e62bc54f69a92039e086bd20 Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Thu, 1 Nov 2018 21:20:33 -0600 Subject: [PATCH 5/6] Improve Effect and Pause docstrings * Change @property docstrings to read like variables * Remove unnecessary docstrings for __repr__() methods * Shorten class docstrings https://github.com/adafruit/Adafruit_CircuitPython_DRV2605/issues/9#issuecomment-432316608 --- adafruit_drv2605.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/adafruit_drv2605.py b/adafruit_drv2605.py index c953fcb..2a6a43d 100644 --- a/adafruit_drv2605.py +++ b/adafruit_drv2605.py @@ -236,7 +236,7 @@ def use_LRM(self): class Effect: - """Class for adding an effect to the DRV2605 waveform sequence.""" + """DRV2605 waveform sequence effect.""" def __init__(self, effect_id): self._effect_id = 0 # pylint: disable=invalid-name @@ -244,13 +244,13 @@ def __init__(self, effect_id): @property def raw_value(self): - """Return the raw effect ID.""" + """Raw effect ID.""" return self._effect_id @property # pylint: disable=invalid-name def id(self): - """Return the effect ID.""" + """Effect ID.""" return self._effect_id @id.setter @@ -262,7 +262,6 @@ def id(self, effect_id): self._effect_id = effect_id def __repr__(self): - """Return a string representation of the Effect class.""" return "{}({})".format(type(self).__qualname__, self.id) @@ -278,7 +277,7 @@ def __init__(self, duration): @property def raw_value(self): - """Return the raw pause duration.""" + """Raw pause duration.""" return self._duration @property @@ -294,7 +293,6 @@ def duration(self, duration): self._duration = 0x80 | duration def __repr__(self): - """Return a string representation of the Pause class.""" return "{}({})".format(type(self).__qualname__, self.duration) From f978a655bfb31044037908cc67a0305c434326c5 Mon Sep 17 00:00:00 2001 From: Josh Gadeken Date: Thu, 1 Nov 2018 21:35:43 -0600 Subject: [PATCH 6/6] Change Pause class to use seconds https://github.com/adafruit/Adafruit_CircuitPython_DRV2605/issues/9#issuecomment-432316608 --- adafruit_drv2605.py | 22 +++++++++++----------- examples/drv2605_simpletest.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/adafruit_drv2605.py b/adafruit_drv2605.py index 2a6a43d..77abd5c 100644 --- a/adafruit_drv2605.py +++ b/adafruit_drv2605.py @@ -267,11 +267,9 @@ def __repr__(self): class Pause: - """Class for adding a pause to the DRV2605 waveform sequence. - Duration is specified in tens of milliseconds, as per page 35 - of the datasheet. I.e. Pause time = 10ms * duration - """ + """DRV2605 waveform sequence timed delay.""" def __init__(self, duration): + # Bit 7 must be set for a slot to be interpreted as a delay self._duration = 0x80 self.duration = duration @@ -282,15 +280,17 @@ def raw_value(self): @property def duration(self): - """Return the pause duration.""" - return self._duration & 0x7f + """Pause duration in seconds.""" + # Remove wait time flag bit and convert duration to seconds + return (self._duration & 0x7f) / 100.0 @duration.setter def duration(self, duration): - """Set the pause duration.""" - if not 0 <= duration <= 127: - raise ValueError('Pause duration must be a value within 0-127!') - self._duration = 0x80 | duration + """Set the pause duration in seconds.""" + if not 0.0 <= duration <= 1.27: + raise ValueError('Pause duration must be a value within 0.0-1.27!') + # Add wait time flag bit and convert duration to centiseconds + self._duration = 0x80 | round(duration * 100.0) def __repr__(self): return "{}({})".format(type(self).__qualname__, self.duration) @@ -318,7 +318,7 @@ def __getitem__(self, slot): # pylint: disable=protected-access slot_contents = self._drv2605._read_u8(_DRV2605_REG_WAVESEQ1 + slot) if slot_contents & 0x80: - return Pause(slot_contents & 0x7f) + return Pause((slot_contents & 0x7f) / 100.0) return Effect(slot_contents) def __iter__(self): diff --git a/examples/drv2605_simpletest.py b/examples/drv2605_simpletest.py index d0100f4..94bc285 100644 --- a/examples/drv2605_simpletest.py +++ b/examples/drv2605_simpletest.py @@ -24,7 +24,7 @@ # them in interesting ways. Index the sequence property with a # slot number 0 to 6. # Optionally, you can assign a pause to a slot. E.g. - # drv.sequence[1] = adafruit_drv2605.Pause(5) # Pause for 50 milliseconds + # drv.sequence[1] = adafruit_drv2605.Pause(0.5) # Pause for half a second drv.play() # Play the effect. time.sleep(0.5) # Increment effect ID and wrap back around to 1.