1#![no_std]
2
3use core::{fmt, slice, mem, ptr};
4
5pub use rpi_ws281x_sys as bindings;
6pub use rpi_ws281x_sys::ws2811_return_t as ErrorCode;
7
8#[repr(transparent)]
9pub struct PiInfo(&'static bindings::rpi_hw_t);
11
12impl PiInfo {
13 #[inline]
14 pub fn detect() -> Option<Self> {
16 unsafe {
18 bindings::rpi_hw_detect().as_ref().map(PiInfo)
19 }
20 }
21
22 #[inline(always)]
23 pub const fn revision(&self) -> u32 {
25 self.0.hwver
26 }
27
28 #[inline(always)]
29 pub const fn periph_base(&self) -> u32 {
31 self.0.periph_base
32 }
33
34 #[inline(always)]
35 pub const fn video_core_base(&self) -> u32 {
37 self.0.videocore_base
38 }
39
40 #[inline(always)]
41 pub fn description(&self) -> &'static str {
45 let bytes = unsafe {
46 let len = libc::strlen(self.0.desc);
47 core::slice::from_raw_parts(self.0.desc as *const u8, len as usize)
48 };
49
50 match core::str::from_utf8(bytes) {
51 Ok(result) => result,
52 Err(_) => "",
53 }
54 }
55}
56
57impl fmt::Debug for PiInfo {
58 #[inline]
59 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
60 fmt.debug_struct("PiInfo")
61 .field("revision", &self.revision())
62 .field("description", &self.description())
63 .field("peripheral base", &self.periph_base())
64 .field("video core base", &self.video_core_base())
65 .finish()
66 }
67}
68
69#[repr(u32)]
70pub enum PwmPin {
72 Pwm0_1 = 12,
74 Pwm0_2 = 18,
76 Pwm1_1 = 13,
78 Pwm1_2 = 19,
80}
81
82#[repr(u32)]
83pub enum SpiPin {
85 Spi0 = 10,
87}
88
89#[repr(u32)]
90pub enum PcmPin {
92 Board = 21,
94 P5 = 31,
96}
97
98#[repr(transparent)]
99pub struct Channel(bindings::ws2811_channel_t);
101
102impl Channel {
103 pub const fn disabled() -> Self {
105 Self(bindings::ws2811_channel_t {
106 gpionum: 0,
107 invert: 0,
108 count: 0,
109 strip_type: bindings::WS2811_STRIP_RGB as _,
110 leds: ptr::null_mut(),
111 brightness: 0,
112 wshift: 0,
113 rshift: 0,
114 gshift: 0,
115 bshift: 0,
116 gamma: ptr::null_mut(),
117 })
118 }
119
120 #[inline]
121 pub const fn set_pwm(pin: PwmPin) -> Self {
123 let mut ch = Channel::disabled();
124 ch.0.gpionum = pin as _;
125 ch
126 }
127
128 #[inline]
129 pub const fn set_pcm(pin: PcmPin) -> Self {
131 let mut ch = Channel::disabled();
132 ch.0.gpionum = pin as _;
133 ch
134 }
135
136 #[inline]
137 pub const fn set_spi(pin: SpiPin) -> Self {
139 let mut ch = Channel::disabled();
140 ch.0.gpionum = pin as _;
141 ch
142 }
143
144 #[inline]
145 pub const fn set_led_count(mut self, led_count: u16) -> Self {
147 debug_assert!(led_count > 0);
148 self.0.count = led_count as _;
149 self
150 }
151
152 #[inline]
153 pub const fn set_brightness(mut self, brightness: u8) -> Self {
155 self.0.brightness = brightness;
156 self
157 }
158
159 #[inline]
160 pub fn get_brightness(&self) -> u8 {
162 self.0.brightness
163 }
164
165 #[inline]
166 pub fn change_brightness(&mut self, brightness: u8) {
168 self.0.brightness = brightness;
169 }
170
171 #[inline]
172 const fn set_strip(mut self, strip: u32) -> Self {
173 self.0.strip_type = strip as _;
174 self
175 }
176
177 #[inline]
178 pub const fn set_strip_rgb(self) -> Self {
180 self.set_strip(bindings::WS2811_STRIP_RGB)
181 }
182
183 #[inline]
184 pub const fn set_strip_rbg(self) -> Self {
186 self.set_strip(bindings::WS2811_STRIP_RBG)
187 }
188
189 #[inline]
190 pub const fn set_strip_grb(self) -> Self {
192 self.set_strip(bindings::WS2811_STRIP_GRB)
193 }
194
195 #[inline]
196 pub const fn set_strip_gbr(self) -> Self {
198 self.set_strip(bindings::WS2811_STRIP_GBR)
199 }
200
201 #[inline]
202 pub const fn set_strip_bgr(self) -> Self {
204 self.set_strip(bindings::WS2811_STRIP_BGR)
205 }
206
207 #[inline]
208 pub const fn set_strip_brg(self) -> Self {
210 self.set_strip(bindings::WS2811_STRIP_BRG)
211 }
212
213 #[inline]
214 pub fn leds(&self) -> &[bindings::ws2811_led_t] {
216 debug_assert!(!self.0.leds.is_null());
217
218 unsafe {
219 slice::from_raw_parts(self.0.leds, self.0.count as usize)
220 }
221 }
222
223 #[inline]
224 pub fn leds_mut(&mut self) -> &mut [bindings::ws2811_led_t] {
226 debug_assert!(!self.0.leds.is_null());
227
228 unsafe {
229 slice::from_raw_parts_mut(self.0.leds, self.0.count as usize)
230 }
231 }
232}
233
234#[derive(Copy, Clone)]
235pub struct DriverBuilder {
243 render_wait_time: u64,
244 freq: u32,
245 dma_channel: u8,
246 channel: [bindings::ws2811_channel_t; 2],
247}
248
249impl DriverBuilder {
250 #[inline]
251 pub const fn new() -> Self {
253 Self {
254 render_wait_time: 0,
255 freq: bindings::WS2811_TARGET_FREQ,
256 dma_channel: 10,
257 channel: [Channel::disabled().0; 2],
258 }
259 }
260
261 #[inline]
262 pub const fn render_wait_time(mut self, render_wait_time: u64) -> Self {
264 self.render_wait_time = render_wait_time;
265 self
266 }
267
268 #[inline]
269 pub const fn freq(mut self, freq: u32) -> Self {
271 debug_assert!(freq > 0);
272 self.freq = freq;
273 self
274 }
275
276 #[inline]
277 pub const fn dma(mut self, dma_num: u8) -> Self {
279 self.dma_channel = dma_num;
280 self
281 }
282
283
284 pub const fn channel1(mut self, channel: Channel) -> Self {
286 debug_assert!(channel.0.gpionum != PwmPin::Pwm0_1 as i32);
288 debug_assert!(channel.0.gpionum != PwmPin::Pwm0_2 as i32);
289
290 self.channel[0] = channel.0;
291 self
292 }
293
294 pub const fn channel2(mut self, channel: Channel) -> Self {
296 debug_assert!(channel.0.gpionum == PwmPin::Pwm1_1 as i32 || channel.0.gpionum == PwmPin::Pwm1_2 as i32);
298
299 self.channel[1] = channel.0;
300 self
301 }
302
303 #[inline]
304 pub fn build(self) -> Result<Driver, ErrorCode> {
305 let mut inner = bindings::ws2811_t {
306 render_wait_time: 0,
307 device: core::ptr::null_mut(),
308 rpi_hw: core::ptr::null(),
309 freq: self.freq,
310 dmanum: self.dma_channel as _,
311 channel: self.channel,
312 };
313
314 let result = unsafe {
315 bindings::ws2811_init(&mut inner)
316 };
317
318 match result {
319 ErrorCode::WS2811_SUCCESS => Ok(Driver {
320 inner,
321 }),
322 error => Err(error),
323 }
324 }
325}
326
327#[repr(transparent)]
328pub struct Driver {
330 inner: bindings::ws2811_t,
331}
332
333impl Driver {
334 #[inline]
335 pub const fn builder() -> DriverBuilder {
337 DriverBuilder::new()
338 }
339
340 #[inline]
341 pub const fn channel1(&self) -> &'_ Channel {
343 unsafe {
344 mem::transmute(&self.inner.channel[0])
345 }
346 }
347
348 #[inline]
349 pub fn channel1_mut(&mut self) -> &'_ mut Channel {
351 unsafe {
352 mem::transmute(&mut self.inner.channel[0])
353 }
354 }
355
356 #[inline]
357 pub const fn channel2(&self) -> &'_ Channel {
361 unsafe {
362 mem::transmute(&self.inner.channel[1])
363 }
364 }
365
366 #[inline]
367 pub fn channel2_mut(&mut self) -> &'_ mut Channel {
369 unsafe {
370 mem::transmute(&mut self.inner.channel[1])
371 }
372 }
373
374 #[inline]
375 pub fn render(&mut self) -> Result<(), ErrorCode> {
377 let result = unsafe {
378 bindings::ws2811_render(&mut self.inner)
379 };
380
381 match result {
382 ErrorCode::WS2811_SUCCESS => Ok(()),
383 error => Err(error),
384 }
385 }
386
387 #[inline]
388 pub fn wait(&mut self) -> Result<(), ErrorCode> {
392 let result = unsafe {
393 bindings::ws2811_wait(&mut self.inner)
394 };
395
396 match result {
397 ErrorCode::WS2811_SUCCESS => Ok(()),
398 error => Err(error),
399 }
400 }
401
402 #[inline]
403 pub fn set_gamma_factor(&mut self, factor: f64) {
405 unsafe {
406 bindings::ws2811_set_custom_gamma_factor(&mut self.inner, factor)
407 }
408 }
409
410 #[inline]
411 pub fn stop(&mut self) {
419 if !self.inner.device.is_null() {
420 unsafe {
423 bindings::ws2811_fini(&mut self.inner)
424 }
425 }
426 }
427
428 pub const fn as_inner(&self) -> &bindings::ws2811_t {
430 &self.inner
431 }
432}
433
434impl Drop for Driver {
435 #[inline]
436 fn drop(&mut self) {
437 self.stop()
438 }
439}