Open averyanalex opened 1 year ago
I'd appreciate your help very much! How do you think a higher level API could look like?
I'd appreciate your help very much! How do you think a higher level API could look like?
I think something like this: https://github.com/averyanalex/pn532/commit/d43ce6a64175a65906f12dfc04c6cf05477d2fd5. But I am not good in Rust, so IDK how to implement it for blocking and async version without just copy-pasting same code and adding await to it.
P.S. I am limited on time too the next 1-2 months.
Here is one potential proposal: We introduce a new trait Cmd
. It knows how to construct a Request for itself and how to parse a response for itself. We add a new function Pn532::call
to use these commands. Here is a full implementation of GetFirmwareVersion.
Usage:
let firmware = pn532.call(GetFirmwareVersion::new(), millis(100)).unwrap();
println!("Found PN532 with firmware version: {}", firmware.version_string());
Implementation is done through a trait (here called Cmd), one example is just the FirmwareVersion call:
pub trait Cmd: Sized {
const NUM_BYTES: usize;
type Response;
fn request(&self) -> crate::requests::Request<0>;
fn parse_result(val: &[u8]) -> Self::Response;
}
pub struct GetFirmwareVersion;
impl GetFirmwareVersion {
pub fn new() -> Self {
Self
}
}
pub struct FirmwareVersion {
pub ic: u8,
pub ver: u8,
pub rev: u8,
pub support: u8,
}
impl FirmwareVersion {
pub fn version_string(&self) -> String {
format!("{}.{}", self.ver, self.rev)
}
}
impl Cmd for GetFirmwareVersion {
const NUM_BYTES: usize = 4;
type Response = FirmwareVersion;
fn request(&self) -> crate::requests::Request<0> {
crate::requests::Request::GET_FIRMWARE_VERSION
}
fn parse_result(val: &[u8]) -> FirmwareVersion {
FirmwareVersion {
ic: val[0],
ver: val[1],
rev: val[2],
support: val[3],
}
}
}
and here is the Pn532::call
function that integrates with these Command structs:
pub fn call<C: Cmd>(&mut self, cmd: C, timeout: T::Time) -> Result<C::Response, Error<I::Error>> {
let request = cmd.request();
let res = self._process((&request).into(), C::NUM_BYTES, timeout)?;
Ok(C::parse_result(&res))
}
At this moment API is really low-lewel: i.e. when you send INLIST_ONE_ISO_A_TARGET cmd you get byte slice in response, not parsed struct. And I maybe can help with it, if you want.