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::*;