Skip to main content

board_info/
board_info.rs

1//! Prints what this binary is running on: the board, and the Bela
2//! version.
3//!
4//! The first thing to ask for from anyone reporting a problem. It
5//! brings no audio system up and touches no audio hardware, so it can
6//! be run on a board that is already doing something else, and it
7//! answers even when nothing else here works — an image whose libbela
8//! is not the one the binary was built against says so in the first two
9//! lines rather than through whatever failure that mismatch causes
10//! later.
11//!
12//! ```text
13//! board: GemStereo
14//! version: 1.18.0
15//! ```
16//!
17//! The version line names both versions when the library and the
18//! vendored headers disagree, and only the one when they do not.
19//!
20//! With `--all-modes` it asks each detect mode in turn instead, which
21//! is how the difference between them was measured. `scan` is in that
22//! list and is the one mode with a side effect: it goes out over the
23//! buses and writes `/run/bela/belaconfig`, so it needs permission to
24//! write that file and is not what a program should call routinely.
25//! It is therefore asked last, after the modes that read that file,
26//! and its line is a fresh answer to compare with what they found
27//! rather than a value they have just been handed.
28//!
29//! Cross-compile and run on the board (see docs/cross-compile.md):
30//!
31//! ```sh
32//! cargo build -p bela --release --target aarch64-unknown-linux-gnu --example board_info
33//! ```
34
35use std::process::ExitCode;
36
37#[cfg(bela_device)]
38fn main() -> ExitCode {
39    use core::iter::once;
40    use std::env::args;
41
42    use bela::{Board, DetectMode, Version};
43
44    let arguments: Vec<String> = args().skip(1).collect();
45    let all_modes = match arguments.as_slice() {
46        [] => false,
47        [flag] if flag == "--all-modes" => true,
48        _ => {
49            eprintln!(
50                "usage: board_info [--all-modes]\n\
51                 \x20 --all-modes  ask every detect mode, including the scan that writes\n\
52                 \x20              /run/bela/belaconfig"
53            );
54            return ExitCode::FAILURE;
55        }
56    };
57
58    if all_modes {
59        // Named per line, because the interesting result is the one
60        // that disagrees with the others.
61        //
62        // `Scan` goes last however `DetectMode::ALL` is ordered: it
63        // writes `/run/bela/belaconfig`, which `Cache`, `CacheOnly` and
64        // `User` read. Asking it first would leave those three
65        // reporting what this same run had just written, and four
66        // modes agreeing would say nothing about the board. Last, they
67        // report what was already on the board and the scan is a fresh
68        // answer to compare with it.
69        let scan_last = DetectMode::ALL
70            .iter()
71            .filter(|mode| **mode != DetectMode::Scan)
72            .chain(once(&DetectMode::Scan));
73        for mode in scan_last {
74            println!("board[{mode}]: {}", Board::detect(*mode));
75        }
76    } else {
77        // `Cache` rather than `Scan`: on a running board the daemon has
78        // already written the file, so this is a file read. It is not
79        // free of side effects — with no file to read it falls back to
80        // scanning, which writes one — but it is the mode that leaves
81        // a working board alone, and `CacheOnly` would answer `NoHw`
82        // on a board that simply had not been scanned yet.
83        println!("board: {}", Board::detect(DetectMode::Cache));
84    }
85
86    // Both versions on one line. They agree on a board whose image is
87    // the one the bindings were vendored from, and the whole point of
88    // printing them together is the run where they do not.
89    let running = Version::running();
90    if running == Version::HEADERS {
91        println!("version: {running}");
92    } else {
93        println!(
94            "version: {running} (this binary was built against {headers})",
95            headers = Version::HEADERS
96        );
97    }
98
99    ExitCode::SUCCESS
100}
101
102#[cfg(not(bela_device))]
103fn main() -> ExitCode {
104    eprintln!("This example must be cross-compiled for Bela Gem (aarch64-unknown-linux-gnu).");
105    ExitCode::FAILURE
106}