blinksy/lib.rs
1#![no_std]
2
3//! # Blinksy
4//!
5//! Blinksy is a no-std, no-alloc LED control library designed for 1D, 2D, and 3D
6//! LED setups, inspired by [FastLED](https://fastled.io/) and [WLED](https://kno.wled.ge/).
7//!
8//! ## How Blinksy works
9//!
10//! - Define your LED [`layout`] in 1D, 2D, or 3D space
11//! - Create your visual [`pattern`] (effect), or choose from our built-in [`patterns`] library
12//! - The pattern will compute colors for each LED based on its position
13//! - Setup a [`driver`] to send each frame of colors to your [`leds`]
14//!
15//! ## Features
16//!
17//! - **No-std, no-alloc**: Designed for embedded targets.
18//! - **Spatial in 1D, 2D, or 3D**: Map out the shape of your LEDs in space.
19//! - **Async support**: Supports blocking or asynchronous execution.
20//! - **Full color support**: Supports modern and classic color spaces.
21//! - **Global settings**: Control overall brightness and color correction.
22//! - **Desktop simulation**: Simulate your LEDs on your desktop to play with ideas.
23//! - **RGB+W support**: Supports RGB + White color channels
24//!
25//! ### LED Support
26//!
27//! #### [Clockless](crate::driver::clockless): One-wire (only data, no clock)
28//!
29//! - **[WS2812B]**: Affordable RGB LED, aka NeoPixel
30//! - **[SK6812]**: RGBW LED
31//!
32//! #### [Clocked](crate::driver::clocked): Two-wire (data and clock)
33//!
34//! - **[APA102]**: High-FPS RGB LED, aka DotStar
35//!
36//! If you want help to support a new LED chipset, [make an issue](https://github.com/ahdinosaur/blinksy/issues)!
37//!
38//! [WS2812B]: leds::Ws2812
39//! [SK6812]: leds::Sk6812
40//! [APA102]: leds::Apa102
41//!
42//! ### Pattern (Effect) Library:
43//!
44//! - **[Rainbow]**: A basic scrolling rainbow
45//! - **[Noise]**: A flow through random noise functions
46//!
47//! If you want help to port a pattern from FastLED / WLED to Rust, [make an issue](https://github.com/ahdinosaur/blinksy/issues)!
48//!
49//! [Rainbow]: patterns::rainbow
50//! [Noise]: patterns::noise
51//!
52//! ### Microcontroller Family Support
53//!
54//! **Clocked LED support (e.g. APA102):**
55//!
56//! | Micro | HAL | Blinksy | Recommended Writer | Backup Writer
57//! |-------|----------------|-------------|--------------------|------------------|
58//! | ALL | [embedded-hal] | [blinksy] | [embedded_hal::spi::SpiBus] / [embedded_hal_async::spi::SpiBus] | [Delay][clocked-delay] |
59//!
60//! [embedded-hal]: embedded_hal
61//! [blinksy]: crate
62//! [clocked-delay]: crate::driver::clocked::ClockedDelay
63//!
64//! **Clockless LED support (e.g. WS2812):**
65//!
66//! | Micro | HAL | Blinksy | Recommended Driver | Backup Driver |
67//! |----------------|-------------|---------------|------------------------|---------------|
68//! | ALL | [embedded-hal] | [blinksy] | - | TODO [Spi #12][clockless-spi] |
69//! | ESP32 | [esp-hal] | [blinksy-esp] | [Rmt][rmt] | - |
70//! | RP (2040/2350) | [rp-hal] | TODO | TODO [#36][rp-issue] | - |
71//! | STM32 | [stm32-hal] | TODO | TODO [#78][stm32-issue] | - |
72//! | nRF | [nrf-hal] | TODO | TODO [#77][nrf-issue] | - |
73//! | atsamd | [atsamd] | TODO | TODO [#67][atsamd-issue] | - |
74//! | AVR (Arduino) | [avr-hal] | TODO | TODO [#79][avr-issue] | - |
75//! | CH32 | [ch32-hal] | TODO | TODO [#80][ch32-issue] | - |
76//! | ??? | - | - | - | - |
77//!
78//! [clockless-spi]: https://github.com/ahdinosaur/blinksy/issues/12
79//! [esp-hal]: https://docs.espressif.com/projects/rust/esp-hal/latest/
80//! [blinksy-esp]: https://docs.rs/blinksy-esp/0.10/
81//! [rmt]: https://docs.espressif.com/projects/rust/esp-hal/latest/
82//! [rp-hal]: https://github.com/rp-rs/rp-hal/
83//! [rp-issue]: https://github.com/ahdinosaur/blinksy/issues/36
84//! [stm32-hal]: https://github.com/David-OConnor/stm32-hal
85//! [stm32-issue]: https://github.com/ahdinosaur/blinksy/issues/78
86//! [nrf-hal]: https://github.com/nrf-rs/nrf-hal
87//! [nrf-issue]: https://github.com/ahdinosaur/blinksy/issues/77
88//! [atsamd]: https://github.com/atsamd-rs/atsamd
89//! [atsamd-issue]: https://github.com/ahdinosaur/blinksy/issues/67
90//! [avr-hal]: https://github.com/Rahix/avr-hal
91//! [avr-issue]: https://github.com/ahdinosaur/blinksy/issues/79
92//! [ch32-hal]: https://github.com/ch32-rs/ch32-hal
93//! [ch32-issue]: https://github.com/ahdinosaur/blinksy/issues/80
94//!
95//! If you want help to support a new microcontroller family, [make an issue](https://github.com/ahdinosaur/blinksy/issues)!
96//!
97//! ### Board Support Packages
98//!
99//! - **[Gledopto]**: A great LED controller available on AliExpress: [Gledopto GL-C-016WL-D](https://www.aliexpress.com/item/1005008707989546.html)
100//! - (TODO) [**QuinLED**](https://quinled.info/): The best DIY and pre-assembled LED controller boards
101//!
102//! If you want help to support a new target, [make an issue](https://github.com/ahdinosaur/blinksy/issues)!
103//!
104//! [Gledopto]: https://docs.rs/gledopto/0.10/gledopto
105//!
106//! ## Quick Start
107//!
108//! To quickstart a project, see:
109//!
110//! - [`blinksy-quickstart-1d-rope`][blinksy-quickstart-1d-rope]
111//! - [`blinksy-quickstart-3d-grid`][blinksy-quickstart-3d-grid]
112//!
113//! To start using the library, see [control][control].
114//!
115//! [blinksy-quickstart-1d-rope]: https://github.com/ahdinosaur/blinksy-quickstart-1d-rope
116//! [blinksy-quickstart-3d-grid]: https://github.com/ahdinosaur/blinksy-quickstart-3d-grid
117//! [control]: https://docs.rs/blinksy/0.10/blinksy/control/index.html
118//!
119//! ### 1D Strip with Rainbow Pattern (Blocking)
120//!
121//! ### 1D Strip with Rainbow Pattern (Blocking)
122//!
123//! ```rust,ignore
124//! # use blinksy::{ControlBuilder, layout::Layout1d, layout1d, patterns::rainbow::{Rainbow, RainbowParams}};
125//! #
126//! // Define a 1D layout with 60 LEDs
127//! layout1d!(Layout, 60);
128//!
129//! let mut control = ControlBuilder::new_1d()
130//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
131//! .with_pattern::<Rainbow>(RainbowParams::default())
132//! .with_driver(/* Insert your LED driver here */)
133//! .with_frame_buffer_size::</* Length of frame buffer */>()
134//! .build();
135//!
136//! control.set_brightness(0.5);
137//!
138//! loop {
139//! control.tick(/* current time in milliseconds */).unwrap();
140//! }
141//! ```
142//!
143//! ### 1D Strip with Rainbow Pattern (Async)
144//!
145//! ```rust,ignore
146//! # use blinksy::{ControlBuilder, layout::Layout1d, layout1d, patterns::rainbow::{Rainbow, RainbowParams}};
147//! #
148//! // Define a 1D layout with 60 LEDs
149//! layout1d!(Layout, 60);
150//!
151//! let mut control = ControlBuilder::new_1d_async()
152//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
153//! .with_pattern::<Rainbow>(RainbowParams::default())
154//! .with_driver(/* Insert your LED driver here */)
155//! .with_frame_buffer_size::</* Length of frame buffer */>()
156//! .build();
157//!
158//! control.set_brightness(0.5);
159//!
160//! loop {
161//! control.tick(/* current time in milliseconds */).await.unwrap();
162//! }
163//! ```
164//!
165//! ### 2D Grid with Noise Pattern (Blocking)
166//!
167//! ```rust,ignore
168//! # use blinksy::{
169//! # ControlBuilder,
170//! # layout::{Layout2d, Shape2d, Vec2},
171//! # layout2d,
172//! # patterns::noise::{noise_fns, Noise2d, NoiseParams},
173//! # };
174//! #
175//! layout2d!(
176//! Layout,
177//! [Shape2d::Grid {
178//! start: Vec2::new(-1., -1.),
179//! horizontal_end: Vec2::new(1., -1.),
180//! vertical_end: Vec2::new(-1., 1.),
181//! horizontal_pixel_count: 16,
182//! vertical_pixel_count: 16,
183//! serpentine: true,
184//! }]
185//! );
186//! let mut control = ControlBuilder::new_2d()
187//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
188//! .with_pattern::<Noise2d<noise_fns::Perlin>>(NoiseParams::default())
189//! .with_driver(/* Insert your LED driver here */)
190//! .with_frame_buffer_size::</* Length of frame buffer */>()
191//! .build();
192//!
193//! control.set_brightness(0.5);
194//!
195//! loop {
196//! control.tick(/* current time in milliseconds */).unwrap();
197//! }
198//! ```
199//!
200//! ### 3D Cube with Noise Pattern (Blocking)
201//!
202//! ```rust,ignore
203//! # use blinksy::{
204//! # layout::{Layout3d, Shape3d, Vec3},
205//! # layout3d,
206//! # patterns::noise::{noise_fns, Noise3d, NoiseParams},
207//! # ControlBuilder,
208//! # };
209//! #
210//! layout3d!(
211//! Layout,
212//! [
213//! // bottom face
214//! Shape3d::Grid {
215//! start: Vec3::new(1., -1., 1.), // right bottom front
216//! horizontal_end: Vec3::new(-1., -1., 1.), // left bottom front
217//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
218//! horizontal_pixel_count: 16,
219//! vertical_pixel_count: 16,
220//! serpentine: true,
221//! },
222//! // back face
223//! Shape3d::Grid {
224//! start: Vec3::new(-1., -1., -1.), // left bottom back
225//! horizontal_end: Vec3::new(-1., 1., -1.), // left top back
226//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
227//! horizontal_pixel_count: 16,
228//! vertical_pixel_count: 16,
229//! serpentine: true,
230//! },
231//! // right face
232//! Shape3d::Grid {
233//! start: Vec3::new(1., 1., -1.), // right top back
234//! horizontal_end: Vec3::new(1., 1., 1.), // right top front
235//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
236//! horizontal_pixel_count: 16,
237//! vertical_pixel_count: 16,
238//! serpentine: true,
239//! },
240//! // front face
241//! Shape3d::Grid {
242//! start: Vec3::new(-1., -1., 1.), // left bottom front
243//! horizontal_end: Vec3::new(1., -1., 1.), // right bottom front
244//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
245//! horizontal_pixel_count: 16,
246//! vertical_pixel_count: 16,
247//! serpentine: true,
248//! },
249//! // left face
250//! Shape3d::Grid {
251////! start: Vec3::new(-1., 1., -1.), // left top back
252//! horizontal_end: Vec3::new(-1., -1., -1.), // left bottom back
253//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
254//! horizontal_pixel_count: 16,
255//! vertical_pixel_count: 16,
256//! serpentine: true,
257//! },
258//! // top face
259//! Shape3d::Grid {
260//! start: Vec3::new(1., 1., 1.), // right top front
261//! horizontal_end: Vec3::new(1., 1., -1.), // right top back
262//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
263//! horizontal_pixel_count: 16,
264//! vertical_pixel_count: 16,
265//! serpentine: true,
266//! }
267//! ]
268//! );
269//!
270//! let mut control = ControlBuilder::new_3d()
271//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
272//! .with_pattern::<Noise3d<noise_fns::Perlin>>(NoiseParams::default())
273//! .with_driver(/* Insert your LED driver here */)
274//! .with_frame_buffer_size::</* Length of frame buffer */>()
275//! .build();
276//!
277//! control.set_brightness(0.2);
278//!
279//! loop {
280//! control.tick(/* current time in milliseconds */).unwrap();
281//! }
282//! ```
283//!
284//! ### 2D Grid with Noise Pattern (Blocking)
285//!
286//! ```rust,ignore
287//! # use blinksy::{
288//! # ControlBuilder,
289//! # layout::{Layout2d, Shape2d, Vec2},
290//! # layout2d,
291//! # patterns::noise::{noise_fns, Noise2d, NoiseParams},
292//! # };
293//! #
294//! layout2d!(
295//! Layout,
296//! [Shape2d::Grid {
297//! start: Vec2::new(-1., -1.),
298//! horizontal_end: Vec2::new(1., -1.),
299//! vertical_end: Vec2::new(-1., 1.),
300//! horizontal_pixel_count: 16,
301//! vertical_pixel_count: 16,
302//! serpentine: true,
303//! }]
304//! );
305//! let mut control = ControlBuilder::new_2d()
306//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
307//! .with_pattern::<Noise2d<noise_fns::Perlin>>(NoiseParams::default())
308//! .with_driver(/* Insert your LED driver here */)
309//! .build();
310//!
311//! control.set_brightness(0.5);
312//!
313//! loop {
314//! control.tick(/* current time in milliseconds */).unwrap();
315//! }
316//! ```
317//!
318//! ### 3D Cube with Noise Pattern (Blocking)
319//!
320//! ```rust,ignore
321//! # use blinksy::{
322//! # layout::{Layout3d, Shape3d, Vec3},
323//! # layout3d,
324//! # patterns::noise::{noise_fns, Noise3d, NoiseParams},
325//! # ControlBuilder,
326//! # };
327//! #
328//! layout3d!(
329//! Layout,
330//! [
331//! // bottom face
332//! Shape3d::Grid {
333//! start: Vec3::new(1., -1., 1.), // right bottom front
334//! horizontal_end: Vec3::new(-1., -1., 1.), // left bottom front
335//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
336//! horizontal_pixel_count: 16,
337//! vertical_pixel_count: 16,
338//! serpentine: true,
339//! },
340//! // back face
341//! Shape3d::Grid {
342//! start: Vec3::new(-1., -1., -1.), // left bottom back
343//! horizontal_end: Vec3::new(-1., 1., -1.), // left top back
344//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
345//! horizontal_pixel_count: 16,
346//! vertical_pixel_count: 16,
347//! serpentine: true,
348//! },
349//! // right face
350//! Shape3d::Grid {
351//! start: Vec3::new(1., 1., -1.), // right top back
352//! horizontal_end: Vec3::new(1., 1., 1.), // right top front
353//! vertical_end: Vec3::new(1., -1., -1.), // right bottom back
354//! horizontal_pixel_count: 16,
355//! vertical_pixel_count: 16,
356//! serpentine: true,
357//! },
358//! // front face
359//! Shape3d::Grid {
360//! start: Vec3::new(-1., -1., 1.), // left bottom front
361//! horizontal_end: Vec3::new(1., -1., 1.), // right bottom front
362//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
363//! horizontal_pixel_count: 16,
364//! vertical_pixel_count: 16,
365//! serpentine: true,
366//! },
367//! // left face
368//! Shape3d::Grid {
369//! start: Vec3::new(-1., 1., -1.), // left top back
370//! horizontal_end: Vec3::new(-1., -1., -1.), // left bottom back
371//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
372//! horizontal_pixel_count: 16,
373//! vertical_pixel_count: 16,
374//! serpentine: true,
375//! },
376//! // top face
377//! Shape3d::Grid {
378//! start: Vec3::new(1., 1., 1.), // right top front
379//! horizontal_end: Vec3::new(1., 1., -1.), // right top back
380//! vertical_end: Vec3::new(-1., 1., 1.), // left top front
381//! horizontal_pixel_count: 16,
382//! vertical_pixel_count: 16,
383//! serpentine: true,
384//! }
385//! ]
386//! );
387//!
388//! let mut control = ControlBuilder::new_3d()
389//! .with_layout::<Layout, { Layout::PIXEL_COUNT }>()
390//! .with_pattern::<Noise3d<noise_fns::Perlin>>(NoiseParams::default())
391//! .with_driver(/* Insert your LED driver here */)
392//! .build();
393//!
394//! control.set_brightness(0.2);
395//!
396//! loop {
397//! control.tick(/* current time in milliseconds */).unwrap();
398//! }
399//! ```
400//!
401
402pub mod color;
403pub mod control;
404pub mod driver;
405pub mod layout;
406pub mod leds;
407pub mod markers;
408pub mod pattern;
409pub mod patterns;
410pub mod time;
411pub mod util;
412
413pub use self::control::*;