use serde::{Deserialize, Serialize};
use serialport::{self, SerialPort};
use serialport::{
ClearBuffer as SerialClearBuffer, DataBits as SerialDataBits, FlowControl as SerialFlowControl,
Parity as SerialParity, StopBits as SerialStopBits,
};
use std::thread::JoinHandle;
use std::{
collections::HashMap,
sync::{mpsc::Sender, Arc, Mutex, OnceLock},
};
pub struct ConnectedPort {
pub port: Box<dyn SerialPort>,
pub sender: Option<Sender<usize>>,
pub thread_handle: Option<JoinHandle<()>>,
}
pub enum PortState {
Closed,
Opening,
Connected(ConnectedPort),
}
impl PortState {
pub fn not_connected_reason(&self) -> String {
match self {
PortState::Closed => "Port is closed".to_string(),
PortState::Opening => "Port is still opening".to_string(),
PortState::Connected(_) => "Port is connected".to_string(),
}
}
}
#[derive(Default)]
pub struct SerialportState {
pub serialports: Arc<Mutex<HashMap<String, SerialportInfo>>>,
}
pub struct SerialportInfo {
pub state: PortState,
}
impl SerialportInfo {
pub fn new(port: Box<dyn SerialPort>) -> Self {
Self {
state: PortState::Connected(ConnectedPort {
port,
sender: None,
thread_handle: None,
}),
}
}
#[cfg(test)]
pub(crate) fn connected_port_mut(&mut self) -> Option<&mut ConnectedPort> {
match &mut self.state {
PortState::Connected(cp) => Some(cp),
_ => None,
}
}
}
#[derive(Serialize, Clone)]
pub struct InvokeResult {
pub code: i32,
pub message: String,
}
#[derive(Serialize, Clone)]
pub struct ReadData<'a> {
pub data: &'a [u8],
pub size: usize,
}
pub const UNKNOWN: &str = "Unknown";
pub const USB: &str = "USB";
pub const BLUETOOTH: &str = "Bluetooth";
pub const PCI: &str = "PCI";
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataBits {
Five,
Six,
Seven,
Eight,
}
impl From<DataBits> for SerialDataBits {
fn from(bits: DataBits) -> Self {
match bits {
DataBits::Five => SerialDataBits::Five,
DataBits::Six => SerialDataBits::Six,
DataBits::Seven => SerialDataBits::Seven,
DataBits::Eight => SerialDataBits::Eight,
}
}
}
impl DataBits {
pub fn as_u8(&self) -> u8 {
match self {
DataBits::Five => 5,
DataBits::Six => 6,
DataBits::Seven => 7,
DataBits::Eight => 8,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FlowControl {
None,
Software,
Hardware,
}
impl From<FlowControl> for SerialFlowControl {
fn from(flow: FlowControl) -> Self {
match flow {
FlowControl::None => SerialFlowControl::None,
FlowControl::Software => SerialFlowControl::Software,
FlowControl::Hardware => SerialFlowControl::Hardware,
}
}
}
impl FlowControl {
pub fn as_u8(&self) -> u8 {
match self {
FlowControl::None => 0,
FlowControl::Software => 1,
FlowControl::Hardware => 2,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Parity {
None,
Odd,
Even,
}
impl From<Parity> for SerialParity {
fn from(parity: Parity) -> Self {
match parity {
Parity::None => SerialParity::None,
Parity::Odd => SerialParity::Odd,
Parity::Even => SerialParity::Even,
}
}
}
impl Parity {
pub fn as_u8(&self) -> u8 {
match self {
Parity::None => 0,
Parity::Odd => 1,
Parity::Even => 2,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum StopBits {
One,
Two,
}
impl From<StopBits> for SerialStopBits {
fn from(bits: StopBits) -> Self {
match bits {
StopBits::One => SerialStopBits::One,
StopBits::Two => SerialStopBits::Two,
}
}
}
impl StopBits {
pub fn as_u8(&self) -> u8 {
match self {
StopBits::One => 1,
StopBits::Two => 2,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ClearBuffer {
Input,
Output,
All,
}
impl From<ClearBuffer> for SerialClearBuffer {
fn from(buffer: ClearBuffer) -> Self {
match buffer {
ClearBuffer::Input => SerialClearBuffer::Input,
ClearBuffer::Output => SerialClearBuffer::Output,
ClearBuffer::All => SerialClearBuffer::All,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum LogLevel {
None,
Error,
Warn,
Info,
Debug,
}
impl Default for LogLevel {
fn default() -> Self {
LogLevel::Info
}
}
impl LogLevel {
pub fn should_log_error(&self) -> bool {
matches!(self, LogLevel::Error | LogLevel::Warn | LogLevel::Info | LogLevel::Debug)
}
pub fn should_log_warn(&self) -> bool {
matches!(self, LogLevel::Warn | LogLevel::Info | LogLevel::Debug)
}
pub fn should_log_info(&self) -> bool {
matches!(self, LogLevel::Info | LogLevel::Debug)
}
pub fn should_log_debug(&self) -> bool {
matches!(self, LogLevel::Debug)
}
}
static LOG_LEVEL: OnceLock<Mutex<LogLevel>> = OnceLock::new();
fn get_log_level_mutex() -> &'static Mutex<LogLevel> {
LOG_LEVEL.get_or_init(|| Mutex::new(LogLevel::Info))
}
pub fn set_log_level(level: LogLevel) {
if let Ok(mut log_level) = get_log_level_mutex().lock() {
*log_level = level;
}
}
pub fn get_log_level() -> LogLevel {
get_log_level_mutex().lock().unwrap_or_else(|e| {
eprintln!("Failed to lock log level: {}", e);
e.into_inner()
}).clone()
}