pub mod constants;
pub mod error;
pub mod peripherals;
pub mod protocol;
pub mod transport;
pub mod util;
pub mod version;
use crate::error::{EtpError, EtpResult};
use constants::{MIN_RESPONSE_SIZE, TRANSPORT_QUEUE_SIZE};
use peripherals::gpio::Gpio;
use protocol::{
ETP_MESSAGE_HEADER_SIZE, EtpFirmwareInfoCmd, EtpMessageHeader, EtpOperations, EtpPayloadType,
ResetType,
};
use std::sync::{Arc, Mutex, mpsc};
use tracing::{debug, info};
use transport::common::TransportLayer;
use version::EtpFirmwareInfo;
pub struct Etp {
sink: mpsc::SyncSender<Vec<u8>>,
source: mpsc::Receiver<Vec<u8>>,
pub gpio: Gpio,
}
fn hex_string(data: &Vec<u8>) -> String {
let mut hex_string = String::new();
for byte in data {
hex_string.push_str(&format!("0x{:02X} ", byte));
}
hex_string.trim_end().to_string()
}
impl Etp {
pub fn new<T: TransportLayer + Send + 'static>(transport: T) -> EtpResult<Self> {
let (sender_queue_sender, sender_queue_receiver) = mpsc::sync_channel(TRANSPORT_QUEUE_SIZE);
let (receiver_queue_sender, receiver_queue_receiver) =
mpsc::sync_channel(TRANSPORT_QUEUE_SIZE);
let transport = Arc::new(Mutex::new(transport));
let transport_sender = Arc::clone(&transport);
std::thread::spawn(move || {
loop {
let recv_result = sender_queue_receiver.recv();
match recv_result {
Ok(command) => {
std::thread::sleep(std::time::Duration::from_millis(1));
let mut transport = transport_sender.lock().unwrap();
debug!("[ETP] Sending command: {:?}", hex_string(&command));
transport.send(command).unwrap();
}
Err(_) => {
info!("Sender queue closed, exiting thread.");
break;
}
}
}
});
let transport_receiver = Arc::clone(&transport);
std::thread::spawn(move || {
loop {
std::thread::sleep(std::time::Duration::from_millis(1));
let mut transport = transport_receiver.lock().unwrap();
let response = transport.receive(MIN_RESPONSE_SIZE);
match response {
Ok(response) => {
if response.is_empty() {
continue;
} else {
debug!("[ETP] Received response: {:?}", hex_string(&response));
receiver_queue_sender.send(response).unwrap();
}
}
Err(e) => {
debug!("Receiver error, transport probably closed {:?}", e);
break;
}
};
}
});
let mut etp = Etp {
sink: sender_queue_sender,
source: receiver_queue_receiver,
gpio: Gpio::new(),
};
etp.reset()?;
Ok(etp)
}
fn send(&self, command: Vec<u8>) -> EtpResult<()> {
self.sink
.send(command)
.map_err(|_| EtpError::TransportSendError("Failed to send command".to_string()))?;
Ok(())
}
fn receive(&self, expected_bytes: usize) -> EtpResult<Vec<u8>> {
let mut message: Vec<u8> = Vec::new();
let mut bytes_received = 0;
while bytes_received < expected_bytes {
let response = self.source.recv().map_err(|_| {
EtpError::TransportReceiveError("Failed to receive response".to_string())
})?;
bytes_received += response.len();
message.extend(response);
}
Ok(message)
}
fn frame_cmd_packet(&self, command: EtpOperations, payload: Vec<u8>) -> Vec<u8> {
let header = EtpMessageHeader::new(
payload.len() as u16,
protocol::EtpStatusCodes::Success,
EtpPayloadType::Command,
command,
);
let mut packet = Vec::new();
packet.extend_from_slice(Into::<Vec<u8>>::into(header).as_slice());
packet.extend_from_slice(&payload);
packet
}
pub fn get_fw_info(&mut self) -> EtpResult<EtpFirmwareInfo> {
let request = self.frame_cmd_packet(
EtpOperations::GetFirmwareInfo,
vec![EtpFirmwareInfoCmd::ProtocolVersion as u8],
);
self.send(request)?;
let bytes = self.receive(ETP_MESSAGE_HEADER_SIZE + 4)?;
let version = format!(
"{}.{}.{}",
bytes[ETP_MESSAGE_HEADER_SIZE + 1],
bytes[ETP_MESSAGE_HEADER_SIZE + 2],
bytes[ETP_MESSAGE_HEADER_SIZE + 3]
);
let request = self.frame_cmd_packet(
EtpOperations::GetFirmwareInfo,
vec![EtpFirmwareInfoCmd::FirmwareVersion as u8],
);
self.send(request)?;
let bytes = self.receive(ETP_MESSAGE_HEADER_SIZE + 4)?;
let fw_version = format!(
"{}.{}.{}",
bytes[ETP_MESSAGE_HEADER_SIZE + 1],
bytes[ETP_MESSAGE_HEADER_SIZE + 2],
bytes[ETP_MESSAGE_HEADER_SIZE + 3]
);
let request = self.frame_cmd_packet(
EtpOperations::GetFirmwareInfo,
vec![EtpFirmwareInfoCmd::BuildDate as u8],
);
self.send(request)?;
let bytes = self.receive(ETP_MESSAGE_HEADER_SIZE + 4)?;
let payload = bytes[ETP_MESSAGE_HEADER_SIZE..].to_vec();
let months = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
let month = months[payload[3] as usize - 1];
let day = payload[4];
let year: u16 = payload[1] as u16 | 0xFF00 & (payload[2] as u16) << 8;
let build_date = format!("{}-{}-{}", year, month, day);
let build_time = format!("{:02}:{:02}:{:02}", payload[5], payload[6], payload[7]);
let request = self.frame_cmd_packet(
EtpOperations::GetFirmwareInfo,
vec![EtpFirmwareInfoCmd::HardwareType as u8],
);
self.send(request)?;
let bytes = self.receive(ETP_MESSAGE_HEADER_SIZE + 4)?;
let hardware_type =
String::from_utf8_lossy(&bytes[ETP_MESSAGE_HEADER_SIZE + 1..]).to_string();
let hardware_type = hardware_type.trim_end_matches(char::from(0));
Ok(EtpFirmwareInfo {
protocol_version: version,
fw_version: fw_version,
build_date: build_date + " " + &build_time,
hardware_type: hardware_type.to_string(),
})
}
pub fn reset(&mut self) -> EtpResult<()> {
let request = self.frame_cmd_packet(
EtpOperations::Reset,
vec![ResetType::ReInit as u8],
);
self.send(request)?;
let _ = self.receive(0)?;
std::thread::sleep(std::time::Duration::from_secs(3));
Ok(())
}
}