Skip to content

Commit 6eb1c0b

Browse files
author
Kevin J Walters
committed
WS2801 constructor argument brightness unlikely to work at the momemt due to inherited strangeness/bug.
1 parent 5f1567f commit 6eb1c0b

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

adafruit_ws2801.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2016 Damien P. George (original Neopixel object)
4+
# Copyright (c) 2017 Ladyada
5+
# Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
6+
# Copyright (c) 2018 Kevin Walters
7+
#
8+
# Permission is hereby granted, free of charge, to any person obtaining a copy
9+
# of this software and associated documentation files (the "Software"), to deal
10+
# in the Software without restriction, including without limitation the rights
11+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
# copies of the Software, and to permit persons to whom the Software is
13+
# furnished to do so, subject to the following conditions:
14+
#
15+
# The above copyright notice and this permission notice shall be included in
16+
# all copies or substantial portions of the Software.
17+
#
18+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
# THE SOFTWARE.
25+
26+
"""
27+
`adafruit_ws2801` - WS2801 LED pixel string driver
28+
====================================================
29+
30+
* Author(s): Damien P. George, Limor Fried & Scott Shawcroft, Kevin Walters
31+
"""
32+
import math
33+
34+
import busio
35+
import digitalio
36+
37+
__version__ = "0.0.0-auto.0"
38+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_WS2801.git"
39+
40+
### based on https://github.com/adafruit/Adafruit_CircuitPython_DotStar
41+
42+
class WS2801:
43+
"""
44+
A sequence of WS2801 controlled LEDs.
45+
46+
:param ~microcontroller.Pin clock: The pin to output dotstar clock on.
47+
:param ~microcontroller.Pin data: The pin to output dotstar data on.
48+
:param int n: The number of LEDs in the chain.
49+
:param float brightness: The brightness between 0.0 and (default) 1.0.
50+
:param bool auto_write: True if the dotstars should immediately change when
51+
set. If False, `show` must be called explicitly.
52+
53+
54+
Example for Gemma M0:
55+
56+
.. code-block:: python
57+
58+
import adafruit_ws2801
59+
import time
60+
from board import *
61+
62+
RED = 0x100000
63+
64+
with adafruit_ws2801.WS2801(board.D2, board.D0, 25, brightness=1.0) as pixels:
65+
pixels[0] = RED
66+
time.sleep(2)
67+
"""
68+
69+
def __init__(self, clock, data, n, *, brightness=1.0, auto_write=True):
70+
self._spi = None
71+
try:
72+
self._spi = busio.SPI(clock, MOSI=data)
73+
while not self._spi.try_lock():
74+
pass
75+
self._spi.configure(baudrate=1000*1000)
76+
except ValueError:
77+
self.dpin = digitalio.DigitalInOut(data)
78+
self.cpin = digitalio.DigitalInOut(clock)
79+
self.dpin.direction = digitalio.Direction.OUTPUT
80+
self.cpin.direction = digitalio.Direction.OUTPUT
81+
self.cpin.value = False
82+
self._n = n
83+
self._buf = bytearray(n * 3)
84+
### TODO - review brightness oddity inherited from adafruit_dotstar
85+
self._brightness = 1.0
86+
self.brightness = brightness
87+
self.auto_write = auto_write
88+
### TODO - review/consider adding GRB support like that in c++ version
89+
90+
def deinit(self):
91+
"""Blank out the DotStars and release the resources."""
92+
self.auto_write = False
93+
black=(0,0,0)
94+
self.fill(black)
95+
self.show()
96+
if self._spi:
97+
self._spi.deinit()
98+
else:
99+
self.dpin.deinit()
100+
self.cpin.deinit()
101+
102+
def __enter__(self):
103+
return self
104+
105+
def __exit__(self, exception_type, exception_value, traceback):
106+
self.deinit()
107+
108+
def __repr__(self):
109+
return "[" + ", ".join([str(x) for x in self]) + "]"
110+
111+
def _set_item(self, index, value):
112+
offset = index * 3
113+
if isinstance(value, int):
114+
r = value >> 16
115+
g = (value >> 8) & 0xff
116+
b = value & 0xff
117+
else:
118+
r, g, b = value
119+
# red/green/blue order for WS2801
120+
self._buf[offset] = r
121+
self._buf[offset + 1] = g
122+
self._buf[offset + 2] = b
123+
124+
def __setitem__(self, index, val):
125+
if isinstance(index, slice):
126+
start, stop, step = index.indices(self._n)
127+
length = stop - start
128+
if step != 0:
129+
length = math.ceil(length / step)
130+
if len(val) != length:
131+
raise ValueError("Slice and input sequence size do not match.")
132+
for val_i, in_i in enumerate(range(start, stop, step)):
133+
self._set_item(in_i, val[val_i])
134+
else:
135+
self._set_item(index, val)
136+
137+
if self.auto_write:
138+
self.show()
139+
140+
def __getitem__(self, index):
141+
if isinstance(index, slice):
142+
out = []
143+
for in_i in range(*index.indices(self._n)):
144+
out.append(
145+
tuple(self._buf[in_i * 3 + (2 - i)] for i in range(3)))
146+
return out
147+
if index < 0:
148+
index += len(self)
149+
if index >= self._n or index < 0:
150+
raise IndexError
151+
offset = index * 3
152+
return tuple(self._buf[offset + (2 - i)] for i in range(3))
153+
154+
def __len__(self):
155+
return self._n
156+
157+
@property
158+
def brightness(self):
159+
"""Overall brightness of the pixel"""
160+
return self._brightness
161+
162+
@brightness.setter
163+
def brightness(self, brightness):
164+
self._brightness = min(max(brightness, 0.0), 1.0)
165+
166+
def fill(self, color):
167+
"""Colors all pixels the given ***color***."""
168+
auto_write = self.auto_write
169+
self.auto_write = False
170+
for i, _ in enumerate(self):
171+
self[i] = color
172+
if auto_write:
173+
self.show()
174+
self.auto_write = auto_write
175+
176+
def _ds_writebytes(self, buf):
177+
for b in buf:
178+
for _ in range(8):
179+
self.cpin.value = True
180+
self.dpin.value = (b & 0x80)
181+
self.cpin.value = False
182+
b = b << 1
183+
184+
def show(self):
185+
"""Shows the new colors on the pixels themselves if they haven't already
186+
been autowritten.
187+
188+
The colors may or may not be showing after this function returns because
189+
it may be done asynchronously."""
190+
# Create a second output buffer if we need to compute brightness
191+
buf = self._buf
192+
if self.brightness < 1.0:
193+
buf = bytearray(len(self._buf))
194+
for i in range(self._n):
195+
buf[i] = int(self._buf[i] * self._brightness)
196+
197+
if self._spi:
198+
self._spi.write(buf)
199+
else:
200+
self._ds_writebytes(buf)
201+
self.cpin.value = False

0 commit comments

Comments
 (0)