Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
154 lines
7.3 KiB
Rust
154 lines
7.3 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
// The rustc-cfg emitted by the build script are *not* public API.
|
|
|
|
#[path = "src/gen/build.rs"]
|
|
mod generated;
|
|
#[path = "version.rs"]
|
|
mod version;
|
|
|
|
use std::env;
|
|
|
|
use self::version::{Version, rustc_version};
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
println!("cargo:rerun-if-changed=src/gen/build.rs");
|
|
|
|
let target_arch = &*env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH not set");
|
|
|
|
let version = match rustc_version() {
|
|
Some(version) => version,
|
|
None => {
|
|
if env::var_os("SEMIHOSTING_DENY_WARNINGS").is_some() {
|
|
panic!("unable to determine rustc version")
|
|
}
|
|
println!(
|
|
"cargo:warning={}: unable to determine rustc version; assuming latest stable rustc (1.{})",
|
|
env!("CARGO_PKG_NAME"),
|
|
Version::LATEST.minor
|
|
);
|
|
Version::LATEST
|
|
}
|
|
};
|
|
|
|
if version.minor >= 80 {
|
|
// Custom cfgs set by build script. Not public API.
|
|
// grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
|
|
println!(
|
|
"cargo:rustc-check-cfg=cfg(semihosting_no_asm,semihosting_no_duration_checked_float,semihosting_no_error_in_core,semihosting_no_strict_provenance,semihosting_target_feature)"
|
|
);
|
|
// TODO: handle multi-line target_feature_fallback
|
|
// grep -F 'target_feature_fallback("' build.rs | grep -Ev '^ *//' | sed -E 's/^.*target_feature_fallback\(//; s/",.*$/"/' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
|
|
println!(
|
|
r#"cargo:rustc-check-cfg=cfg(semihosting_target_feature,values("mclass","thumb-mode"))"#
|
|
);
|
|
}
|
|
|
|
// Note that cfgs are `no_`*, not `has_*`. This allows treating as the latest
|
|
// stable rustc is used when the build script doesn't run. This is useful
|
|
// for non-cargo build systems that don't run the build script.
|
|
|
|
// duration_checked_float stabilized in Rust 1.66 (nightly-2022-10-25): https://github.com/rust-lang/rust/pull/102271
|
|
if !version.probe(66, 2022, 10, 24) {
|
|
println!("cargo:rustc-cfg=semihosting_no_duration_checked_float");
|
|
}
|
|
// error_in_core stabilized in Rust 1.81 (nightly-2024-06-09): https://github.com/rust-lang/rust/pull/125951
|
|
if !version.probe(81, 2024, 6, 8) {
|
|
println!("cargo:rustc-cfg=semihosting_no_error_in_core");
|
|
}
|
|
// strict_provenance/exposed_provenance APIs stabilized in Rust 1.84 (nightly-2024-10-22): https://github.com/rust-lang/rust/pull/130350
|
|
if !version.probe(84, 2024, 10, 21) {
|
|
println!("cargo:rustc-cfg=semihosting_no_strict_provenance");
|
|
}
|
|
|
|
match target_arch {
|
|
"arm" => {
|
|
let target = &*env::var("TARGET").expect("TARGET not set");
|
|
|
|
// https://github.com/rust-lang/rust/pull/123745 (includes https://github.com/rust-lang/cargo/pull/13560) merged in Rust 1.79 (nightly-2024-04-11).
|
|
if !version.probe(79, 2024, 4, 10) {
|
|
// HACK: If --target is specified, rustflags is not applied to the build
|
|
// script itself, so the build script will not be recompiled when rustflags
|
|
// is changed. That in itself is not a problem, but the old Cargo does
|
|
// not rerun the build script as well, which can be problematic.
|
|
// https://github.com/rust-lang/cargo/issues/13003
|
|
// This problem has been fixed in 1.79 so only older versions need a workaround.
|
|
println!("cargo:rerun-if-env-changed=CARGO_ENCODED_RUSTFLAGS");
|
|
println!("cargo:rerun-if-env-changed=RUSTFLAGS");
|
|
println!("cargo:rerun-if-env-changed=CARGO_BUILD_RUSTFLAGS");
|
|
let mut target_upper = target.replace(['-', '.'], "_");
|
|
target_upper.make_ascii_uppercase();
|
|
println!("cargo:rerun-if-env-changed=CARGO_TARGET_{target_upper}_RUSTFLAGS");
|
|
}
|
|
|
|
if needs_target_feature_fallback(&version) {
|
|
// See https://github.com/taiki-e/atomic-maybe-uninit/blob/HEAD/build.rs for details
|
|
let mut subarch =
|
|
target.strip_prefix("arm").or_else(|| target.strip_prefix("thumb")).unwrap();
|
|
subarch = subarch.strip_prefix("eb").unwrap_or(subarch); // ignore endianness
|
|
subarch = subarch.split('-').next().unwrap(); // ignore vender/os/env
|
|
subarch = subarch.split('.').next().unwrap(); // ignore .base/.main suffix
|
|
let mut mclass = false;
|
|
match subarch {
|
|
"v6m" | "v7em" | "v7m" | "v8m" => mclass = true,
|
|
_ => {}
|
|
}
|
|
target_feature_fallback("mclass", mclass);
|
|
// All builtin targets that start with "thumb" enable thumb-mode, and
|
|
// some builtin targets that start with "arm" are also enable thumb-mode.
|
|
let thumb_mode =
|
|
target.starts_with("thumb") || generated::ARM_BUT_THUMB_MODE.contains(&target);
|
|
target_feature_fallback("thumb-mode", thumb_mode);
|
|
}
|
|
}
|
|
"loongarch32" => {
|
|
// asm! on loongarch32 stabilized in Rust 1.91 (nightly-2025-08-11): https://github.com/rust-lang/rust/pull/144402
|
|
if !version.probe(91, 2025, 8, 10) {
|
|
println!("cargo:rustc-cfg=semihosting_no_asm");
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
// HACK: Currently, it seems that the only way to handle unstable target
|
|
// features on the stable is to parse the `-C target-feature` in RUSTFLAGS.
|
|
//
|
|
// - #[cfg(target_feature = "unstable_target_feature")] doesn't work on stable.
|
|
// - CARGO_CFG_TARGET_FEATURE excludes unstable target features on stable.
|
|
//
|
|
// As mentioned in the [RFC2045], unstable target features are also passed to LLVM
|
|
// (e.g., https://godbolt.org/z/4rr7rMcfG), so this hack works properly on stable.
|
|
//
|
|
// [RFC2045]: https://rust-lang.github.io/rfcs/2045-target-feature.html#backend-compilation-options
|
|
fn needs_target_feature_fallback(version: &Version) -> bool {
|
|
if version.nightly {
|
|
// In this case, cfg(target_feature = "...") would work, so skip emitting our own fallback target_feature cfg.
|
|
false
|
|
} else {
|
|
true
|
|
}
|
|
}
|
|
fn target_feature_fallback(name: &str, mut has_target_feature: bool) {
|
|
if let Some(rustflags) = env::var_os("CARGO_ENCODED_RUSTFLAGS") {
|
|
for mut flag in rustflags.to_string_lossy().split('\x1f') {
|
|
flag = flag.strip_prefix("-C").unwrap_or(flag);
|
|
if let Some(flag) = flag.strip_prefix("target-feature=") {
|
|
for s in flag.split(',') {
|
|
// TODO: Handles cases where a specific target feature
|
|
// implicitly enables another target feature.
|
|
match (s.as_bytes().first(), s.as_bytes().get(1..)) {
|
|
(Some(b'+'), Some(f)) if f == name.as_bytes() => has_target_feature = true,
|
|
(Some(b'-'), Some(f)) if f == name.as_bytes() => has_target_feature = false,
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if has_target_feature {
|
|
println!("cargo:rustc-cfg=semihosting_target_feature=\"{name}\"");
|
|
}
|
|
}
|