samcrow / uhd-rust

Rust bindings to the UHD (USRP Hardware Driver) library
14 stars 12 forks source link

Can't build a streamer with more than 1 channel #9

Open mwk088 opened 1 year ago

mwk088 commented 1 year ago

I have been using this great repository to write my rust code for finding, probing and tasking Ettus radios. I currently have single channel working, but when I try and create a two channel stream I get uhd::runtime error stating it cannot start the stream.

Thank you, Mark

let args = uhd::StreamArgs::<Complex32>::builder()
            .wire_format("sc16".to_string())
            .channels(chan_len)
            .build();

        // Set up the data type
        let mut receiver = usrp.get_rx_stream(&args).unwrap();
        // Start the Stream
        receiver
            .send_command(&StreamCommand {
                command_type: StreamCommandType::StartContinuous,
                time: StreamTime::Now,
            })
            .into_report()
            .change_context(RadioError::RadioConfigError(format!(
                "Could not Start the Stream"
            )))
            .attach_printable(format!("Could not Start the Stream"))?;
The check_status function flags it as a runtime error.

    /// Sends a stream command to the USRP
    ///
    /// This can be used to start or stop streaming
    pub fn send_command(&mut self, command: &StreamCommand) -> Result<(), Error> {
        let command_c = command.as_c_command();
        check_status(unsafe { uhd_sys::uhd_rx_streamer_issue_stream_cmd(self.handle, &command_c) })
    }

/// Converts a status code into a result
pub(crate) fn check_status(status: uhd_sys::uhd_error::Type) -> Result<()> {
    use uhd_sys::uhd_error;
    use Error::*;
    let iserr = match status {
        uhd_error::UHD_ERROR_NONE => None,
        uhd_error::UHD_ERROR_INVALID_DEVICE => Some(InvalidDevice),
        uhd_error::UHD_ERROR_INDEX => Some(Index),
        uhd_error::UHD_ERROR_KEY => Some(Key),
        uhd_error::UHD_ERROR_NOT_IMPLEMENTED => Some(NotImplemented),
        uhd_error::UHD_ERROR_USB => Some(Usb),
        uhd_error::UHD_ERROR_IO => Some(Io),
        uhd_error::UHD_ERROR_OS => Some(Os),
        uhd_error::UHD_ERROR_ASSERTION => Some(Assertion),
        uhd_error::UHD_ERROR_LOOKUP => Some(Lookup),
        uhd_error::UHD_ERROR_TYPE => Some(Type),
        uhd_error::UHD_ERROR_VALUE => Some(Value),
        uhd_error::UHD_ERROR_RUNTIME => Some(Runtime),
        uhd_error::UHD_ERROR_ENVIRONMENT => Some(Environment),
        uhd_error::UHD_ERROR_SYSTEM => Some(System),
        uhd_error::UHD_ERROR_EXCEPT => Some(Except),
        uhd_error::UHD_ERROR_BOOSTEXCEPT => Some(BoostExcept),
        uhd_error::UHD_ERROR_STDEXCEPT => Some(StdExcept),
        uhd_error::UHD_ERROR_UNKNOWN | _ => Some(Unknown),
    };
samcrow commented 1 year ago

I don't have access to a real USRP to confirm, but I think both this issue and #8 might be caused by not setting the subdevice. The X300 series need to know which daughter board to use when there is only one channel, and probably also need to know how to map daughter boards to channels when there are multiple channels.

This library probably needs to expose uhd_usrp_set_rx_subdev_spec and the related function for transmit.

If you confirm using some example code that specifying the subdevice fixes the problem, I'll make the change. You could also add it yourself and create a pull request.

mwk088 commented 1 year ago

Thank you Sam, I will look into it this week.

Mark


From: Sam Crow @.> Sent: Saturday, July 22, 2023 11:51 AM To: samcrow/uhd-rust @.> Cc: Mark Koenig @.>; Author @.> Subject: Re: [samcrow/uhd-rust] Can't build a streamer with more than 1 channel (Issue #9)

I don't have access to a real USRP to confirm, but I think both this issue and #8https://github.com/samcrow/uhd-rust/issues/8 might be caused by not setting the subdevicehttps://files.ettus.com/manual/page_configuration.html#config_subdev. The X300 series need to know which daughter card to use when there is only one channel, and probably also need to know how to map daughter cards to channels when there are multiple channels.

This library probably needs to expose uhd_usrp_set_rx_subdev_spechttps://files.ettus.com/manual/usrp_8h.html#ae74e9cfd8ad6da42a23ac6278707a04b and the related function for transmit.

If you confirm using some example code that specifying the subdevice fixes the problem, I'll make the change. You could also add it yourself and create a pull request.

— Reply to this email directly, view it on GitHubhttps://github.com/samcrow/uhd-rust/issues/9#issuecomment-1646613812, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ANFEJUDTBUEQHL36DYYSWO3XRPZJ7ANCNFSM6AAAAAA2TG4SUA. You are receiving this because you authored the thread.Message ID: @.***>

mwk088 commented 1 year ago

I tried doing what was suggested, but am still seeing the same results(only 1 stream and NOT continuous). Below is the code I used to set the rx subdev spec. If there is anything you may see I am doing incorrectly or other steps I need to take, feel free to let me know.

Thanks

Below I am getting the subdev spec, and in my instance it is "A:0 B:0". I have also passed in "A:0" and "B:0" with with the same failing results.

let model_name = info.motherboard_id();
self.subdev_spec = info.subdev_spec().to_string().into();

Here I am making the subdev handle using the subdev spec from above

 let mut subdev_handle = ptr::null_mut();
 let markup: CString = CString::new(self.subdev_spec.as_str()).unwrap();
 unsafe { uhd_sys::uhd_subdev_spec_make(&mut subdev_handle, markup.as_ptr()) };

Here is where I set the subdev spec

usrp.set_rx_subdev_spec(subdev_handle, 0)
    .into_report()
    .change_context(RadioError::RadioConfigError(format!(
     "Could not set subdev "
        )))
       .attach_printable(format!("Could not set subdev"))?;
samcrow commented 1 year ago

The subdevice specification "A:0 B:0" looks like it should work. With the limited information and hardware I have right now, the best advice I can give is to make a simple C++ program that uses the UHD C++ APIs (or in C using the C APIs) to start streaming with multiple channels and then get the Rust code to do the same operations.