Added preset file saving and tests
This commit is contained in:
6 files changed
+394
No files matched your search
@@ -2,6 +2,7 @@ mod color;
|
||||
mod hid_wrapper;
|
||||
mod keymap;
|
||||
mod rgb_controller;
|
||||
mod tests;
|
||||
|
||||
pub use color::Color;
|
||||
pub use hid_wrapper::HidWrapperError;
|
||||
@@ -13,5 +14,10 @@ pub use rgb_controller::effect_info::{
|
||||
pub use rgb_controller::effects::Effects;
|
||||
pub use rgb_controller::preset::Preset;
|
||||
|
||||
#[cfg(feature = "preset_file_saving")]
|
||||
mod save_preset;
|
||||
#[cfg(feature = "preset_file_saving")]
|
||||
pub use save_preset::{LoadPresetError, SavePresetError};
|
||||
|
||||
#[cfg(feature = "access_hid_wrapper")]
|
||||
pub use hid_wrapper::HidWrapper;
|
||||
@@ -32,6 +32,10 @@ impl Preset {
|
||||
keymap,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.brightness <= 16 && self.direction <= 3 && 1 <= self.speed && self.speed <= 16
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Preset {
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
use crate::{
|
||||
DirectionPolicy, EFFECTS, EffectInfo, Effects, Preset,
|
||||
save_preset::{LoadPresetError::InvalidOrCorruptedFile, SavePresetError::InvalidPreset},
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
vec,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SavePresetError {
|
||||
InvalidPreset,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoadPresetError {
|
||||
InvalidOrCorruptedFile,
|
||||
OpenFileError(std::io::Error),
|
||||
}
|
||||
|
||||
const MAGIC_NUMBER_1: u8 = 0b10100100;
|
||||
const MAGIC_NUMBER_2: u8 = 0b00010000;
|
||||
const VERSION: u8 = 1;
|
||||
|
||||
impl Preset {
|
||||
pub fn save_to_file(&self, _file: &mut File) -> Result<(), SavePresetError> {
|
||||
if !self.is_valid() {
|
||||
return Err(SavePresetError::InvalidPreset);
|
||||
}
|
||||
_file.write_all(&self._encode_to_buffer()).expect("");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn _encode_to_buffer(&self) -> Vec<u8> {
|
||||
let effect_info: EffectInfo = EFFECTS[usize::from(self.effect.to_u8() - 1)].clone();
|
||||
let mut buffer: Vec<u8> = vec![MAGIC_NUMBER_1, MAGIC_NUMBER_2, VERSION];
|
||||
|
||||
buffer
|
||||
.push(self.effect.to_u8() + (u8::from(self.full_color) * 128) + (self.direction * 32)); //Effect id, full_color, and direction in a single byte
|
||||
|
||||
if !self.full_color && effect_info.can_set_color {
|
||||
buffer.extend(&self.color.to_array());
|
||||
}
|
||||
|
||||
if effect_info.can_set_speed {
|
||||
buffer.push(self.speed);
|
||||
}
|
||||
|
||||
buffer.push(self.brightness);
|
||||
|
||||
if effect_info.requires_keymap {
|
||||
for key_color in self.keymap.expect("keymap is Option::None").iter() {
|
||||
buffer.extend(key_color);
|
||||
}
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
pub fn load_from_file(_file: &mut File) -> Result<Self, LoadPresetError> {
|
||||
let mut buffer: Vec<u8> = vec![];
|
||||
match _file.read_to_end(&mut buffer) {
|
||||
Ok(_) => {
|
||||
let mut buffer: VecDeque<u8> = buffer.into();
|
||||
|
||||
Self::_decode_from_buffer(&mut buffer)
|
||||
}
|
||||
Err(err) => return Err(LoadPresetError::OpenFileError(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn _decode_from_buffer(buffer: &mut VecDeque<u8>) -> Result<Self, LoadPresetError> {
|
||||
let mut save: Preset = Default::default();
|
||||
|
||||
if buffer.pop_front() != Some(MAGIC_NUMBER_1) || buffer.pop_front() != Some(MAGIC_NUMBER_2)
|
||||
{
|
||||
return Err(LoadPresetError::InvalidOrCorruptedFile);
|
||||
}
|
||||
|
||||
if buffer.pop_front().expect("") != VERSION {
|
||||
return Err(LoadPresetError::InvalidOrCorruptedFile);
|
||||
//todo!("TOO BAD, Invalid VERSION")
|
||||
}
|
||||
|
||||
if buffer[0] & 128 != 0 {
|
||||
buffer[0] -= 128;
|
||||
save.full_color = true;
|
||||
}
|
||||
|
||||
let direction: u8 = (buffer[0] >> 5) & 0b11;
|
||||
buffer[0] -= direction * 32;
|
||||
|
||||
save.effect = Effects::from_u8(
|
||||
buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?,
|
||||
)
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
let effect_info: EffectInfo = EFFECTS[usize::from(save.effect.to_u8() - 1)].clone();
|
||||
|
||||
if !save.full_color && effect_info.can_set_color {
|
||||
save.color.red = buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
save.color.green = buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
save.color.blue = buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
}
|
||||
|
||||
if effect_info.can_set_direction != DirectionPolicy::None {
|
||||
save.direction = direction;
|
||||
}
|
||||
|
||||
if effect_info.can_set_speed {
|
||||
save.speed = buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
}
|
||||
|
||||
save.brightness = buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?;
|
||||
|
||||
if effect_info.requires_keymap {
|
||||
let mut keymap_buffer: [[u8; 3]; 144] = [[0; 3]; 144];
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..keymap_buffer.len() {
|
||||
keymap_buffer[i] = [
|
||||
buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?,
|
||||
buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?,
|
||||
buffer
|
||||
.pop_front()
|
||||
.ok_or(LoadPresetError::InvalidOrCorruptedFile)?,
|
||||
];
|
||||
}
|
||||
save.keymap = Some(keymap_buffer);
|
||||
}
|
||||
Ok(save)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "preset_file_saving")]
|
||||
mod preset_saving;
|
||||
@@ -0,0 +1,232 @@
|
||||
mod tests {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::Keymap;
|
||||
#[allow(unused_imports)]
|
||||
use crate::Preset;
|
||||
|
||||
#[test]
|
||||
fn test_encode_decode() {
|
||||
let preset = Preset::new(
|
||||
crate::Effects::Static,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
true,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
);
|
||||
let mut buffer: VecDeque<u8> = preset._encode_to_buffer().into();
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::_decode_from_buffer(&mut buffer).expect("error decoding")
|
||||
);
|
||||
|
||||
let preset = Preset::new(
|
||||
crate::Effects::VerticalWave,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
true,
|
||||
2,
|
||||
9,
|
||||
2,
|
||||
None,
|
||||
);
|
||||
let mut buffer: VecDeque<u8> = preset._encode_to_buffer().into();
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::_decode_from_buffer(&mut buffer).expect("error decoding")
|
||||
);
|
||||
|
||||
let preset = Preset::new(
|
||||
crate::Effects::HorizontalWave,
|
||||
crate::Color {
|
||||
red: 67,
|
||||
green: 69,
|
||||
blue: 255,
|
||||
},
|
||||
false,
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
None,
|
||||
);
|
||||
let mut buffer: VecDeque<u8> = preset._encode_to_buffer().into();
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::_decode_from_buffer(&mut buffer).expect("error decoding")
|
||||
);
|
||||
|
||||
let mut keymap: Keymap = Default::default();
|
||||
keymap.set_all_keys(crate::Color {
|
||||
red: 255,
|
||||
green: 9,
|
||||
blue: 7,
|
||||
});
|
||||
keymap.set_key(
|
||||
crate::KeymapKeys::C,
|
||||
crate::Color {
|
||||
red: 111,
|
||||
green: 222,
|
||||
blue: 133,
|
||||
},
|
||||
);
|
||||
keymap.set_key(
|
||||
crate::KeymapKeys::NumPlus,
|
||||
crate::Color {
|
||||
red: 112,
|
||||
green: 223,
|
||||
blue: 134,
|
||||
},
|
||||
);
|
||||
let preset = Preset::new(
|
||||
crate::Effects::StaticPerKey,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
false,
|
||||
16,
|
||||
1,
|
||||
0,
|
||||
Some(keymap.map()),
|
||||
);
|
||||
let mut buffer: VecDeque<u8> = preset._encode_to_buffer().into();
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::_decode_from_buffer(&mut buffer).expect("error decoding")
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_save_load() {
|
||||
use std::fs::File;
|
||||
|
||||
let preset = Preset::new(
|
||||
crate::Effects::Static,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
true,
|
||||
6,
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
);
|
||||
preset
|
||||
.save_to_file(&mut File::create("/tmp/test_file.gk1k").expect("Failed to create file"))
|
||||
.expect("failed to save");
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::load_from_file(
|
||||
&mut File::open("/tmp/test_file.gk1k").expect("failed to open file")
|
||||
)
|
||||
.expect("error loading from file")
|
||||
);
|
||||
|
||||
let preset = Preset::new(
|
||||
crate::Effects::VerticalWave,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
true,
|
||||
2,
|
||||
9,
|
||||
2,
|
||||
None,
|
||||
);
|
||||
preset
|
||||
.save_to_file(&mut File::create("/tmp/test_file.gk1k").expect("Failed to create file"))
|
||||
.expect("failed to save");
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::load_from_file(
|
||||
&mut File::open("/tmp/test_file.gk1k").expect("failed to open file")
|
||||
)
|
||||
.expect("error loading from file")
|
||||
);
|
||||
|
||||
let preset = Preset::new(
|
||||
crate::Effects::HorizontalWave,
|
||||
crate::Color {
|
||||
red: 67,
|
||||
green: 69,
|
||||
blue: 255,
|
||||
},
|
||||
false,
|
||||
2,
|
||||
9,
|
||||
1,
|
||||
None,
|
||||
);
|
||||
preset
|
||||
.save_to_file(&mut File::create("/tmp/test_file.gk1k").expect("Failed to create file"))
|
||||
.expect("failed to save");
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::load_from_file(
|
||||
&mut File::open("/tmp/test_file.gk1k").expect("failed to open file")
|
||||
)
|
||||
.expect("error loading from file")
|
||||
);
|
||||
|
||||
let mut keymap: Keymap = Default::default();
|
||||
keymap.set_all_keys(crate::Color {
|
||||
red: 255,
|
||||
green: 9,
|
||||
blue: 7,
|
||||
});
|
||||
keymap.set_key(
|
||||
crate::KeymapKeys::C,
|
||||
crate::Color {
|
||||
red: 111,
|
||||
green: 222,
|
||||
blue: 133,
|
||||
},
|
||||
);
|
||||
keymap.set_key(
|
||||
crate::KeymapKeys::NumPlus,
|
||||
crate::Color {
|
||||
red: 112,
|
||||
green: 223,
|
||||
blue: 134,
|
||||
},
|
||||
);
|
||||
let preset = Preset::new(
|
||||
crate::Effects::StaticPerKey,
|
||||
crate::Color {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0,
|
||||
},
|
||||
false,
|
||||
16,
|
||||
1,
|
||||
0,
|
||||
Some(keymap.map()),
|
||||
);
|
||||
preset
|
||||
.save_to_file(&mut File::create("/tmp/test_file.gk1k").expect("Failed to create file"))
|
||||
.expect("failed to save");
|
||||
assert_eq!(
|
||||
preset,
|
||||
Preset::load_from_file(
|
||||
&mut File::open("/tmp/test_file.gk1k").expect("failed to open file")
|
||||
)
|
||||
.expect("error loading from file")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user