kernel/
commandline.rs

1use std::collections::HashMap ;
2use std::str::SplitAsciiWhitespace;
3use Common::fixture;
4use Common::fixture::{Fixture, FixtureType};
5use Common::fixture::ChannelError::{ChannelOutOfRange, ChannelAlreadyInUse, UniverseOutOfRange};
6use Common::fixture::FixtureError::{InvalidPropertyType, MultipleColorOutputTypes, MissingProperty, FixtureTypeNameAlreadyInUse, ChannelError, InvalidFixtureType, FixtureNameAlreadyInUse, InvalidFixture};
7
8
9/// Checks if the given string is a valid command and executes it.
10/// See '../help.txt` for a list of available commands.
11pub(crate) fn parse_command(line: String) {
12
13    let mut line_iter = line.split_ascii_whitespace();
14    //We want to check the arg count, we don't want the command counted
15    let arg_count = line_iter.clone().count().saturating_sub(1);
16    match line_iter.next() {
17
18        Some("help") => {
19            const HELP_TEXT: &str = include_str!("../help.txt");
20            println!("{}", HELP_TEXT);
21        }
22
23        Some("new") if arg_count % 2 == 1 && arg_count > 1 => {
24            new_fixture_type(line_iter);
25        }
26
27        Some("new") => {
28            println!("Error: \"new\"-Command needs a name for the new Fixture-Type, and then a list of properties with \
29            their channels.");
30        }
31
32        Some("add") if arg_count == 4 => {
33            new_fixture(line_iter);
34        }
35
36        Some("add") => {
37            println!("Error: \"add\" needs a name, a fixture-type, a start-channel and a universe as arguments")
38        }
39
40        Some("set") if arg_count == 3 => {
41            set_value(line_iter);
42        }
43
44        Some("set") => {
45            println!("Error: \"set\" needs a fixture, a property, and a value as arguments")
46        }
47
48        Some("type") if arg_count == 1 => {
49            get_type(line_iter);
50        }
51
52        Some("type") => {
53            print!("Error: \"type\" needs a fixture as argument");
54        }
55
56        Some("create_debug") => {
57            let args = "rgb red 0 green 1 blue 2".split_ascii_whitespace();
58            new_fixture_type(args);
59            for i in 0..50 {
60                let name = i.to_string();
61                let start_channel = (i * 3).to_string();
62                let args = format!("{} rgb 0 {}", name.clone(), start_channel.clone());
63                let args = args.split_ascii_whitespace();
64                new_fixture(args);
65            }
66        }
67
68        Some("set_all") if arg_count == 2 => {
69            let property_type = line_iter.next().unwrap().to_string();
70            let value = line_iter.next().unwrap().to_string();
71
72            for i in 0..50 {
73                let name = i.to_string();
74                let args = format!("{} {} {}", name, property_type.clone(), value.clone());
75                let args = args.split_ascii_whitespace();
76                set_value(args);
77
78            }
79        }
80
81        Some("break") => {
82            let _dmx_config = fixture::DMX_CONFIGURATION.read().unwrap();
83            let _universes = fixture::calculate_dmx_values();
84            println!("Add a breakpoint at this point in the code to check the datastructures");
85        }
86
87        _ => {
88            println!("Unknown command. Please enter help, to get a list of commands.");
89        }
90    }
91}
92
93fn new_fixture_type(mut args: SplitAsciiWhitespace) {
94    let name = args.next().unwrap().to_string();
95    let mut properties: HashMap<String, (u16, Option<u16>)> = HashMap::new();
96
97    //*******************************************
98    //***Parsing the input to the right Format***
99    //*******************************************
100    while let Some(property) = args.next() {
101
102        //We can do that without throwing an Error, because args has an even number of elements at this point
103        let channel = args.next().unwrap();
104        if let Err(_) = channel.parse::<u16>() {
105            eprintln!("Error: \"{channel}\" is not a valid channel-number");
106            return;
107        } else {
108            let channel = channel.parse::<u16>().unwrap();
109
110            if property.ends_with("_f") {
111                //fine-channels
112
113                // Cut off the _f
114                let property =  &property[..(property.len() - 2)];
115                if let Some((_, opt)) = properties.get_mut(property) {
116                    if opt.is_none() {
117                        *opt = Some(channel);
118                    } else {
119                        eprintln!("{property} can only have one Fine-Channel");
120                        return;
121                    }
122                } else {
123                    eprintln!("{property} needs to define a normal Channel, before defining an fine-Channel");
124                    return;
125                }
126            } else {
127                //Non-fine channels
128
129                if !properties.contains_key(property) {
130                    properties.insert(property.to_string(), (channel, None));
131                } else {
132                    eprintln!("{property} can only have one non-fine Channel");
133                    return;
134                }
135            }
136        }
137
138    }
139
140    //***********************************************************
141    //**Creating the fixture_type and handling possible Errors***
142    //***********************************************************
143    let fixture_type = FixtureType::new(name.clone(), properties);
144    match fixture_type {
145        Err(ChannelError(ChannelAlreadyInUse(channel_type))) => {
146            eprintln!("Error: The channel {channel_type} overlaps with another channel.");
147        },
148
149        Err(ChannelError(ChannelOutOfRange)) => {
150            eprintln!("Error: A Channel is higher than the size of the Universe. This is not yet supported");
151        }
152
153        Err(FixtureTypeNameAlreadyInUse(name)) => {
154            eprintln!("Error: The Fixture type name {name} is already used.");
155        }
156
157        Err(InvalidPropertyType(property_type)) => {
158            eprintln!("Error: \"{property_type}\" is not a valid PropertyType");
159        }
160
161        Err(MultipleColorOutputTypes(error_message)) => {
162            eprintln!("{error_message}");
163        }
164
165        Err(_) => {
166            eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
167            None::<Fixture>.unwrap();
168            // Mir ist langweilig, deswegen crashe ich hier, auf die lustigste und verwirrendste Art. Hier muss auch
169            // gecrashed werden, weil das nie passieren sollte
170        }
171
172        Ok(()) => { println!("{} created successfully", name); }
173    }
174}
175
176fn new_fixture(mut args: SplitAsciiWhitespace) {
177    let name = args.next().unwrap().to_string();
178    let fixture_type_name = args.next().unwrap().to_string();
179    let universe = args.next().unwrap().to_string();
180    let channel = args.next().unwrap().to_string();
181
182    //*******************************************
183    //***Parsing the input to the right Format***
184    //*******************************************
185    if let Err(_) = channel.parse::<u16>() {
186        eprintln!("Error: \"{fixture_type_name}\" is not a valid channel-number");
187        return;
188    }
189    let channel = channel.parse::<u16>().unwrap();
190
191    if let Err(_) = universe.parse::<usize>() {
192        eprintln!("Error: \"{fixture_type_name}\" is not a valid universe-number");
193        return;
194    }
195    let universe = universe.parse().unwrap();
196
197    //******************************************************
198    //**Creating the fixture and handling possible Errors***
199    //******************************************************
200    let fixture = Fixture::new(fixture_type_name,channel,universe, name.clone());
201    match fixture {
202        Err(ChannelError(ChannelOutOfRange)) => {
203            eprintln!("Error: fixture overflowes out of this remaining universe");
204        }
205
206        Err(ChannelError(UniverseOutOfRange)) => {
207            panic!("Fatal Error: Fixture created in Universe that does not exist. Normally, the programm should \
208        automatically create an universe, but somehow, this hasn't happened");
209        }
210
211        Err(ChannelError(ChannelAlreadyInUse(overlapping_fixture))) => {
212            eprintln!("Error: At least one Channel of this fixture is overlapping with {}.\
213            Fixture has not been created.", overlapping_fixture);
214        }
215
216        Err(InvalidFixtureType(fixture_type_name)) => {
217            eprintln!("Error: There is no fixture-type named \"{fixture_type_name}\".");
218        }
219
220        Err(FixtureNameAlreadyInUse(name)) => {
221            eprintln!("Error: The Fixture name {name} is already used.");
222        }
223
224        Err(_) => {
225            eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
226            None::<Fixture>.unwrap();
227            // Mir ist langweilig, deswegen crashe ich hier, auf die lustigste und verwirrendste Art. Hier muss auch
228            // gecrashed werden, weil das nie passieren sollte, und ich hab all das einfach von new_fixture_type kopiert
229        }
230
231        Ok(_) => { println!("{} created successfully", name); }
232    }
233}
234
235fn set_value(mut args: SplitAsciiWhitespace) {
236    let fixture_name = args.next().unwrap().to_string();
237    let property_name = args.next().unwrap().to_string();
238    let value = args.next().unwrap().to_string();
239
240    //*******************************************
241    //***Parsing the input to the right Format***
242    //*******************************************
243    if let Err(_) = value.parse::<u16>() {
244        eprintln!("Error: \"{value}\" is not a valid value.");
245        return;
246    }
247    let value = value.parse::<u16>().unwrap();
248
249    //****************************************************
250    //**Changing the value and handling possible Errors***
251    //****************************************************
252    let result = Fixture::set(fixture_name.clone(), &*property_name, value);
253    match result {
254        Err(InvalidPropertyType(property_type)) => {
255            eprintln!("Error: \"{property_type}\" is not a valid PropertyType");
256        }
257
258        Err(MissingProperty(_)) => {
259            eprintln!("Error: \"{fixture_name}\" has no property \"{property_name}\"")
260        }
261
262        Err(InvalidFixture(name)) => {
263            eprintln!("Error: \"{name}\" is not a valid Fixture");
264        }
265
266        Err(_) => {
267            eprintln!("Error: new_fixture_type() threw an Error it shouldn't");
268            None::<Fixture>.unwrap();
269            // Mir ist langweilig, deswegen crashe ich hier, auf die lustigste und verwirrendste Art. Hier muss auch
270            // gecrashed werden, weil das nie passieren sollte, und ich hab all das einfach schon wieder von
271            // new_fixture_type kopiert
272        }
273
274        Ok(_) => { println!("Value changed successfully"); }
275    }
276}
277
278
279fn get_type(mut args: SplitAsciiWhitespace) {
280    let fixture_name = args.next().unwrap().to_string();
281
282    match Fixture::get_fixture_type_from_string(fixture_name.clone()) {
283        Ok(fixture_type) => println!("\"{fixture_name}\" is a fixture of the type \"{fixture_type}\""),
284        Err(InvalidFixture(fixture)) => eprintln!("Error: \"{fixture}\" is not a valid Fixture"),
285        Err(_) => panic!("Error: get_fixture_type_from_string() threw an Error it shouldn't"),
286    }
287}
288