nns779/px4_drv

[PX4-W3PE4] PTX_GET_CNRからCN比を取得しようとするとENOSYSが返却される

kazuki0824 opened this issue · 3 comments

特殊設定になりますが、原因の切り分け方法が分からないため、ご質問させてください。

環境

  • Ubuntu Server 22.04
  • developブランチの最新のドライバ(7fa9f05)
  • PX4-W3PE4
  • エリアは東京都で、視聴自体は正しく行うことができる

できていること

checksignal 18 を実行した結果

device = /dev/px4video2
C/N = 30.716024dB^C

つまり、https://github.com/stz2012/recpt1 のchecksignal を使うと、
ioctl(fd, GET_SIGNAL_STRENGTH, &rc) の結果として
rcに正しいC/N比が格納されていることがわかる。

できないこと

use std::os::unix::io::AsRawFd;
nix::ioctl_write_ptr!(set_ch, 0x8d, 0x01, Freq);
nix::ioctl_none!(start_rec, 0x8d, 0x02);
nix::ioctl_none!(stop_rec, 0x8d, 0x03);
nix::ioctl_read!(ptx_get_cnr, 0x8d, 0x04, i32);
nix::ioctl_write_int!(ptx_enable_lnb, 0x8d, 0x05);
nix::ioctl_none!(ptx_disable_lnb, 0x8d, 0x06);
nix::ioctl_write_int!(ptx_set_sys_mode, 0x8d, 0x0b);

#[repr(C)]
pub struct Freq {
    pub ch: i32,
    pub slot: i32,
}

fn main() {
    let path = std::path::Path::new("/dev/px4video2");

    let freq = Freq {
        ch: 68,
        slot: 0,
    };

    let mut output = 0i32;
    let f = std::fs::OpenOptions::new().read(true).open(path).unwrap();
    let _errno = unsafe { set_ch(f.as_raw_fd(), &freq) }.unwrap();
    let _errno = unsafe { ptx_get_cnr(f.as_raw_fd(), &mut output) }.unwrap();
}

以上のプログラムをRust 1.60でコンパイルし実行すると、

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ENOSYS', src/main.rs:27:69
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

SET_CHANNELは成功するのに、
なぜかPTX_GET_CNRはENOSYSが返却されてしまう。

疑問点

  • なぜCで書かれたioctlは機能するのに、Rustからioctlを叩いたときに限ってENOSYSが返るのか
  • (Rustで書いたせいで互換性が失われた可能性はかなり低いと考えています。実際SET_CHANNELは成功していますし、START_STREAMINGとSTOP_STREAMINGも同じ方法で呼び出して正しく機能する(録画できる)ことを確認しています)
  • PTX_GET_CNRがENOSYSを返すコードパスは

    px4_drv/driver/ptx_chrdev.c

    Lines 418 to 421 in d528b9b

    if (chrdev->ops && chrdev->ops->read_cnr_raw)
    ret = chrdev->ops->read_cnr_raw(chrdev, &cn);
    else
    ret = -ENOSYS;
    しかないが、ここを通るようなことはどんな場合にあり得るのか

再現に使用したコードです
https://github.com/kazuki0824/px4_drv_cnr_test

recisdb-rs を使わせて頂こうとして checksignal が上手くいかなかった者です。
px4_drv のissueに書き込むのも違う気はするのですが、こちらの件だと思うので、ここに記載させていただきます。

px4_drv にprintk() を追記して試してみたところ、
switch(cmd) の default (ptx_chrdev.c の 518行目) を通っているために、
ENOSYS が返っているみたいです。

c も Rust も分かっているわけではないですが、
switch文の処理から c の _IOR(0x8d, 0x04, int *) と
Rust の nix::ioctl_read!(ptx_get_cnr, 0x8d, 0x04, i32) が一致しないことが原因に見えます。
%dでの出力ですが、こちらの環境では
PTX_GET_CNR が -2146923260 で
呼び出し時の cmd が -2147185404 と、異なっていました。

kernel関係もRustも全然わからないので解決策は示せないですが、参考までに。

@sakuei-ld ありがとうございます!

px4_drv/driver/ptx_chrdev.c

Lines 518 to 520 in d528b9b

default:
ret = -ENOSYS;
break;

指摘頂いた部分はノーマークでした...助かります。

switch文の処理から c の _IOR(0x8d, 0x04, int *) と
Rust の nix::ioctl_read!(ptx_get_cnr, 0x8d, 0x04, i32) が一致しないことが原因に見えます。
%dでの出力ですが、こちらの環境では
PTX_GET_CNR が -2146923260 で
呼び出し時の cmd が -2147185404 と、異なっていました。

このあたりから察するに、私の書いた
nix::ioctl_read!(ptx_get_cnr, 0x8d, 0x04, i32);
が間違いであると判断して良さそうに思いましたので、このissueは一旦クローズいたします