use bit_field::BitField;
use crate::Error;
#[derive(Debug, Clone)]
pub struct DeviceString(String);
impl TryFrom<String> for DeviceString {
type Error = &'static str;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.encode_utf16().count() <= 30 {
Ok(Self(value))
} else {
Err("String must be 60 bytes or fewer when UTF-16-encoded.")
}
}
}
impl std::str::FromStr for DeviceString {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s.to_owned())
}
}
impl DeviceString {
pub(crate) fn try_from_buffer(buf: &[u8; 64]) -> Result<Self, Error> {
assert_eq!(buf[3], 0x03, "String response sanity check.");
let n_bytes = buf[2] as usize - 2;
assert!(n_bytes <= 60, "String longer than specified.");
assert_eq!(n_bytes % 2, 0, "Odd number of utf-16 bytes received.");
let n_utf16_chars = n_bytes / 2;
let mut str_utf16 = Vec::with_capacity(n_utf16_chars);
for char_number in 0..n_utf16_chars {
let low_idx = 4 + 2 * char_number;
let high_idx = 4 + 2 * char_number + 1;
let utf16 = u16::from_le_bytes([buf[low_idx], buf[high_idx]]);
str_utf16.push(utf16);
}
String::from_utf16(str_utf16.as_slice())
.map(Self)
.map_err(Error::InvalidStringFromDevice)
}
pub(crate) fn apply_to_flash_buffer(&self, buf: &mut [u8; 64]) {
let mut byte_count = 0;
let utf16_pairs = self.0.encode_utf16().map(u16::to_le_bytes);
for (unicode_char_number, [low, high]) in utf16_pairs.enumerate() {
let pos = 4 + (2 * unicode_char_number);
buf[pos] = low;
buf[pos + 1] = high;
byte_count += 2;
}
buf[2] = byte_count + 2;
buf[3] = 0x03; }
}
impl std::fmt::Display for DeviceString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub enum ClockDutyCycle {
P75,
#[default]
P50,
P25,
P0,
}
#[doc(hidden)]
impl From<u8> for ClockDutyCycle {
fn from(value: u8) -> Self {
assert!(value <= 0b11, "Invalid bit pattern for duty cycle");
match value {
0b11 => Self::P75,
0b10 => Self::P50,
0b01 => Self::P25,
0b00 => Self::P0,
_ => unreachable!("Precondition assert covers > 3."),
}
}
}
#[doc(hidden)]
impl From<ClockDutyCycle> for u8 {
fn from(value: ClockDutyCycle) -> u8 {
match value {
ClockDutyCycle::P75 => 0b11,
ClockDutyCycle::P50 => 0b10,
ClockDutyCycle::P25 => 0b01,
ClockDutyCycle::P0 => 0b00,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Default, Clone, Copy)]
pub enum ClockFrequency {
_375_kHz,
_750_kHz,
_1_5_MHz,
_3_MHz,
_6_MHz,
#[default]
_12_MHz,
_24_MHz,
}
#[doc(hidden)]
impl From<u8> for ClockFrequency {
fn from(value: u8) -> Self {
assert!(value <= 0b111, "Invalid bit pattern for clock speed.");
assert_ne!(value, 0, "Use of Reserved clock speed bit pattern.");
match value {
0b111 => Self::_375_kHz,
0b110 => Self::_750_kHz,
0b101 => Self::_1_5_MHz,
0b100 => Self::_3_MHz,
0b011 => Self::_6_MHz,
0b010 => Self::_12_MHz,
0b001 => Self::_24_MHz,
_ => unreachable!("Precondition asserts cover 0 and > 7."),
}
}
}
#[doc(hidden)]
impl From<ClockFrequency> for u8 {
fn from(value: ClockFrequency) -> Self {
match value {
ClockFrequency::_375_kHz => 0b111,
ClockFrequency::_750_kHz => 0b110,
ClockFrequency::_1_5_MHz => 0b101,
ClockFrequency::_3_MHz => 0b100,
ClockFrequency::_6_MHz => 0b011,
ClockFrequency::_12_MHz => 0b010,
ClockFrequency::_24_MHz => 0b001,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct ClockOutputSetting(
) of the clock output signal.
pub ClockDutyCycle,
pub ClockFrequency
);
#[doc(hidden)]
impl From<u8> for ClockOutputSetting {
fn from(value: u8) -> Self {
assert!(
value <= 0b11111,
"Raw clock 'divider' must be in the low 5 bits."
);
Self(
ClockDutyCycle::from(value.get_bits(3..=4)),
ClockFrequency::from(value.get_bits(0..=2)),
)
}
}
#[doc(hidden)]
impl From<ClockOutputSetting> for u8 {
fn from(value: ClockOutputSetting) -> Self {
let ClockOutputSetting(duty_cycle, frequency) = value;
let mut byte = 0u8;
byte.set_bits(3..=4, duty_cycle.into());
byte.set_bits(0..=2, frequency.into());
byte
}
}