e-tipsmemo

ごった煮

libiio rust binding for Windows

前置き

ADALM PLUTOからデータをもらうのに、用意されている方法として、Industrial-ioを使用する方法がある。
Linux Industrial I/O Subsystem [Analog Devices Wiki]

組み込み機器が得たデータを簡単にPCとやり取りできる。
(組み込み機器上でLinuxが動いていたら簡単、Busyboxも可、ベアメタルではなさそう。)
物理層をラップしてくれる(速度の問題はあると思うが)

Windowsのドライバもあって、コマンドで簡単に接続を確認できる。
f:id:katakanan:20210516221649p:plain
これを利用している測定器が、
ADALM2000 評価用ボード | アナログ・デバイセズ

PythonC#バインディングがった。
RustではLinux向けにはあったが、Windowsでは動かなかった。
そこでdllをダイナミックにロードするcrateを使用してWindowsで動くように変更した。

但し、前回動作を確認したdlopenは使用せず、windows-dllを使用したところ、より簡単に実現できた。
https://github.com/katakanan/rust-industrial-io

本当はConditional Compilationを利用して、linux向けにもビルドできるようにもしたかったが、nix crateに依存していて、これに対応するWindowsの動作が分からなかったので、
それっぽく置き換えて、とりあえずWindowsだけでビルドできるようにした。

サンプルコード

autodetectでbackendを指定しなければ、接続方法に関わらず、接続方法を列挙する。(iio_info -sと同じ)

#[test]
fn autodetect() {
    let _ = iio::Context::autodetect_context(false, "", "");
}

####

backendを指定して、見つかったものが1つだと接続できる。
名前とdescriptionを得る。

#[test]
fn usb_scan() {
    let scan = "usb";
    let ctx = iio::Context::autodetect_context(true, "", scan).unwrap_or_else(|err| {
        eprintln!("Error find {} context: {}", scan, err);
        std::process::exit(1);
    });

    println!("{}", ctx.name());
    println!("{}", ctx.description());
}
running 1 test
Using auto-detected IIO context at URI
usb
Linux (none) 5.4.0-212055-gb05d16429dac #403 SMP PREEMPT Tue Mar 30 12:57:31 CEST 2021 armv7l
test usb_scan ... ok

対象の機器のデバイスから電圧データを得る

バイスというのは1個の機器に対してぶら下がっているコントロールされる個々の機能だと思う
DDSとかphyとかADC..etc
(iio_attr -u usb:x.xx.x -s -B で分かる)

fn main() {
    println!("Hello, world!");
    let scan = "usb";
    let ctx = iio::Context::autodetect_context(true, "", scan).unwrap_or_else(|err| {
        eprintln!("Error find {} context: {}", scan, err);
        std::process::exit(1);
    });

    let dev = ctx.get_device(0).unwrap_or_else(|err| {
        eprintln!("Error opening first device: {}", err);
        std::process::exit(1);
    });

    let unknown = "unknown".to_string();
    let tick = periodic(Duration::from_millis(1000));

    println!("Device: {}", dev.name().unwrap_or_else(|| unknown.clone()));

    for chan in dev.channels() {
        if chan.has_attr("raw") {
            print!(" {:>9}", chan.id().unwrap_or_else(|| unknown.clone()));
        }
    }
    println!();

    loop {
        tick.recv().unwrap();
        for chan in dev.channels() {
            if let Ok(val) = chan.attr_read_int("raw") {
                print!(" {:>8} ", val);
            }
        }
        println!();
    }
}
Hello, world!
Using auto-detected IIO context at URI
Device: ad9361-phy
  voltage3  voltage2  voltage2
      306       306      1523 
      306       306      1520 
      306       306      1517 
      306       306      1518 
      306       306      1518 
      306       306      1524 
      306       306      1520 
      306       306      1522 
error: process didn't exit successfully: `target\debug\readpluto.exe` (exit code: 0xc000013a, STATUS_CONTROL_C_EXIT)

どこかの電圧を連続で読み取る。

うまくいっているようだ。