use std::fmt::Debug;
use anyhow::{Result, ensure};
use crate::{
serde::{Deserializer, Serializer, SizedString, SliceDeserializer},
units::{Milimeters, MilimetersPerMinute, Seconds},
};
use crate::goo::{DELIMITER, MAGIC_TAG, PreviewImage};
#[derive(Debug)]
pub struct Header {
pub version: SizedString<4>,
pub software_info: SizedString<32>,
pub software_version: SizedString<24>,
pub file_time: SizedString<24>,
pub printer_name: SizedString<32>,
pub printer_type: SizedString<32>,
pub profile_name: SizedString<32>,
pub anti_aliasing_level: u16,
pub grey_level: u16,
pub blur_level: u16,
pub small_preview: PreviewImage<116, 116>,
pub big_preview: PreviewImage<290, 290>,
pub layer_count: u32,
pub x_resolution: u16,
pub y_resolution: u16,
pub x_mirror: bool,
pub y_mirror: bool,
pub x_size: Milimeters,
pub y_size: Milimeters,
pub z_size: Milimeters,
pub layer_thickness: Milimeters,
pub exposure_time: Seconds,
pub exposure_delay_mode: ExposureDelayMode,
pub turn_off_time: Seconds,
pub bottom_before_lift_time: Seconds,
pub bottom_after_lift_time: Seconds,
pub bottom_after_retract_time: Seconds,
pub before_lift_time: Seconds,
pub after_lift_time: Seconds,
pub after_retract_time: Seconds,
pub bottom_exposure_time: Seconds,
pub bottom_layers: u32,
pub bottom_lift_distance: Milimeters,
pub bottom_lift_speed: MilimetersPerMinute,
pub lift_distance: Milimeters,
pub lift_speed: MilimetersPerMinute,
pub bottom_retract_distance: Milimeters,
pub bottom_retract_speed: MilimetersPerMinute,
pub retract_distance: Milimeters,
pub retract_speed: MilimetersPerMinute,
pub bottom_second_lift_distance: Milimeters,
pub bottom_second_lift_speed: MilimetersPerMinute,
pub second_lift_distance: Milimeters,
pub second_lift_speed: MilimetersPerMinute,
pub bottom_second_retract_distance: Milimeters,
pub bottom_second_retract_speed: MilimetersPerMinute,
pub second_retract_distance: Milimeters,
pub second_retract_speed: MilimetersPerMinute,
pub bottom_light_pwm: u8,
pub light_pwm: u8,
pub per_layer_settings: bool,
pub printing_time: u32,
pub total_volume: f32,
pub total_weight: f32,
pub total_price: f32,
pub price_unit: SizedString<8>,
pub grey_scale_level: bool,
pub transition_layers: u16,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone)]
pub enum ExposureDelayMode {
TurnOffTime,
StaticTime,
}
impl Header {
pub const SIZE: usize = 0x2FB95;
}
impl Header {
pub fn serialize<T: Serializer>(&self, ser: &mut T) {
self.version.serialize(ser);
ser.write_bytes(MAGIC_TAG);
self.software_info.serialize(ser);
self.software_version.serialize(ser);
self.file_time.serialize(ser);
self.printer_name.serialize(ser);
self.printer_type.serialize(ser);
self.profile_name.serialize(ser);
ser.write_u16_be(self.anti_aliasing_level);
ser.write_u16_be(self.grey_level);
ser.write_u16_be(self.blur_level);
self.small_preview.serializes(ser);
ser.write_bytes(DELIMITER);
self.big_preview.serializes(ser);
ser.write_bytes(DELIMITER);
ser.write_u32_be(self.layer_count);
ser.write_u16_be(self.x_resolution);
ser.write_u16_be(self.y_resolution);
ser.write_bool(self.x_mirror);
ser.write_bool(self.y_mirror);
ser.write_f32_be(self.x_size.raw());
ser.write_f32_be(self.y_size.raw());
ser.write_f32_be(self.z_size.raw());
ser.write_f32_be(self.layer_thickness.raw());
ser.write_f32_be(self.exposure_time.raw());
ser.write_u8(self.exposure_delay_mode as u8);
ser.write_f32_be(self.turn_off_time.raw());
ser.write_f32_be(self.bottom_before_lift_time.raw());
ser.write_f32_be(self.bottom_after_lift_time.raw());
ser.write_f32_be(self.bottom_after_retract_time.raw());
ser.write_f32_be(self.before_lift_time.raw());
ser.write_f32_be(self.after_lift_time.raw());
ser.write_f32_be(self.after_retract_time.raw());
ser.write_f32_be(self.bottom_exposure_time.raw());
ser.write_u32_be(self.bottom_layers);
ser.write_f32_be(self.bottom_lift_distance.raw());
ser.write_f32_be(self.bottom_lift_speed.raw());
ser.write_f32_be(self.lift_distance.raw());
ser.write_f32_be(self.lift_speed.raw());
ser.write_f32_be(self.bottom_retract_distance.raw());
ser.write_f32_be(self.bottom_retract_speed.raw());
ser.write_f32_be(self.retract_distance.raw());
ser.write_f32_be(self.retract_speed.raw());
ser.write_f32_be(self.bottom_second_lift_distance.raw());
ser.write_f32_be(self.bottom_second_lift_speed.raw());
ser.write_f32_be(self.second_lift_distance.raw());
ser.write_f32_be(self.second_lift_speed.raw());
ser.write_f32_be(self.bottom_second_retract_distance.raw());
ser.write_f32_be(self.bottom_second_retract_speed.raw());
ser.write_f32_be(self.second_retract_distance.raw());
ser.write_f32_be(self.second_retract_speed.raw());
ser.write_u16_be(self.bottom_light_pwm as u16);
ser.write_u16_be(self.light_pwm as u16);
ser.write_bool(self.per_layer_settings);
ser.write_u32_be(self.printing_time);
ser.write_f32_be(self.total_volume);
ser.write_f32_be(self.total_weight);
ser.write_f32_be(self.total_price);
self.price_unit.serialize(ser);
ser.write_u32_be(Self::SIZE as u32);
ser.write_bool(self.grey_scale_level);
ser.write_u16_be(self.transition_layers);
}
pub fn deserialize(des: &mut SliceDeserializer) -> Result<Self> {
Ok(Self {
version: SizedString::deserialize(des),
software_info: {
ensure!(des.read_slice(8) == [0x07, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x50, 0x00]);
SizedString::deserialize(des)
},
software_version: SizedString::deserialize(des),
file_time: SizedString::deserialize(des),
printer_name: SizedString::deserialize(des),
printer_type: SizedString::deserialize(des),
profile_name: SizedString::deserialize(des),
anti_aliasing_level: des.read_u16_be(),
grey_level: des.read_u16_be(),
blur_level: des.read_u16_be(),
small_preview: PreviewImage::deserializes(des),
big_preview: {
ensure!(des.read_slice(2) == [0xd, 0xa]);
PreviewImage::deserializes(des)
},
layer_count: {
ensure!(des.read_slice(2) == [0xd, 0xa]);
des.read_u32_be()
},
x_resolution: des.read_u16_be(),
y_resolution: des.read_u16_be(),
x_mirror: des.read_bool(),
y_mirror: des.read_bool(),
x_size: Milimeters::new(des.read_f32_be()),
y_size: Milimeters::new(des.read_f32_be()),
z_size: Milimeters::new(des.read_f32_be()),
layer_thickness: Milimeters::new(des.read_f32_be()),
exposure_time: Seconds::new(des.read_f32_be()),
exposure_delay_mode: ExposureDelayMode::from_bool(des.read_bool()),
turn_off_time: Seconds::new(des.read_f32_be()),
bottom_before_lift_time: Seconds::new(des.read_f32_be()),
bottom_after_lift_time: Seconds::new(des.read_f32_be()),
bottom_after_retract_time: Seconds::new(des.read_f32_be()),
before_lift_time: Seconds::new(des.read_f32_be()),
after_lift_time: Seconds::new(des.read_f32_be()),
after_retract_time: Seconds::new(des.read_f32_be()),
bottom_exposure_time: Seconds::new(des.read_f32_be()),
bottom_layers: des.read_u32_be(),
bottom_lift_distance: Milimeters::new(des.read_f32_be()),
bottom_lift_speed: MilimetersPerMinute::new(des.read_f32_be()),
lift_distance: Milimeters::new(des.read_f32_be()),
lift_speed: MilimetersPerMinute::new(des.read_f32_be()),
bottom_retract_distance: Milimeters::new(des.read_f32_be()),
bottom_retract_speed: MilimetersPerMinute::new(des.read_f32_be()),
retract_distance: Milimeters::new(des.read_f32_be()),
retract_speed: MilimetersPerMinute::new(des.read_f32_be()),
bottom_second_lift_distance: Milimeters::new(des.read_f32_be()),
bottom_second_lift_speed: MilimetersPerMinute::new(des.read_f32_be()),
second_lift_distance: Milimeters::new(des.read_f32_be()),
second_lift_speed: MilimetersPerMinute::new(des.read_f32_be()),
bottom_second_retract_distance: Milimeters::new(des.read_f32_be()),
bottom_second_retract_speed: MilimetersPerMinute::new(des.read_f32_be()),
second_retract_distance: Milimeters::new(des.read_f32_be()),
second_retract_speed: MilimetersPerMinute::new(des.read_f32_be()),
bottom_light_pwm: des.read_u16_be().min(255) as u8,
light_pwm: des.read_u16_be().min(255) as u8,
per_layer_settings: des.read_bool(),
printing_time: des.read_u32_be(),
total_volume: des.read_f32_be(),
total_weight: des.read_f32_be(),
total_price: des.read_f32_be(),
price_unit: SizedString::deserialize(des),
grey_scale_level: {
ensure!(des.read_u32_be() == Self::SIZE as u32);
des.read_bool()
},
transition_layers: des.read_u16_be(),
})
}
}
impl ExposureDelayMode {
pub fn from_bool(value: bool) -> Self {
match value {
false => ExposureDelayMode::TurnOffTime,
true => ExposureDelayMode::StaticTime,
}
}
}