diff --git a/Cargo.lock b/Cargo.lock index 05b3be2..20372bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,6 +242,7 @@ dependencies = [ "log", "log4rs", "num_enum", + "paste", "ptp_cursor", "ptp_macro", "rusb", @@ -502,6 +503,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pkg-config" version = "0.3.32" diff --git a/Cargo.toml b/Cargo.toml index 772e201..882d27b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,4 @@ ptp_macro = { path = "crates/ptp/macro" } ptp_cursor = { path = "crates/ptp/cursor" } strum = { version = "0.27.2", features = ["strum_macros"] } strum_macros = "0.27.2" +paste = "1.0.15" diff --git a/crates/ptp/cursor/src/lib.rs b/crates/ptp/cursor/src/lib.rs index d91f68e..08ec409 100644 --- a/crates/ptp/cursor/src/lib.rs +++ b/crates/ptp/cursor/src/lib.rs @@ -216,7 +216,7 @@ pub trait PtpDeserialize: Sized { fn try_read_ptp(cur: &mut R) -> io::Result; } -macro_rules! impl_ptp_ser { +macro_rules! ptp_ser { ($ty:ty, $read_fn:ident, $write_fn:ident) => { impl PtpSerialize for $ty { fn try_into_ptp(&self) -> io::Result> { @@ -232,7 +232,7 @@ macro_rules! impl_ptp_ser { }; } -macro_rules! impl_ptp_de { +macro_rules! ptp_de { ($ty:ty, $read_fn:ident, $write_fn:ident) => { impl PtpDeserialize for $ty { fn try_from_ptp(buf: &[u8]) -> io::Result { @@ -249,38 +249,38 @@ macro_rules! impl_ptp_de { }; } -impl_ptp_ser!(u8, read_ptp_u8, write_ptp_u8); -impl_ptp_de!(u8, read_ptp_u8, write_ptp_u8); -impl_ptp_ser!(i8, read_ptp_i8, write_ptp_i8); -impl_ptp_de!(i8, read_ptp_i8, write_ptp_i8); -impl_ptp_ser!(u16, read_ptp_u16, write_ptp_u16); -impl_ptp_de!(u16, read_ptp_u16, write_ptp_u16); -impl_ptp_ser!(i16, read_ptp_i16, write_ptp_i16); -impl_ptp_de!(i16, read_ptp_i16, write_ptp_i16); -impl_ptp_ser!(u32, read_ptp_u32, write_ptp_u32); -impl_ptp_de!(u32, read_ptp_u32, write_ptp_u32); -impl_ptp_ser!(i32, read_ptp_i32, write_ptp_i32); -impl_ptp_de!(i32, read_ptp_i32, write_ptp_i32); -impl_ptp_ser!(u64, read_ptp_u64, write_ptp_u64); -impl_ptp_de!(u64, read_ptp_u64, write_ptp_u64); -impl_ptp_ser!(i64, read_ptp_i64, write_ptp_i64); -impl_ptp_de!(i64, read_ptp_i64, write_ptp_i64); -impl_ptp_ser!(&str, read_ptp_str, write_ptp_str); -impl_ptp_ser!(String, read_ptp_str, write_ptp_str); -impl_ptp_de!(String, read_ptp_str, write_ptp_str); -impl_ptp_ser!(Vec, read_ptp_u8_vec, write_ptp_u8_vec); -impl_ptp_de!(Vec, read_ptp_u8_vec, write_ptp_u8_vec); -impl_ptp_ser!(Vec, read_ptp_i8_vec, write_ptp_i8_vec); -impl_ptp_de!(Vec, read_ptp_i8_vec, write_ptp_i8_vec); -impl_ptp_ser!(Vec, read_ptp_u16_vec, write_ptp_u16_vec); -impl_ptp_de!(Vec, read_ptp_u16_vec, write_ptp_u16_vec); -impl_ptp_ser!(Vec, read_ptp_i16_vec, write_ptp_i16_vec); -impl_ptp_de!(Vec, read_ptp_i16_vec, write_ptp_i16_vec); -impl_ptp_ser!(Vec, read_ptp_u32_vec, write_ptp_u32_vec); -impl_ptp_de!(Vec, read_ptp_u32_vec, write_ptp_u32_vec); -impl_ptp_ser!(Vec, read_ptp_i32_vec, write_ptp_i32_vec); -impl_ptp_de!(Vec, read_ptp_i32_vec, write_ptp_i32_vec); -impl_ptp_ser!(Vec, read_ptp_u64_vec, write_ptp_u64_vec); -impl_ptp_de!(Vec, read_ptp_u64_vec, write_ptp_u64_vec); -impl_ptp_ser!(Vec, read_ptp_i64_vec, write_ptp_i64_vec); -impl_ptp_de!(Vec, read_ptp_i64_vec, write_ptp_i64_vec); +ptp_ser!(u8, read_ptp_u8, write_ptp_u8); +ptp_de!(u8, read_ptp_u8, write_ptp_u8); +ptp_ser!(i8, read_ptp_i8, write_ptp_i8); +ptp_de!(i8, read_ptp_i8, write_ptp_i8); +ptp_ser!(u16, read_ptp_u16, write_ptp_u16); +ptp_de!(u16, read_ptp_u16, write_ptp_u16); +ptp_ser!(i16, read_ptp_i16, write_ptp_i16); +ptp_de!(i16, read_ptp_i16, write_ptp_i16); +ptp_ser!(u32, read_ptp_u32, write_ptp_u32); +ptp_de!(u32, read_ptp_u32, write_ptp_u32); +ptp_ser!(i32, read_ptp_i32, write_ptp_i32); +ptp_de!(i32, read_ptp_i32, write_ptp_i32); +ptp_ser!(u64, read_ptp_u64, write_ptp_u64); +ptp_de!(u64, read_ptp_u64, write_ptp_u64); +ptp_ser!(i64, read_ptp_i64, write_ptp_i64); +ptp_de!(i64, read_ptp_i64, write_ptp_i64); +ptp_ser!(&str, read_ptp_str, write_ptp_str); +ptp_ser!(String, read_ptp_str, write_ptp_str); +ptp_de!(String, read_ptp_str, write_ptp_str); +ptp_ser!(Vec, read_ptp_u8_vec, write_ptp_u8_vec); +ptp_de!(Vec, read_ptp_u8_vec, write_ptp_u8_vec); +ptp_ser!(Vec, read_ptp_i8_vec, write_ptp_i8_vec); +ptp_de!(Vec, read_ptp_i8_vec, write_ptp_i8_vec); +ptp_ser!(Vec, read_ptp_u16_vec, write_ptp_u16_vec); +ptp_de!(Vec, read_ptp_u16_vec, write_ptp_u16_vec); +ptp_ser!(Vec, read_ptp_i16_vec, write_ptp_i16_vec); +ptp_de!(Vec, read_ptp_i16_vec, write_ptp_i16_vec); +ptp_ser!(Vec, read_ptp_u32_vec, write_ptp_u32_vec); +ptp_de!(Vec, read_ptp_u32_vec, write_ptp_u32_vec); +ptp_ser!(Vec, read_ptp_i32_vec, write_ptp_i32_vec); +ptp_de!(Vec, read_ptp_i32_vec, write_ptp_i32_vec); +ptp_ser!(Vec, read_ptp_u64_vec, write_ptp_u64_vec); +ptp_de!(Vec, read_ptp_u64_vec, write_ptp_u64_vec); +ptp_ser!(Vec, read_ptp_i64_vec, write_ptp_i64_vec); +ptp_de!(Vec, read_ptp_i64_vec, write_ptp_i64_vec); diff --git a/src/camera/mod.rs b/src/camera/mod.rs index 12978e6..5672b22 100644 --- a/src/camera/mod.rs +++ b/src/camera/mod.rs @@ -27,8 +27,26 @@ use crate::usb::find_endpoint; const SESSION: u32 = 1; pub struct Camera { - r#impl: Box>, - ptp: Ptp, + pub r#impl: Box>, + pub ptp: Ptp, +} + +macro_rules! camera_custom_settings { + ($( $name:ident : $type:ty => $code:expr ),+ $(,)?) => { + $( + paste::paste! { + #[allow(dead_code)] + pub fn [](&mut self) -> anyhow::Result<$type> { + self.r#impl.[](&mut self.ptp) + } + + #[allow(dead_code)] + pub fn [](&mut self, value: &$type) -> anyhow::Result<()> { + self.r#impl.[](&mut self.ptp, value) + } + } + )+ + }; } impl Camera { @@ -88,183 +106,28 @@ impl Camera { self.r#impl.import_backup(&mut self.ptp, backup) } - pub fn set_active_custom_setting(&mut self, slot: FujiCustomSetting) -> anyhow::Result<()> { - self.r#impl.set_custom_setting_slot(&mut self.ptp, slot) - } - - pub fn get_custom_setting_name(&mut self) -> anyhow::Result { - self.r#impl.get_custom_setting_name(&mut self.ptp) - } - - pub fn set_custom_setting_name(&mut self, value: &str) -> anyhow::Result<()> { - self.r#impl.set_custom_setting_name(&mut self.ptp, value) - } - - pub fn get_image_size(&mut self) -> anyhow::Result { - self.r#impl.get_image_size(&mut self.ptp) - } - - pub fn set_image_size(&mut self, value: FujiImageSize) -> anyhow::Result<()> { - self.r#impl.set_image_size(&mut self.ptp, value) - } - - pub fn get_image_quality(&mut self) -> anyhow::Result { - self.r#impl.get_image_quality(&mut self.ptp) - } - - pub fn set_image_quality(&mut self, value: FujiImageQuality) -> anyhow::Result<()> { - self.r#impl.set_image_quality(&mut self.ptp, value) - } - - pub fn get_dynamic_range(&mut self) -> anyhow::Result { - self.r#impl.get_dynamic_range(&mut self.ptp) - } - - pub fn set_dynamic_range(&mut self, value: FujiDynamicRange) -> anyhow::Result<()> { - self.r#impl.set_dynamic_range(&mut self.ptp, value) - } - - pub fn get_dynamic_range_priority(&mut self) -> anyhow::Result { - self.r#impl.get_dynamic_range_priority(&mut self.ptp) - } - - pub fn set_dynamic_range_priority( - &mut self, - value: FujiDynamicRangePriority, - ) -> anyhow::Result<()> { - self.r#impl.set_dynamic_range_priority(&mut self.ptp, value) - } - - pub fn get_film_simulation(&mut self) -> anyhow::Result { - self.r#impl.get_film_simulation(&mut self.ptp) - } - - pub fn set_film_simulation(&mut self, value: FujiFilmSimulation) -> anyhow::Result<()> { - self.r#impl.set_film_simulation(&mut self.ptp, value) - } - - pub fn get_grain_effect(&mut self) -> anyhow::Result { - self.r#impl.get_grain_effect(&mut self.ptp) - } - - pub fn set_grain_effect(&mut self, value: FujiGrainEffect) -> anyhow::Result<()> { - self.r#impl.set_grain_effect(&mut self.ptp, value) - } - - pub fn get_white_balance(&mut self) -> anyhow::Result { - self.r#impl.get_white_balance(&mut self.ptp) - } - - pub fn set_white_balance(&mut self, value: FujiWhiteBalance) -> anyhow::Result<()> { - self.r#impl.set_white_balance(&mut self.ptp, value) - } - - pub fn get_high_iso_nr(&mut self) -> anyhow::Result { - self.r#impl.get_high_iso_nr(&mut self.ptp) - } - - pub fn set_high_iso_nr(&mut self, value: FujiHighISONR) -> anyhow::Result<()> { - self.r#impl.set_high_iso_nr(&mut self.ptp, value) - } - - pub fn get_highlight_tone(&mut self) -> anyhow::Result { - self.r#impl.get_highlight_tone(&mut self.ptp) - } - - pub fn set_highlight_tone(&mut self, value: FujiHighlightTone) -> anyhow::Result<()> { - self.r#impl.set_highlight_tone(&mut self.ptp, value) - } - - pub fn get_shadow_tone(&mut self) -> anyhow::Result { - self.r#impl.get_shadow_tone(&mut self.ptp) - } - - pub fn set_shadow_tone(&mut self, value: FujiShadowTone) -> anyhow::Result<()> { - self.r#impl.set_shadow_tone(&mut self.ptp, value) - } - - pub fn get_color(&mut self) -> anyhow::Result { - self.r#impl.get_color(&mut self.ptp) - } - - pub fn set_color(&mut self, value: FujiColor) -> anyhow::Result<()> { - self.r#impl.set_color(&mut self.ptp, value) - } - - pub fn get_sharpness(&mut self) -> anyhow::Result { - self.r#impl.get_sharpness(&mut self.ptp) - } - - pub fn set_sharpness(&mut self, value: FujiSharpness) -> anyhow::Result<()> { - self.r#impl.set_sharpness(&mut self.ptp, value) - } - - pub fn get_clarity(&mut self) -> anyhow::Result { - self.r#impl.get_clarity(&mut self.ptp) - } - - pub fn set_clarity(&mut self, value: FujiClarity) -> anyhow::Result<()> { - self.r#impl.set_clarity(&mut self.ptp, value) - } - - pub fn get_white_balance_shift_red(&mut self) -> anyhow::Result { - self.r#impl.get_white_balance_shift_red(&mut self.ptp) - } - - pub fn set_white_balance_shift_red( - &mut self, - value: FujiWhiteBalanceShift, - ) -> anyhow::Result<()> { - self.r#impl - .set_white_balance_shift_red(&mut self.ptp, value) - } - - pub fn get_white_balance_shift_blue(&mut self) -> anyhow::Result { - self.r#impl.get_white_balance_shift_blue(&mut self.ptp) - } - - pub fn set_white_balance_shift_blue( - &mut self, - value: FujiWhiteBalanceShift, - ) -> anyhow::Result<()> { - self.r#impl - .set_white_balance_shift_blue(&mut self.ptp, value) - } - - pub fn get_white_balance_temperature(&mut self) -> anyhow::Result { - self.r#impl.get_white_balance_temperature(&mut self.ptp) - } - - pub fn set_white_balance_temperature( - &mut self, - value: FujiWhiteBalanceTemperature, - ) -> anyhow::Result<()> { - self.r#impl - .set_white_balance_temperature(&mut self.ptp, value) - } - - pub fn get_color_chrome_effect(&mut self) -> anyhow::Result { - self.r#impl.get_color_chrome_effect(&mut self.ptp) - } - - pub fn set_color_chrome_effect(&mut self, value: FujiColorChromeEffect) -> anyhow::Result<()> { - self.r#impl.set_color_chrome_effect(&mut self.ptp, value) - } - - pub fn get_color_chrome_fx_blue(&mut self) -> anyhow::Result { - self.r#impl.get_color_chrome_fx_blue(&mut self.ptp) - } - - pub fn set_color_chrome_fx_blue(&mut self, value: FujiColorChromeFXBlue) -> anyhow::Result<()> { - self.r#impl.set_color_chrome_fx_blue(&mut self.ptp, value) - } - - pub fn get_smooth_skin_effect(&mut self) -> anyhow::Result { - self.r#impl.get_smooth_skin_effect(&mut self.ptp) - } - - pub fn set_smooth_skin_effect(&mut self, value: FujiSmoothSkinEffect) -> anyhow::Result<()> { - self.r#impl.set_smooth_skin_effect(&mut self.ptp, value) + camera_custom_settings! { + active_custom_setting: FujiCustomSetting => DevicePropCode::FujiStillCustomSetting, + custom_setting_name: FujiCustomSettingName => DevicePropCode::FujiStillCustomSettingName, + image_size: FujiImageSize => DevicePropCode::FujiStillCustomSettingImageSize, + image_quality: FujiImageQuality => DevicePropCode::FujiStillCustomSettingImageQuality, + dynamic_range: FujiDynamicRange => DevicePropCode::FujiStillCustomSettingDynamicRange, + dynamic_range_priority: FujiDynamicRangePriority => DevicePropCode::FujiStillCustomSettingDynamicRangePriority, + film_simulation: FujiFilmSimulation => DevicePropCode::FujiStillCustomSettingFilmSimulation, + grain_effect: FujiGrainEffect => DevicePropCode::FujiStillCustomSettingGrainEffect, + white_balance: FujiWhiteBalance => DevicePropCode::FujiStillCustomSettingWhiteBalance, + high_iso_nr: FujiHighISONR => DevicePropCode::FujiStillCustomSettingHighISONR, + highlight_tone: FujiHighlightTone => DevicePropCode::FujiStillCustomSettingHighlightTone, + shadow_tone: FujiShadowTone => DevicePropCode::FujiStillCustomSettingShadowTone, + color: FujiColor => DevicePropCode::FujiStillCustomSettingColor, + sharpness: FujiSharpness => DevicePropCode::FujiStillCustomSettingSharpness, + clarity: FujiClarity => DevicePropCode::FujiStillCustomSettingClarity, + white_balance_shift_red: FujiWhiteBalanceShift => DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed, + white_balance_shift_blue: FujiWhiteBalanceShift => DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue, + white_balance_temperature: FujiWhiteBalanceTemperature => DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature, + color_chrome_effect: FujiColorChromeEffect => DevicePropCode::FujiStillCustomSettingColorChromeEffect, + color_chrome_fx_blue: FujiColorChromeFXBlue => DevicePropCode::FujiStillCustomSettingColorChromeFXBlue, + smooth_skin_effect: FujiSmoothSkinEffect => DevicePropCode::FujiStillCustomSettingSmoothSkinEffect, } } @@ -348,6 +211,28 @@ impl TryFrom<&rusb::Device> for Camera { } } +macro_rules! camera_impl_custom_settings { + ($( $name:ident : $type:ty => $code:expr ),+ $(,)?) => { + $( + paste::paste! { + #[allow(dead_code)] + fn [](&self, ptp: &mut Ptp) -> anyhow::Result<$type> { + let bytes = self.get_prop_value(ptp, $code)?; + let result = <$type>::try_from_ptp(&bytes)?; + Ok(result) + } + + #[allow(dead_code)] + fn [](&self, ptp: &mut Ptp, value: &$type) -> anyhow::Result<()> { + let bytes = value.try_into_ptp()?; + self.set_prop_value(ptp, $code, &bytes)?; + Ok(()) + } + } + )+ + }; +} + pub trait CameraImpl { fn supported_camera(&self) -> &'static SupportedCamera

; @@ -460,363 +345,27 @@ pub trait CameraImpl { Ok(()) } - fn set_custom_setting_slot( - &self, - ptp: &mut Ptp, - slot: FujiCustomSetting, - ) -> anyhow::Result<()> { - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSetting, - &slot.try_into_ptp()?, - )?; - Ok(()) - } - - fn get_custom_setting_name(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingName)?; - let result = FujiCustomSettingName::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_custom_setting_name(&self, ptp: &mut Ptp, value: &str) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingName, &bytes)?; - Ok(()) - } - - fn get_image_size(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingImageSize)?; - let result = FujiImageSize::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_image_size(&self, ptp: &mut Ptp, value: FujiImageSize) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingImageSize, &bytes)?; - Ok(()) - } - - fn get_image_quality(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingImageQuality)?; - let result = FujiImageQuality::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_image_quality(&self, ptp: &mut Ptp, value: FujiImageQuality) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingImageQuality, - &bytes, - )?; - Ok(()) - } - - fn get_dynamic_range(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingDynamicRange)?; - let result = FujiDynamicRange::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_dynamic_range(&self, ptp: &mut Ptp, value: FujiDynamicRange) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingDynamicRange, - &bytes, - )?; - Ok(()) - } - - fn get_dynamic_range_priority( - &self, - ptp: &mut Ptp, - ) -> anyhow::Result { - let bytes = self.get_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingDynamicRangePriority, - )?; - let result = FujiDynamicRangePriority::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_dynamic_range_priority( - &self, - ptp: &mut Ptp, - value: FujiDynamicRangePriority, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingDynamicRangePriority, - &bytes, - )?; - Ok(()) - } - - fn get_film_simulation(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = - self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingFilmSimulation)?; - let result = FujiFilmSimulation::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_film_simulation(&self, ptp: &mut Ptp, value: FujiFilmSimulation) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingFilmSimulation, - &bytes, - )?; - Ok(()) - } - - fn get_grain_effect(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingGrainEffect)?; - let result = FujiGrainEffect::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_grain_effect(&self, ptp: &mut Ptp, value: FujiGrainEffect) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingGrainEffect, - &bytes, - )?; - Ok(()) - } - - fn get_white_balance(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingWhiteBalance)?; - let result = FujiWhiteBalance::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_white_balance(&self, ptp: &mut Ptp, value: FujiWhiteBalance) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalance, - &bytes, - )?; - Ok(()) - } - - fn get_high_iso_nr(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighISONR)?; - let result = FujiHighISONR::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_high_iso_nr(&self, ptp: &mut Ptp, value: FujiHighISONR) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighISONR, &bytes)?; - Ok(()) - } - - fn get_highlight_tone(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = - self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighlightTone)?; - let result = FujiHighlightTone::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_highlight_tone(&self, ptp: &mut Ptp, value: FujiHighlightTone) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingHighlightTone, - &bytes, - )?; - Ok(()) - } - - fn get_shadow_tone(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingShadowTone)?; - let result = FujiShadowTone::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_shadow_tone(&self, ptp: &mut Ptp, value: FujiShadowTone) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingShadowTone, - &bytes, - )?; - Ok(()) - } - - fn get_color(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColor)?; - let result = FujiColor::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_color(&self, ptp: &mut Ptp, value: FujiColor) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColor, &bytes)?; - Ok(()) - } - - fn get_sharpness(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingSharpness)?; - let result = FujiSharpness::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_sharpness(&self, ptp: &mut Ptp, value: FujiSharpness) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingSharpness, &bytes)?; - Ok(()) - } - - fn get_clarity(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingClarity)?; - let result = FujiClarity::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_clarity(&self, ptp: &mut Ptp, value: FujiClarity) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingClarity, &bytes)?; - Ok(()) - } - - fn get_white_balance_shift_red(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed, - )?; - let result = FujiWhiteBalanceShift::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_white_balance_shift_red( - &self, - ptp: &mut Ptp, - value: FujiWhiteBalanceShift, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed, - &bytes, - )?; - Ok(()) - } - - fn get_white_balance_shift_blue(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = self.get_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue, - )?; - let result = FujiWhiteBalanceShift::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_white_balance_shift_blue( - &self, - ptp: &mut Ptp, - value: FujiWhiteBalanceShift, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue, - &bytes, - )?; - Ok(()) - } - - fn get_white_balance_temperature( - &self, - ptp: &mut Ptp, - ) -> anyhow::Result { - let bytes = self.get_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature, - )?; - let result = FujiWhiteBalanceTemperature::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_white_balance_temperature( - &self, - ptp: &mut Ptp, - value: FujiWhiteBalanceTemperature, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature, - &bytes, - )?; - Ok(()) - } - - fn get_color_chrome_effect(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = - self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColorChromeEffect)?; - let result = FujiColorChromeEffect::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_color_chrome_effect( - &self, - ptp: &mut Ptp, - value: FujiColorChromeEffect, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingColorChromeEffect, - &bytes, - )?; - Ok(()) - } - - fn get_color_chrome_fx_blue(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = - self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColorChromeFXBlue)?; - let result = FujiColorChromeFXBlue::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_color_chrome_fx_blue( - &self, - ptp: &mut Ptp, - value: FujiColorChromeFXBlue, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingColorChromeFXBlue, - &bytes, - )?; - Ok(()) - } - - fn get_smooth_skin_effect(&self, ptp: &mut Ptp) -> anyhow::Result { - let bytes = - self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingSmoothSkinEffect)?; - let result = FujiSmoothSkinEffect::try_from_ptp(&bytes)?; - Ok(result) - } - - fn set_smooth_skin_effect( - &self, - ptp: &mut Ptp, - value: FujiSmoothSkinEffect, - ) -> anyhow::Result<()> { - let bytes = value.try_into_ptp()?; - self.set_prop_value( - ptp, - DevicePropCode::FujiStillCustomSettingSmoothSkinEffect, - &bytes, - )?; - Ok(()) + camera_impl_custom_settings! { + active_custom_setting: FujiCustomSetting => DevicePropCode::FujiStillCustomSetting, + custom_setting_name: FujiCustomSettingName => DevicePropCode::FujiStillCustomSettingName, + image_size: FujiImageSize => DevicePropCode::FujiStillCustomSettingImageSize, + image_quality: FujiImageQuality => DevicePropCode::FujiStillCustomSettingImageQuality, + dynamic_range: FujiDynamicRange => DevicePropCode::FujiStillCustomSettingDynamicRange, + dynamic_range_priority: FujiDynamicRangePriority => DevicePropCode::FujiStillCustomSettingDynamicRangePriority, + film_simulation: FujiFilmSimulation => DevicePropCode::FujiStillCustomSettingFilmSimulation, + grain_effect: FujiGrainEffect => DevicePropCode::FujiStillCustomSettingGrainEffect, + white_balance: FujiWhiteBalance => DevicePropCode::FujiStillCustomSettingWhiteBalance, + high_iso_nr: FujiHighISONR => DevicePropCode::FujiStillCustomSettingHighISONR, + highlight_tone: FujiHighlightTone => DevicePropCode::FujiStillCustomSettingHighlightTone, + shadow_tone: FujiShadowTone => DevicePropCode::FujiStillCustomSettingShadowTone, + color: FujiColor => DevicePropCode::FujiStillCustomSettingColor, + sharpness: FujiSharpness => DevicePropCode::FujiStillCustomSettingSharpness, + clarity: FujiClarity => DevicePropCode::FujiStillCustomSettingClarity, + white_balance_shift_red: FujiWhiteBalanceShift => DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed, + white_balance_shift_blue: FujiWhiteBalanceShift => DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue, + white_balance_temperature: FujiWhiteBalanceTemperature => DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature, + color_chrome_effect: FujiColorChromeEffect => DevicePropCode::FujiStillCustomSettingColorChromeEffect, + color_chrome_fx_blue: FujiColorChromeFXBlue => DevicePropCode::FujiStillCustomSettingColorChromeFXBlue, + smooth_skin_effect: FujiSmoothSkinEffect => DevicePropCode::FujiStillCustomSettingSmoothSkinEffect, } } diff --git a/src/camera/ptp/hex.rs b/src/camera/ptp/hex.rs index e2bd1e3..3f5c00f 100644 --- a/src/camera/ptp/hex.rs +++ b/src/camera/ptp/hex.rs @@ -1095,7 +1095,7 @@ impl FromStr for FujiHighISONR { } } -macro_rules! define_fuji_i16 { +macro_rules! fuji_i16 { ($name:ident, $min:expr, $max:expr, $step:expr, $scale:literal) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, PtpSerialize, PtpDeserialize)] pub struct $name(i16); @@ -1192,13 +1192,13 @@ macro_rules! define_fuji_i16 { }; } -define_fuji_i16!(FujiWhiteBalanceShift, -9.0, 9.0, 1.0, 1i16); -define_fuji_i16!(FujiWhiteBalanceTemperature, 2500.0, 10000.0, 10.0, 1i16); -define_fuji_i16!(FujiHighlightTone, -2.0, 4.0, 0.5, 10i16); -define_fuji_i16!(FujiShadowTone, -2.0, 4.0, 0.5, 10i16); -define_fuji_i16!(FujiColor, -4.0, 4.0, 1.0, 10i16); -define_fuji_i16!(FujiSharpness, -4.0, 4.0, 1.0, 10i16); -define_fuji_i16!(FujiClarity, -5.0, 5.0, 1.0, 10i16); +fuji_i16!(FujiWhiteBalanceShift, -9.0, 9.0, 1.0, 1i16); +fuji_i16!(FujiWhiteBalanceTemperature, 2500.0, 10000.0, 10.0, 1i16); +fuji_i16!(FujiHighlightTone, -2.0, 4.0, 0.5, 10i16); +fuji_i16!(FujiShadowTone, -2.0, 4.0, 0.5, 10i16); +fuji_i16!(FujiColor, -4.0, 4.0, 1.0, 10i16); +fuji_i16!(FujiSharpness, -4.0, 4.0, 1.0, 10i16); +fuji_i16!(FujiClarity, -5.0, 5.0, 1.0, 10i16); #[repr(u16)] #[derive( diff --git a/src/cli/simulation/mod.rs b/src/cli/simulation/mod.rs index 32a337b..096934a 100644 --- a/src/cli/simulation/mod.rs +++ b/src/cli/simulation/mod.rs @@ -81,7 +81,7 @@ fn handle_list(json: bool, device_id: Option<&str>) -> anyhow::Result<()> { let mut slots = Vec::new(); for slot in FujiCustomSetting::iter() { - camera.set_active_custom_setting(slot)?; + camera.set_active_custom_setting(&slot)?; let name = camera.get_custom_setting_name()?; slots.push(CustomSettingRepr { slot, name }); } @@ -157,7 +157,7 @@ impl fmt::Display for FilmSimulationRepr { fn handle_get(json: bool, device_id: Option<&str>, slot: FujiCustomSetting) -> anyhow::Result<()> { let mut camera = usb::get_camera(device_id)?; - camera.set_active_custom_setting(slot)?; + camera.set_active_custom_setting(&slot)?; let repr = FilmSimulationRepr { name: camera.get_custom_setting_name()?, @@ -191,14 +191,15 @@ fn handle_get(json: bool, device_id: Option<&str>, slot: FujiCustomSetting) -> a Ok(()) } +#[allow(clippy::cognitive_complexity)] fn handle_set( device_id: Option<&str>, slot: FujiCustomSetting, - name: Option, - options: FilmSimulationOptions, + name: Option<&FujiCustomSettingName>, + options: &FilmSimulationOptions, ) -> anyhow::Result<()> { let mut camera = usb::get_camera(device_id)?; - camera.set_active_custom_setting(slot)?; + camera.set_active_custom_setting(&slot)?; // General if let Some(name) = &name { @@ -206,53 +207,53 @@ fn handle_set( } if let Some(size) = &options.size { - camera.set_image_size(*size)?; + camera.set_image_size(size)?; } if let Some(quality) = &options.quality { - camera.set_image_quality(*quality)?; + camera.set_image_quality(quality)?; } // Style if let Some(simulation) = &options.simulation { - camera.set_film_simulation(*simulation)?; + camera.set_film_simulation(simulation)?; } if let Some(color) = &options.color { - camera.set_color(*color)?; + camera.set_color(color)?; } if let Some(sharpness) = &options.sharpness { - camera.set_sharpness(*sharpness)?; + camera.set_sharpness(sharpness)?; } if let Some(clarity) = &options.clarity { - camera.set_clarity(*clarity)?; + camera.set_clarity(clarity)?; } if let Some(noise_reduction) = &options.noise_reduction { - camera.set_high_iso_nr(*noise_reduction)?; + camera.set_high_iso_nr(noise_reduction)?; } if let Some(grain) = &options.grain { - camera.set_grain_effect(*grain)?; + camera.set_grain_effect(grain)?; } if let Some(color_chrome_effect) = &options.color_chrome_effect { - camera.set_color_chrome_effect(*color_chrome_effect)?; + camera.set_color_chrome_effect(color_chrome_effect)?; } if let Some(color_chrome_fx_blue) = &options.color_chrome_fx_blue { - camera.set_color_chrome_fx_blue(*color_chrome_fx_blue)?; + camera.set_color_chrome_fx_blue(color_chrome_fx_blue)?; } if let Some(smooth_skin_effect) = &options.smooth_skin_effect { - camera.set_smooth_skin_effect(*smooth_skin_effect)?; + camera.set_smooth_skin_effect(smooth_skin_effect)?; } // White Balance if let Some(white_balance) = &options.white_balance { - camera.set_white_balance(*white_balance)?; + camera.set_white_balance(white_balance)?; } if let Some(temperature) = &options.white_balance_temperature { @@ -262,24 +263,24 @@ fn handle_set( &camera.get_white_balance()? }; - if *white_balance != FujiWhiteBalance::Temperature { - warn!("White Balance mode is not set to 'Temperature', refusing to set temperature") + if *white_balance == FujiWhiteBalance::Temperature { + camera.set_white_balance_temperature(temperature)?; } else { - camera.set_white_balance_temperature(*temperature)?; + warn!("White Balance mode is not set to 'Temperature', refusing to set temperature"); } } if let Some(shift_red) = &options.white_balance_shift_red { - camera.set_white_balance_shift_red(*shift_red)?; + camera.set_white_balance_shift_red(shift_red)?; } if let Some(shift_blue) = &options.white_balance_shift_blue { - camera.set_white_balance_shift_blue(*shift_blue)?; + camera.set_white_balance_shift_blue(shift_blue)?; } // Exposure if let Some(dynamic_range_priority) = &options.dynamic_range_priority { - camera.set_dynamic_range_priority(*dynamic_range_priority)?; + camera.set_dynamic_range_priority(dynamic_range_priority)?; } if options.dynamic_range.is_some() || options.highlight.is_some() || options.shadow.is_some() { @@ -291,26 +292,26 @@ fn handle_set( }; if let Some(dynamic_range) = &options.dynamic_range { - if *dynamic_range_priority != FujiDynamicRangePriority::Off { - warn!("Dynamic Range Priority is enabled, refusing to set dynamic range") + if *dynamic_range_priority == FujiDynamicRangePriority::Off { + camera.set_dynamic_range(dynamic_range)?; } else { - camera.set_dynamic_range(*dynamic_range)?; + warn!("Dynamic Range Priority is enabled, refusing to set dynamic range"); } } if let Some(highlights) = &options.highlight { - if *dynamic_range_priority != FujiDynamicRangePriority::Off { - warn!("Dynamic Range Priority is enabled, refusing to set highlight tone") + if *dynamic_range_priority == FujiDynamicRangePriority::Off { + camera.set_highlight_tone(highlights)?; } else { - camera.set_highlight_tone(*highlights)?; + warn!("Dynamic Range Priority is enabled, refusing to set highlight tone"); } } if let Some(shadows) = &options.shadow { - if *dynamic_range_priority != FujiDynamicRangePriority::Off { - warn!("Dynamic Range Priority is enabled, refusing to set shadow tone") + if *dynamic_range_priority == FujiDynamicRangePriority::Off { + camera.set_shadow_tone(shadows)?; } else { - camera.set_shadow_tone(*shadows)?; + warn!("Dynamic Range Priority is enabled, refusing to set shadow tone"); } } } @@ -342,7 +343,7 @@ pub fn handle(cmd: SimulationCmd, json: bool, device_id: Option<&str>) -> anyhow slot, name, film_simulation_options, - } => handle_set(device_id, slot, name, film_simulation_options), + } => handle_set(device_id, slot, name.as_ref(), &film_simulation_options), SimulationCmd::Export { slot, output_file } => handle_export(device_id, slot, &output_file), SimulationCmd::Import { slot, input_file } => handle_import(device_id, slot, &input_file), }