Last active
August 27, 2024 23:38
-
-
Save kiranshila/69f7e64f1c708edfd76121db44cd9c02 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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