1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use bindings::RGBLedMatrixOptions;
6use std::{env, ffi::CString, ptr};
7
8use crate::bindings::RGBLedRuntimeOptions;
9
10pub mod bindings {
11 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
12}
13
14impl Default for bindings::RGBLedMatrixOptions {
15 fn default() -> Self {
16 Self {
17 hardware_mapping: std::ptr::null(),
18 rows: 32,
19 cols: 0,
20 chain_length: 1,
21 parallel: 1,
22 pwm_bits: 0,
23 pwm_lsb_nanoseconds: 50,
24 pwm_dither_bits: 0,
25 brightness: 0,
26 scan_mode: 0,
27 row_address_type: 0,
28 multiplexing: 0,
29 disable_hardware_pulsing: 0,
30 show_refresh_rate: 1,
31 inverse_colors: 0,
32 led_rgb_sequence: std::ptr::null(),
33 pixel_mapper_config: std::ptr::null(),
34 panel_type: std::ptr::null(),
35 limit_refresh_rate_hz: 0,
36 }
37 }
38}
39
40impl bindings::RGBLedMatrixOptions {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn hardware_mapping(mut self, mapping: &str) -> Self {
46 self.hardware_mapping = std::ffi::CString::new(mapping).unwrap().into_raw();
47 self
48 }
49
50 pub fn rows(mut self, rows: u16) -> Self {
51 self.rows = rows as i32;
52 self
53 }
54 pub fn cols(mut self, cols: u16) -> Self {
55 self.cols = cols as i32;
56 self
57 }
58 pub fn chain_length(mut self, length: u16) -> Self {
59 self.chain_length = length as i32;
60 self
61 }
62 pub fn parallel(mut self, parallel: u16) -> Self {
63 self.parallel = parallel as i32;
64 self
65 }
66 pub fn pwm_bits(mut self, bits: u16) -> Self {
67 self.pwm_bits = bits as i32;
68 self
69 }
70 pub fn pwm_lsb_nanoseconds(mut self, ns: u16) -> Self {
71 self.pwm_lsb_nanoseconds = ns as i32;
72 self
73 }
74 pub fn pwm_dither_bits(mut self, bits: u16) -> Self {
75 self.pwm_dither_bits = bits as i32;
76 self
77 }
78 pub fn brightness(mut self, brightness: u16) -> Self {
79 self.brightness = brightness as i32;
80 self
81 }
82 pub fn scan_mode(mut self, mode: u16) -> Self {
83 self.scan_mode = mode as i32;
84 self
85 }
86 pub fn row_address_type(mut self, address_type: u16) -> Self {
87 self.row_address_type = address_type as i32;
88 self
89 }
90 pub fn multiplexing(mut self, multiplexing: u16) -> Self {
91 self.multiplexing = multiplexing as i32;
92 self
93 }
94 pub fn disable_hardware_pulsing(mut self, disable: bool) -> Self {
95 self.disable_hardware_pulsing = disable.into();
96 self
97 }
98 pub fn show_refresh_rate(mut self, show: bool) -> Self {
99 self.show_refresh_rate = show.into();
100 self
101 }
102 pub fn inverse_colors(mut self, inverse: bool) -> Self {
103 self.inverse_colors = inverse.into();
104 self
105 }
106 pub fn led_rgb_sequence(mut self, sequence: &str) -> Self {
107 self.led_rgb_sequence = std::ffi::CString::new(sequence).unwrap().into_raw();
108 self
109 }
110 pub fn pixel_mapper_config(mut self, config: &str) -> Self {
111 self.pixel_mapper_config = std::ffi::CString::new(config).unwrap().into_raw();
112 self
113 }
114 pub fn panel_type(mut self, panel_type: &str) -> Self {
115 self.panel_type = std::ffi::CString::new(panel_type).unwrap().into_raw();
116 self
117 }
118 pub fn limit_refresh_rate_hz(mut self, hz: u32) -> Self {
119 self.limit_refresh_rate_hz = hz as i32;
120 self
121 }
122
123 pub fn build(mut self) -> Box<bindings::RGBLedMatrix> {
124 unsafe {
125 Box::from_raw(bindings::led_matrix_create_from_options(
126 &mut self as *mut bindings::RGBLedMatrixOptions,
127 std::ptr::null_mut(),
128 std::ptr::null_mut(),
129 ))
130 }
131 }
132
133 pub fn build_with_rt_options(
134 mut self,
135 mut rt_options: RGBLedRuntimeOptions,
136 ) -> Box<bindings::RGBLedMatrix> {
137 unsafe {
138 Box::from_raw(bindings::led_matrix_create_from_options_and_rt_options(
139 &mut self,
140 &mut rt_options,
141 ))
142 }
143 }
144}
145
146impl Default for bindings::RGBLedRuntimeOptions {
147 fn default() -> Self {
148 Self {
149 gpio_slowdown: 1,
150 daemon: 0,
151 drop_privileges: 0,
152 do_gpio_init: true,
153 }
154 }
155}
156
157impl bindings::RGBLedRuntimeOptions {
158 pub fn new() -> Self {
159 Self::default()
160 }
161 pub fn gpio_slowdown(mut self, slowdown: u32) -> Self {
162 self.gpio_slowdown = slowdown as i32;
163 self
164 }
165
166 pub fn daemon(mut self, run_as_daemon: bool) -> Self {
167 self.daemon = run_as_daemon as i32;
168 self
169 }
170
171 pub fn drop_priviliges(mut self, do_drop_privileges: bool) -> Self {
172 self.drop_privileges = do_drop_privileges as i32;
173 self
174 }
175
176 pub fn do_gpio_init(mut self, do_gpio_init: bool) -> Self {
177 self.do_gpio_init = do_gpio_init;
178 self
179 }
180}
181
182impl bindings::RGBLedMatrix {
183 pub fn create_offscreen_canvas(&self) -> Box<bindings::LedCanvas> {
184 unsafe {
185 Box::from_raw(bindings::led_matrix_create_offscreen_canvas(
186 self as *const Self as *mut bindings::RGBLedMatrix,
187 ))
188 }
189 }
190
191 pub fn swap_on_vsync(&mut self, canvas: &mut bindings::LedCanvas) -> Box<bindings::LedCanvas> {
192 unsafe {
193 Box::from_raw(bindings::led_matrix_swap_on_vsync(
194 self as *mut Self,
195 canvas as *mut bindings::LedCanvas,
196 ))
197 }
198 }
199}
200
201impl bindings::LedCanvas {
202 pub fn clear(&mut self) {
203 unsafe {
204 bindings::led_canvas_clear(self);
205 }
206 }
207
208 pub fn set_pixel(&mut self, x: i32, y: i32, r: u8, g: u8, b: u8) {
209 unsafe {
210 bindings::led_canvas_set_pixel(self, x, y, r, g, b);
211 }
212 }
213
214 pub fn get_size(&self) -> (i32, i32) {
215 let mut width = 0;
216 let mut height = 0;
217 unsafe {
218 bindings::led_canvas_get_size(
219 self,
220 &mut width as *mut i32,
221 &mut height as *mut i32,
222 );
223 }
224 (width, height)
225 }
226}
227
228#[test]
229fn test() {
230 let mut matrix = RGBLedMatrixOptions::new().build();
231
232 let mut canvas = matrix.create_offscreen_canvas();
233
234 canvas.clear();
235
236 loop {
237 for i in 0..255 {
238 for y in 0..32 {
239 for x in 0..32 {
240 canvas.set_pixel(x, y, i & 0xFF, x.try_into().unwrap(), y.try_into().unwrap());
241 }
242 }
243 canvas = matrix.swap_on_vsync(&mut canvas);
244 }
245 }
246}