Repository: google/OpenSK
File: third_party/libtock-drivers/src/nfc.rs (Rust)

Code before:
    pub const RECEIVE: usize = 2;
}

#[allow(dead_code)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Subscribe to the tag being SELECTED callback.
    pub fn selected() -> bool {
        let is_selected = Cell::new(false);
        let mut is_selected_alarm = || is_selected.set(true);
        let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SELECT,
            &mut is_selected_alarm,
        );
        if subscription.is_err() {
            return false;
        }

        util::yieldk_for(|| is_selected.get());
        true
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// Set the maximum frame delay value to support transmission with the reader.
    pub fn set_framedelaymax(delay: u32) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::FRAMEDELAYMAX, delay as usize, 0).is_ok()
    }


Review comment (suggestion):
This function will be blocking until the tag gets selected. I guess from the CTAP2 point of view, that's going to be a problematic behavior because we won't be able to receive packets from USB if we call this function.
@kaczmarczyck and @gendx  WDYT?
I have the impression that this function (as the documentation says) should only take a callback function as a parameter, issue the syscall and returns whether the subscription succeeded or not. The `yield_for` belongs to CTAP2 logic to be able to multiplex the transport channels (NFC, USB and maybe BLE at some point).
Otherwise we have to add the notion of timeouts like in USB but it means we need to poll sequentially USB and NFC which can lead to timing problems.
Last alternative would be to do the multiplexing directly in a capsule and then there's 1 single point to receive command (the capsule would probably need to tag the received packet/frame with the channel it came from for parsing/routing it properly)

Code after:
}

#[allow(dead_code)]
#[derive(Clone, Copy)]
pub struct RecvOp {
    pub result_code: usize,
    pub recv_amount: usize,
}

pub struct NfcTag {}

impl NfcTag {
    /// Check the existence of an NFC driver.
    pub fn setup() -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0).is_ok()
    }

    pub fn enable_emulation() -> bool {
        NfcTag::emulate(true)
    }

    pub fn disable_emulation() -> bool {
        NfcTag::emulate(false)
    }

    fn emulate(enabled: bool) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0).is_ok()
    }

    /// Configure the tag type command.
    pub fn configure(tag_type: u8) -> bool {
        syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0).is_ok()
    }

    /// 1. Share with the driver a buffer.
    /// 2. Subscribe to having a successful receive callback.
    /// 3. Issue the request for reception.
    pub fn receive(buf: &mut [u8; 256]) -> TockResult<RecvOp> {
        let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
        // set callback with 2 arguments, to receive ReturnCode and RX Amount
        let recv_data = Cell::new(None);
        let mut callback = |result, amount| {
            recv_data.set(Some(RecvOp {
                result_code: result,
                recv_amount: amount,
            }))
        };
        let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::RECEIVE,
            &mut callback,