use crate::types::LaserPoint;
use std::time::Duration;
pub const CONTROL_TIMEOUT: Duration = Duration::from_millis(1000);
pub const LASERDOCK_VID: u16 = 0x1fc9;
pub const LASERDOCK_PID: u16 = 0x04d8;
pub const CONTROL_INTERFACE: u8 = 0;
pub const DATA_INTERFACE: u8 = 1;
pub const DATA_ALT_SETTING: u8 = 1;
pub const ENDPOINT_CONTROL_OUT: u8 = 0x01;
pub const ENDPOINT_CONTROL_IN: u8 = 0x81;
pub const ENDPOINT_DATA_OUT: u8 = 0x03;
pub const CONTROL_PACKET_SIZE: usize = 64;
pub const CMD_SET_OUTPUT: u8 = 0x80;
pub const CMD_GET_OUTPUT: u8 = 0x81;
pub const CMD_SET_DAC_RATE: u8 = 0x82;
pub const CMD_GET_DAC_RATE: u8 = 0x83;
pub const CMD_GET_MAX_DAC_RATE: u8 = 0x84;
pub const CMD_GET_SAMPLE_ELEMENT_COUNT: u8 = 0x85;
pub const CMD_GET_ISO_PACKET_SAMPLE_COUNT: u8 = 0x86;
pub const CMD_GET_MIN_DAC_VALUE: u8 = 0x87;
pub const CMD_GET_MAX_DAC_VALUE: u8 = 0x88;
pub const CMD_GET_RINGBUFFER_SAMPLE_COUNT: u8 = 0x89;
pub const CMD_GET_RINGBUFFER_EMPTY_SAMPLE_COUNT: u8 = 0x8A;
pub const CMD_GET_VERSION_MAJOR: u8 = 0x8B;
pub const CMD_GET_VERSION_MINOR: u8 = 0x8C;
pub const CMD_CLEAR_RINGBUFFER: u8 = 0x8D;
pub const CMD_GET_BULK_PACKET_SAMPLE_COUNT: u8 = 0x8E;
pub const CMD_RUNNER_MODE: u8 = 0xC0;
pub const RUNNER_MODE_SUB_ENABLE: u8 = 0x01;
pub const RUNNER_MODE_SUB_RUN: u8 = 0x09;
pub const MAX_COORDINATE_VALUE: u16 = 4095;
pub const SAMPLE_SIZE_BYTES: usize = 8;
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Sample {
pub rg: u16,
pub b: u16,
pub x: u16,
pub y: u16,
}
impl Sample {
pub fn new(x: u16, y: u16, r: u8, g: u8, b: u8) -> Self {
Self {
rg: (r as u16) | ((g as u16) << 8),
b: b as u16,
x: x.min(MAX_COORDINATE_VALUE),
y: y.min(MAX_COORDINATE_VALUE),
}
}
pub fn blank() -> Self {
Self::new(2048, 2048, 0, 0, 0)
}
pub fn red(&self) -> u8 {
(self.rg & 0xFF) as u8
}
pub fn green(&self) -> u8 {
((self.rg >> 8) & 0xFF) as u8
}
pub fn blue(&self) -> u8 {
(self.b & 0xFF) as u8
}
pub fn flip_x(&mut self) {
self.x = MAX_COORDINATE_VALUE - self.x;
}
pub fn flip_y(&mut self) {
self.y = MAX_COORDINATE_VALUE - self.y;
}
pub fn to_bytes(&self) -> [u8; SAMPLE_SIZE_BYTES] {
let mut bytes = [0u8; SAMPLE_SIZE_BYTES];
bytes[0..2].copy_from_slice(&self.rg.to_le_bytes());
bytes[2..4].copy_from_slice(&self.b.to_le_bytes());
bytes[4..6].copy_from_slice(&self.x.to_le_bytes());
bytes[6..8].copy_from_slice(&self.y.to_le_bytes());
bytes
}
}
impl From<&LaserPoint> for Sample {
fn from(p: &LaserPoint) -> Self {
Sample::new(
LaserPoint::coord_to_u12(p.x),
LaserPoint::coord_to_u12(p.y),
LaserPoint::color_to_u8(p.r),
LaserPoint::color_to_u8(p.g),
LaserPoint::color_to_u8(p.b),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample_new() {
let sample = Sample::new(2048, 2048, 255, 128, 64);
assert_eq!(sample.x, 2048);
assert_eq!(sample.y, 2048);
assert_eq!(sample.red(), 255);
assert_eq!(sample.green(), 128);
assert_eq!(sample.blue(), 64);
}
#[test]
fn test_sample_blank() {
let blank = Sample::blank();
assert_eq!(blank.x, 2048);
assert_eq!(blank.y, 2048);
assert_eq!(blank.red(), 0);
assert_eq!(blank.green(), 0);
assert_eq!(blank.blue(), 0);
}
#[test]
fn test_sample_clamps_coordinates() {
let sample = Sample::new(5000, 6000, 0, 0, 0);
assert_eq!(sample.x, MAX_COORDINATE_VALUE);
assert_eq!(sample.y, MAX_COORDINATE_VALUE);
}
#[test]
fn test_sample_flip() {
let mut sample = Sample::new(1000, 3000, 0, 0, 0);
sample.flip_x();
sample.flip_y();
assert_eq!(sample.x, 4095 - 1000);
assert_eq!(sample.y, 4095 - 3000);
}
#[test]
fn test_sample_size() {
assert_eq!(std::mem::size_of::<Sample>(), SAMPLE_SIZE_BYTES);
}
}