use crate::device::PoKeysDevice;
use crate::error::Result;
use crate::types::I2cStatus;
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum USPIBridgeCommand {
SetBrightness = 0x11, DisplayText = 0x20, DisplayNumber = 0x21, SetCharacter = 0x22, SetPattern = 0x23, SetDecimal = 0x24, ClearDevice = 0x25,
SetSegmentMapping = 0x26, SetSegmentMappingType = 0x27, GetSegmentMapping = 0x28, TestSegmentMapping = 0x29,
CreateVirtualDevice = 0x40, DeleteVirtualDevice = 0x41, ListVirtualDevices = 0x42, VirtualText = 0x43, VirtualBrightness = 0x44, VirtualClear = 0x45, VirtualScrollLeft = 0x46, VirtualScrollRight = 0x47, VirtualFlash = 0x48, VirtualStop = 0x49,
SystemReset = 0x50, SystemStatus = 0x51, SystemConfig = 0x52, }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SegmentMappingType {
Standard = 0,
Reversed = 1,
CommonCathode = 2,
SparkfunSerial = 3,
AdafruitBackpack = 4,
Custom = 5,
}
impl Default for SegmentMappingType {
fn default() -> Self {
Self::Standard
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SegmentMapping {
pub mapping_type: SegmentMappingType,
pub custom_mapping: Option<[u8; 8]>,
}
impl Default for SegmentMapping {
fn default() -> Self {
Self {
mapping_type: SegmentMappingType::Standard,
custom_mapping: None,
}
}
}
impl SegmentMapping {
pub fn new(mapping_type: SegmentMappingType) -> Self {
Self {
mapping_type,
custom_mapping: None,
}
}
pub fn custom(mapping: [u8; 8]) -> Self {
Self {
mapping_type: SegmentMappingType::Custom,
custom_mapping: Some(mapping),
}
}
pub fn is_custom(&self) -> bool {
self.mapping_type == SegmentMappingType::Custom
}
pub fn get_custom_mapping(&self) -> Option<&[u8; 8]> {
self.custom_mapping.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct USPIBridgeConfig {
pub device_count: u8,
pub segment_mappings: Vec<SegmentMapping>,
pub default_brightness: u8,
pub max_virtual_devices: u8,
}
impl Default for USPIBridgeConfig {
fn default() -> Self {
Self::new()
}
}
impl USPIBridgeConfig {
pub fn new() -> Self {
Self {
device_count: 8,
segment_mappings: vec![SegmentMapping::default(); 8],
default_brightness: 8,
max_virtual_devices: 16,
}
}
pub fn with_device_count(mut self, count: u8) -> Self {
self.device_count = count;
self.segment_mappings
.resize(count as usize, SegmentMapping::default());
self
}
pub fn with_segment_mapping(mut self, device_id: usize, mapping: SegmentMapping) -> Self {
if device_id < self.segment_mappings.len() {
self.segment_mappings[device_id] = mapping;
}
self
}
pub fn with_all_devices_segment_mapping(mut self, mapping: SegmentMapping) -> Self {
for device_mapping in &mut self.segment_mappings {
*device_mapping = mapping.clone();
}
self
}
pub fn with_default_brightness(mut self, brightness: u8) -> Self {
self.default_brightness = brightness.min(15);
self
}
pub fn with_max_virtual_devices(mut self, max_devices: u8) -> Self {
self.max_virtual_devices = max_devices;
self
}
}
impl PoKeysDevice {
pub fn uspibridge_write_command(
&mut self,
slave_address: u8,
command: USPIBridgeCommand,
device_id: u8,
data: &[u8],
) -> Result<I2cStatus> {
let mut packet = Vec::new();
packet.push(command as u8); packet.push(device_id); packet.push(data.len() as u8); packet.extend_from_slice(data);
let mut checksum = 0u8;
for &byte in &packet {
checksum ^= byte;
}
packet.push(checksum);
self.i2c_write(slave_address, &packet)
}
pub fn uspibridge_set_segment_mapping(
&mut self,
slave_address: u8,
device_id: u8,
mapping: &[u8; 8],
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetSegmentMapping,
device_id,
mapping,
)
}
pub fn uspibridge_set_segment_mapping_type(
&mut self,
slave_address: u8,
device_id: u8,
mapping_type: SegmentMappingType,
) -> Result<I2cStatus> {
let data = vec![mapping_type as u8];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetSegmentMappingType,
device_id,
&data,
)
}
pub fn uspibridge_get_segment_mapping(
&mut self,
slave_address: u8,
device_id: u8,
) -> Result<(I2cStatus, Option<[u8; 8]>)> {
let status = self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::GetSegmentMapping,
device_id,
&[],
)?;
if status != I2cStatus::Ok {
return Ok((status, None));
}
std::thread::sleep(std::time::Duration::from_millis(10));
let (read_status, response_data) = self.i2c_read(slave_address, 10)?;
if read_status == I2cStatus::Ok && response_data.len() >= 8 {
let mut mapping = [0u8; 8];
mapping.copy_from_slice(&response_data[0..8]);
Ok((read_status, Some(mapping)))
} else {
Ok((read_status, None))
}
}
pub fn uspibridge_test_segment_mapping(
&mut self,
slave_address: u8,
device_id: u8,
test_pattern: u8,
) -> Result<I2cStatus> {
let data = vec![test_pattern];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::TestSegmentMapping,
device_id,
&data,
)
}
pub fn uspibridge_display_text(
&mut self,
slave_address: u8,
device_id: u8,
text: &str,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::DisplayText,
device_id,
text.as_bytes(),
)
}
pub fn uspibridge_display_number(
&mut self,
slave_address: u8,
device_id: u8,
number: u32,
) -> Result<I2cStatus> {
let data = number.to_le_bytes();
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::DisplayNumber,
device_id,
&data,
)
}
pub fn uspibridge_set_character(
&mut self,
slave_address: u8,
device_id: u8,
position: u8,
character: u8,
) -> Result<I2cStatus> {
let data = vec![position, character];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetCharacter,
device_id,
&data,
)
}
pub fn uspibridge_set_pattern(
&mut self,
slave_address: u8,
device_id: u8,
position: u8,
pattern: u8,
) -> Result<I2cStatus> {
let data = vec![position, pattern];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetPattern,
device_id,
&data,
)
}
pub fn uspibridge_set_decimal(
&mut self,
slave_address: u8,
device_id: u8,
position: u8,
state: bool,
) -> Result<I2cStatus> {
let data = vec![position, if state { 1 } else { 0 }];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetDecimal,
device_id,
&data,
)
}
pub fn uspibridge_set_brightness(
&mut self,
slave_address: u8,
device_id: u8,
brightness: u8,
) -> Result<I2cStatus> {
let data = vec![brightness.min(15)];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::SetBrightness,
device_id,
&data,
)
}
pub fn uspibridge_clear_device(
&mut self,
slave_address: u8,
device_id: u8,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::ClearDevice,
device_id,
&[],
)
}
pub fn uspibridge_virtual_text(
&mut self,
slave_address: u8,
virtual_id: u8,
text: &str,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::VirtualText,
virtual_id,
text.as_bytes(),
)
}
pub fn uspibridge_create_virtual_device(
&mut self,
slave_address: u8,
virtual_id: u8,
physical_devices: &[u8],
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::CreateVirtualDevice,
virtual_id,
physical_devices,
)
}
pub fn uspibridge_delete_virtual_device(
&mut self,
slave_address: u8,
virtual_id: u8,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::DeleteVirtualDevice,
virtual_id,
&[],
)
}
pub fn uspibridge_list_virtual_devices(
&mut self,
slave_address: u8,
) -> Result<(I2cStatus, Option<Vec<u8>>)> {
let status = self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::ListVirtualDevices,
0, &[],
)?;
if status != I2cStatus::Ok {
return Ok((status, None));
}
std::thread::sleep(std::time::Duration::from_millis(10));
let (read_status, response_data) = self.i2c_read(slave_address, 32)?;
Ok((read_status, Some(response_data)))
}
pub fn uspibridge_virtual_brightness(
&mut self,
slave_address: u8,
virtual_id: u8,
brightness: u8,
) -> Result<I2cStatus> {
let data = vec![brightness.min(15)];
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::VirtualBrightness,
virtual_id,
&data,
)
}
pub fn uspibridge_virtual_scroll(
&mut self,
slave_address: u8,
virtual_id: u8,
text: &str,
speed_ms: u16,
direction_left: bool,
) -> Result<I2cStatus> {
let mut data = text.as_bytes().to_vec();
data.extend_from_slice(&speed_ms.to_le_bytes());
let command = if direction_left {
USPIBridgeCommand::VirtualScrollLeft
} else {
USPIBridgeCommand::VirtualScrollRight
};
self.uspibridge_write_command(slave_address, command, virtual_id, &data)
}
pub fn uspibridge_virtual_flash(
&mut self,
slave_address: u8,
virtual_id: u8,
text: &str,
interval_ms: u16,
) -> Result<I2cStatus> {
let mut data = text.as_bytes().to_vec();
data.extend_from_slice(&interval_ms.to_le_bytes());
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::VirtualFlash,
virtual_id,
&data,
)
}
pub fn uspibridge_virtual_stop(
&mut self,
slave_address: u8,
virtual_id: u8,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::VirtualStop,
virtual_id,
&[],
)
}
pub fn uspibridge_virtual_clear(
&mut self,
slave_address: u8,
virtual_id: u8,
) -> Result<I2cStatus> {
self.uspibridge_write_command(
slave_address,
USPIBridgeCommand::VirtualClear,
virtual_id,
&[],
)
}
pub fn uspibridge_system_reset(&mut self, slave_address: u8) -> Result<I2cStatus> {
self.uspibridge_write_command(slave_address, USPIBridgeCommand::SystemReset, 0, &[])
}
pub fn uspibridge_system_status(
&mut self,
slave_address: u8,
) -> Result<(I2cStatus, Option<Vec<u8>>)> {
let status =
self.uspibridge_write_command(slave_address, USPIBridgeCommand::SystemStatus, 0, &[])?;
if status != I2cStatus::Ok {
return Ok((status, None));
}
std::thread::sleep(std::time::Duration::from_millis(10));
let (read_status, response_data) = self.i2c_read(slave_address, 16)?;
Ok((read_status, Some(response_data)))
}
}