1use crate::options::{LedMatrixOptions, LedRuntimeOptions};
4use clap::{arg, App};
5
6#[must_use]
9#[allow(clippy::cognitive_complexity)]
10pub fn add_matrix_args(app: App<'static>) -> App<'static> {
11 app
12 .arg(
13 arg!(
14 --"gpio-mapping" <name> "'Name of GPIO mapping used'")
15 .default_value("Regular").required(false))
16 .arg(
17 arg!(
18 --rows <rows> "Panel rows. Typically 8, 16, 32 or 64")
19 .default_value("32").required(false))
20 .arg(
21 arg!(
22 --cols <cols> "Panel columns. Typically 32 or 64")
23 .default_value("32").required(false))
24 .arg(
25 arg!(
26 --chain <chained> "Number of daisy-chained panels")
27 .default_value("1").required(false))
28 .arg(
29 arg!(
30 --parallel <parallel> "Parallel chains. range=1..3")
31 .default_value("1").required(false))
32 .arg(
33 arg!(
34 --multiplexing <VAL> "[0,16] Mux type: 0=direct, 1=Stripe, 2=Checkered, 3=Spiral, 4=ZStripe, 5=ZnMirrorZStripe, 6=coreman, 7=Kaler2Scan, 8=ZStripeUneven, 9=P10-128x4-Z, 10=QiangLiQ8, 11=InversedZStripe, 12=P10Outdoor1R1G1-1, 13=P10Outdoor1R1G1-2, 14=P10Outdoor1R1G1-3, 15=P10CoremanMapper, 16=P8Outdoor1R1G1")
35 .default_value("0").required(false))
36 .arg(
37 arg!(
38 --"pixel-mapper" <VAL> "Semicolon-separated list of pixel-mappers to arrange pixels. Optional params after a colon e.g. \"U-mapper;Rotate:90\"\"Available: \"Mirror\", \"Rotate\", \"U-mapper\", \"V-mapper\"")
39 .default_value("").required(false))
40 .arg(
41 arg!(
42 --"pwm-bits" <VAL> "[1,11] PWM bits")
43 .default_value("11").required(false))
44 .arg(
45 arg!(
46 --brightness <percent> "Brightness in percent")
47 .default_value("100").required(false))
48 .arg(
49 arg!(
50 --"scan-mode" <VAL> "0 = progressive; 1 = interlaced")
51 .default_value("0").required(false))
52 .arg(
53 arg!(
54 --"row-addr-type" <VAL> "0 = default; 1 = AB-addressed panels; 2 = direct row select; 3 = ABC-addressed panels; 4 = ABC Shift + DE direct")
55 .default_value("0").required(false))
56 .arg(
57 arg!(
58 --"limit-refresh" <Hz> "Limit refresh rate to this frequency in Hz. Useful to keep a constant refresh rate on loaded system. 0=no limit")
59 .default_value("0").required(false))
60 .arg(
61 arg!(
62 --"rgb-sequence" <SEQ> "Switch if your matrix has led colors swapped")
63 .default_value("RGB").required(false))
64 .arg(
65 arg!(
66 --"pwm-lsb-nanoseconds" <ns> "PWM Nanoseconds for LSB")
67 .default_value("130").required(false))
68 .arg(
69 arg!(
70 --"pwm-dither-bits" <VAL> "[0,2] Time dithering of lower bits")
71 .default_value("0").required(false))
72 .arg(
73 arg!(
74 --"panel-type" <name> "Needed to initialize special panels. Supported: 'FM6126A', 'FM6127'")
75 .default_value("").required(false))
76 .arg(
77 arg!(
78 --"slowdown-gpio" <VAL> "[0,4] Slowdown GPIO. Needed for faster Pis/slower panels")
79 .default_value("1").required(false))
80
81 .arg(
83 arg!(
84 --"show-refresh" "Show refresh rate"))
85 .arg(
86 arg!(
87 --inverse "Switch if your matrix has inverse colors on"))
88 .arg(
89 arg!(
90 --"no-hardware-pulse" "Don't use hardware pin-pulse generation"))
91 .arg(
92 arg!(
93 --daemon "Make the process run in the background as daemon"))
94 .arg(
95 arg!(
96 --"no-drop-privs" "Don't drop privileges from 'root' after initializing the hardware"))
97}
98
99#[must_use]
104#[rustfmt::skip]
105pub fn matrix_options_from_args(
106 parsed_args: &clap::ArgMatches,
107) -> (LedMatrixOptions, LedRuntimeOptions) {
108 let mut options = LedMatrixOptions::new();
109 let mut rt_options = LedRuntimeOptions::new();
110
111 let gpio_mapping = parsed_args.value_of("gpio-mapping").expect("Invalid value given for gpio_mapping");
112 let rows: u32 = parsed_args.value_of_t("rows").expect("Invalid value given for rows");
113 let cols: u32 = parsed_args.value_of_t("cols").expect("Invalid value given for cols");
114 let chain: u32 = parsed_args.value_of_t("chain").expect("Invalid value given for chain");
115 let parallel: u32 = parsed_args.value_of_t("parallel").expect("Invalid value given for parallel");
116 let multiplexing: u32 = parsed_args.value_of_t("multiplexing").expect("Invalid value given for multiplexing");
117 let pixel_mapper = parsed_args.value_of("pixel-mapper").expect("Invalid value given for pixel_mapper");
118 let pwm_bits: u8 = parsed_args.value_of_t("pwm-bits").expect("Invalid value given for pwm_bits");
119 let brightness: u8 = parsed_args.value_of_t("brightness").expect("Invalid value given for brightness");
120 let scan_mode: u32 = parsed_args.value_of_t("scan-mode").expect("Invalid value given for scan_mode");
121 let row_addr_type: u32 = parsed_args.value_of_t("row-addr-type").expect("Invalid value given for row_addr_type");
122 let limit_refresh: u32 = parsed_args.value_of_t("limit-refresh").expect("Invalid value given for limit_refresh");
123 let rgb_sequence = parsed_args.value_of("rgb-sequence").expect("Invalid value given for rgb_sequence");
124 let pwm_lsb_nanoseconds: u32 = parsed_args.value_of_t("pwm-lsb-nanoseconds").expect("Invalid value given for pwm_lsb_nanoseconds");
125 let pwm_dither_bits: u32 = parsed_args.value_of_t("pwm-dither-bits").expect("Invalid value given for pwm_dither_bits");
126 let panel_type = parsed_args.value_of("panel-type").expect("Invalid value given for panel_type");
127 let slowdown_gpio: u32 = parsed_args.value_of_t("slowdown-gpio").expect("Invalid value given for slowdown_gpio");
128
129 let show_refresh: bool = parsed_args.is_present("show-refresh");
131 let inverse: bool = parsed_args.is_present("inverse");
132 let no_hardware_pulse: bool = parsed_args.is_present("no-hardware-pulse");
133 let daemon: bool = parsed_args.is_present("daemon");
134 let no_drop_privs: bool = parsed_args.is_present("no-drop-privs");
135
136 options.set_hardware_mapping(gpio_mapping);
137 options.set_rows(rows);
138 options.set_cols(cols);
139 options.set_chain_length(chain);
140 options.set_parallel(parallel);
141 options.set_multiplexing(multiplexing);
142 options.set_pixel_mapper_config(pixel_mapper);
143 options.set_pwm_bits(pwm_bits).unwrap();
144 options.set_brightness(brightness).unwrap();
145 options.set_scan_mode(scan_mode);
146 options.set_row_addr_type(row_addr_type);
147 options.set_limit_refresh(limit_refresh);
148 options.set_led_rgb_sequence(rgb_sequence);
149 options.set_pwm_lsb_nanoseconds(pwm_lsb_nanoseconds);
150 options.set_pwm_dither_bits(pwm_dither_bits);
151 options.set_panel_type(panel_type);
152
153 options.set_hardware_pulsing(!no_hardware_pulse);
154 options.set_refresh_rate(show_refresh);
155 options.set_inverse_colors(inverse);
156
157 rt_options.set_gpio_slowdown(slowdown_gpio);
159 rt_options.set_daemon(daemon);
160 rt_options.set_drop_privileges(!no_drop_privs);
161
162 (options, rt_options)
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use clap::App;
169
170 #[test]
171 #[serial_test::serial]
172 fn matrix_args_add() {
173 let app = add_matrix_args(App::new("test"));
174 let matches = app.get_matches_from(vec!["app"]);
175 let _slowdown: u32 = matches.value_of_t("slowdown-gpio").unwrap();
176 }
177
178 #[test]
179 #[serial_test::serial]
180 fn matrix_args_clap_basic() {
181 let app = add_matrix_args(App::new("test"));
182 let matches = app.get_matches_from(vec!["app", "--limit-refresh", "42"]);
183 let slowdown: u32 = matches.value_of_t("limit-refresh").unwrap();
184 assert_eq!(slowdown, 42);
185 }
186
187 #[test]
188 #[serial_test::serial]
189 fn matrix_args_to_options() {
190 let app = add_matrix_args(App::new("test"));
191 let matches = app.get_matches_from(vec!["app", "--pwm-dither-bits", "42"]);
192 let (options, _rt_options) = matrix_options_from_args(&matches);
193 assert_eq!(options.0.pwm_dither_bits, 42);
194 }
195
196 #[test]
197 #[serial_test::serial]
198 fn matrix_args_to_rt_options() {
199 let app = add_matrix_args(App::new("test"));
200 let matches = app.get_matches_from(vec!["app", "--slowdown-gpio", "4"]);
201 let (_options, rt_options) = matrix_options_from_args(&matches);
202 assert_eq!(rt_options.0.gpio_slowdown, 4);
203 }
204
205 #[test]
206 #[serial_test::serial]
207 fn matrix_args_to_rt_options_flag() {
208 let app = add_matrix_args(App::new("test"));
209 let matches = app.get_matches_from(vec!["app", "--daemon"]);
210 let (_options, rt_options) = matrix_options_from_args(&matches);
211 assert_eq!(rt_options.0.daemon, 1);
212 }
213}