Skip to content

Instantly share code, notes, and snippets.

@kiranshila
Last active August 27, 2024 23:38
Show Gist options
  • Save kiranshila/69f7e64f1c708edfd76121db44cd9c02 to your computer and use it in GitHub Desktop.
Save kiranshila/69f7e64f1c708edfd76121db44cd9c02 to your computer and use it in GitHub Desktop.
use hidapi::{HidDevice, HidError};
const PAYLOAD_SIZE: usize = 128;
// Factory-values for the VID and PID
const VID: u16 = 0x1a0d;
const PID: u16 = 0x15d8;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Lower-level HID error")]
Hid(#[from] HidError),
#[error("Did not receive a handshake from USB")]
NoHandshake,
}
pub struct LadyBug {
dev: HidDevice,
}
pub type LadyBugResult<T> = Result<T, Error>;
// NULL NULL * 1 0 NULL
const NULL_REPORT: [u8; 6] = [0x00, 0x00, 0x2A, 0x31, 0x30, 0x00];
/// Create a byte array of a SCPI string (no terminator) for IEEE488
fn format_488_query(s: &str) -> Vec<u8> {
let s_len_str = (s.len() + 1).to_string();
let formated = format!("%{}{}{}\n", s_len_str.len(), s_len_str, s);
formated.into_bytes()
}
/// Parse a response (skip the leading null from the HID endpoint
fn parse_488_reponse(bytes: &[u8]) -> String {
assert_eq!(bytes[0], b'*', "Reponses start with *");
let string_len_n = (bytes[1] as char).to_digit(10).expect("Not a digit") as usize;
let string_len = String::from_utf8(bytes[2..string_len_n + 2].to_vec())
.expect("Invalid UTF8")
.parse::<usize>()
.expect("Invalid digits");
String::from_utf8(bytes[(2 + string_len_n)..(2 + string_len_n + string_len)].to_vec())
.expect("Invalid UTF8")
}
impl LadyBug {
/// Open a ladybug device
pub fn new() -> LadyBugResult<Self> {
let api = hidapi::HidApi::new()?;
let dev = api.open(VID, PID)?;
Ok(Self { dev })
}
fn write(&self, str: &str) -> LadyBugResult<()> {
let mut buf = [0u8; PAYLOAD_SIZE];
let bytes = format_488_query(str);
buf[2..(2 + bytes.len())].clone_from_slice(&bytes);
self.dev.write(&buf)?;
self.dev.read(&mut buf)?;
let s = parse_488_reponse(&buf[1..]);
if s.is_empty() {
Ok(())
} else {
Err(Error::NoHandshake)
}
}
fn read(&self) -> LadyBugResult<String> {
let mut buf = [0u8; PAYLOAD_SIZE];
self.dev.write(&NULL_REPORT)?;
self.dev.read(&mut buf)?;
Ok(parse_488_reponse(&buf[1..]))
}
fn query(&self, str: &str) -> LadyBugResult<String> {
self.write(str)?;
self.read()
}
pub fn reset(&self) -> LadyBugResult<()> {
self.write("*RST")
}
pub fn identifier(&self) -> LadyBugResult<String> {
self.query("*IDN?")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment