use std::{
io::{BufRead, BufReader},
thread::sleep,
time::Duration,
};
use scpi_client::{
EmptyResponse, ScpiDeserialize, ScpiRequest, ScpiSerialize, check_empty, match_literal,
};
use serialport::{SerialPort, SerialPortInfo};
use crate::commands::{
CurrentRange, DifferentialConversionRequest, DisableRequest, EepromAddress, EnableRequest,
EnableVoltageCalibrationModeRequest, IdentityRequest,
LockCurrentRangeAndClearCalibrationRequest, MeasureRequest, MeasureResponse, ReadEepromRequest,
ResetRequest, SetCurrentLimitDacRequest, SetCurrentLimitRequest, SetOverSampleRateRequest,
SetVoltageDacRequest, SetVoltageRequest, WriteCurrentLimitCalibrationRequest,
WriteCurrentLimitDacCalibrationRequest, WriteVoltageAdcCalibrationRequest,
WriteVoltageDacCalibrationRequest,
};
pub type Current = uom::si::f32::ElectricCurrent;
pub type Voltage = uom::si::f32::ElectricPotential;
pub type Time = uom::si::f32::Time;
pub use uom::si::electric_current::{ampere, milliampere};
pub use uom::si::electric_potential::{millivolt, volt};
pub use uom::si::time::{millisecond, second};
pub mod commands;
pub mod record_iv_curve;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("{0}")]
ScpiClient(#[from] scpi_client::Error),
#[error("IOError: {0}")]
IoError(#[from] std::io::Error),
#[error("serialport error: {0}")]
Serialport(#[from] serialport::Error),
#[error("{0}")]
Other(#[from] anyhow::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
pub struct MicroSmu {
port: Box<dyn SerialPort>,
}
impl MicroSmu {
pub fn open(port: SerialPortInfo) -> Result<MicroSmu> {
const BAUDRATE: u32 = 9600;
let port = serialport::new(port.port_name, BAUDRATE)
.timeout(Duration::from_millis(1000))
.open()?;
let smu = Self::new(port);
Ok(smu)
}
pub fn new(port: Box<dyn SerialPort>) -> MicroSmu {
Self { port }
}
fn send(&mut self, request: impl ScpiSerialize) -> Result<()> {
let mut out = String::new();
out.reserve(32);
request.serialize(&mut out);
out.push('\n');
assert!(out.is_ascii());
self.port.write_all(out.as_bytes())?;
sleep(Duration::from_millis(50));
Ok(())
}
pub fn send_command<Request>(&mut self, request: Request) -> Result<()>
where
Request: ScpiRequest<Response = EmptyResponse>,
{
self.send(request)?;
Ok(())
}
pub fn query<Request, Response>(&mut self, request: Request) -> Result<Response>
where
Request: ScpiRequest<Response = Response>,
Response: ScpiDeserialize,
{
self.send(request)?;
let mut reader = BufReader::new(&mut self.port);
let mut data = String::new();
reader.read_line(&mut data)?;
let mut data = data.as_str();
let response = Response::deserialize(&mut data)?;
match_literal(&mut data, "\n")?;
check_empty(data)?;
Ok(response)
}
pub fn enable(&mut self) -> Result<()> {
self.send_command(EnableRequest)?;
Ok(())
}
pub fn disable(&mut self) -> Result<()> {
self.send_command(DisableRequest)?;
Ok(())
}
pub fn set_current_limit(&mut self, limit: Current) -> Result<()> {
self.send_command(SetCurrentLimitRequest::new(limit))?;
Ok(())
}
pub fn set_voltage(&mut self, voltage: Voltage) -> Result<()> {
self.send_command(SetVoltageRequest { voltage })?;
Ok(())
}
pub fn measure(&mut self, voltage: Voltage) -> Result<MeasureResponse> {
let response = self.query(MeasureRequest { voltage })?;
Ok(response)
}
pub fn set_over_sample_rate(&mut self, samples: u16) -> Result<()> {
self.send_command(SetOverSampleRateRequest { samples })?;
Ok(())
}
pub fn set_voltage_dac(&mut self, level: u16) -> Result<()> {
self.send_command(SetVoltageDacRequest { level })?;
Ok(())
}
pub fn manual_measure_differential_channel(&mut self, channel: u8) -> Result<u16> {
let response = self.query(DifferentialConversionRequest::new(channel))?;
Ok(response.value)
}
pub fn set_current_limit_dac(&mut self, level: u16) -> Result<()> {
self.send_command(SetCurrentLimitDacRequest { level })?;
Ok(())
}
pub fn enable_voltage_calibration_mode(&mut self) -> Result<()> {
self.send_command(EnableVoltageCalibrationModeRequest)?;
Ok(())
}
pub fn lock_current_range_and_clear_calibration(&mut self, range: CurrentRange) -> Result<()> {
self.send_command(LockCurrentRangeAndClearCalibrationRequest { range })?;
Ok(())
}
pub fn write_eeprom(&mut self, _address: u16, _value: f32) -> Result<()> {
unimplemented!("Unavailable, see documentation.");
}
pub fn read_eeprom(&mut self, address: EepromAddress) -> Result<f32> {
let response = self.query(ReadEepromRequest { address })?;
Ok(response.value)
}
pub fn reset(mut self) -> Result<()> {
self.send_command(ResetRequest)?;
Ok(())
}
pub fn get_identity(&mut self) -> Result<u32> {
let response = self.query(IdentityRequest)?;
Ok(response.uid)
}
pub fn write_voltage_dac_calibration(&mut self, slope: f32, intercept: f32) -> Result<()> {
self.send_command(WriteVoltageDacCalibrationRequest { slope, intercept })?;
Ok(())
}
pub fn write_voltage_adc_calibration(&mut self, slope: f32, intercept: f32) -> Result<()> {
self.send_command(WriteVoltageAdcCalibrationRequest { slope, intercept })?;
Ok(())
}
pub fn write_current_limit_calibration(
&mut self,
range: CurrentRange,
slope: f32,
intercept: f32,
) -> Result<()> {
self.send_command(WriteCurrentLimitCalibrationRequest {
range,
slope,
intercept,
})?;
Ok(())
}
pub fn write_current_limit_dac(&mut self, slope: f32, intercept: f32) -> Result<()> {
self.send_command(WriteCurrentLimitDacCalibrationRequest { slope, intercept })?;
Ok(())
}
}
pub const USB_VID: u16 = 1155;
pub const USB_PID: u16 = 22336;
pub fn find_serial_ports() -> Result<Vec<SerialPortInfo>> {
let ports = serialport::available_ports()?
.into_iter()
.filter(|e| match &e.port_type {
serialport::SerialPortType::UsbPort(usb) => usb.pid == USB_PID && usb.vid == USB_VID,
_ => false,
})
.collect();
Ok(ports)
}