usb: make max interface count configurable at compile time.
This commit is contained in:
parent
4a224efe75
commit
1d841cc8ac
6 changed files with 212 additions and 5 deletions
|
@ -16,6 +16,19 @@ usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
|
|||
msos-descriptor = []
|
||||
default = ["usbd-hid"]
|
||||
|
||||
# BEGIN AUTOGENERATED CONFIG FEATURES
|
||||
# Generated by gen_config.py. DO NOT EDIT.
|
||||
max-interface-count-1 = []
|
||||
max-interface-count-2 = []
|
||||
max-interface-count-3 = []
|
||||
max-interface-count-4 = [] # Default
|
||||
max-interface-count-5 = []
|
||||
max-interface-count-6 = []
|
||||
max-interface-count-7 = []
|
||||
max-interface-count-8 = []
|
||||
|
||||
# END AUTOGENERATED CONFIG FEATURES
|
||||
|
||||
[dependencies]
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
||||
|
|
|
@ -1,6 +1,28 @@
|
|||
# embassy-usb
|
||||
|
||||
TODO crate description/
|
||||
TODO crate description
|
||||
|
||||
## Configuration
|
||||
|
||||
`embassy-usb` has some configuration settings that are set at compile time, affecting sizes
|
||||
and counts of buffers.
|
||||
|
||||
They can be set in two ways:
|
||||
|
||||
- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and
|
||||
use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values
|
||||
is available, check `Cargo.toml` for the list.
|
||||
- Via environment variables at build time: set the variable named `EMBASSY_USB_<value>`. For example
|
||||
`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
|
||||
Any value can be set, unlike with Cargo features.
|
||||
|
||||
Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
|
||||
with different values, compilation fails.
|
||||
|
||||
### `MAX_INTERFACE_COUNT`
|
||||
|
||||
Max amount of interfaces that can be created in one device. Default: 4.
|
||||
|
||||
|
||||
## Interoperability
|
||||
|
||||
|
|
93
embassy-usb/build.rs
Normal file
93
embassy-usb/build.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
static CONFIGS: &[(&str, usize)] = &[
|
||||
// BEGIN AUTOGENERATED CONFIG FEATURES
|
||||
// Generated by gen_config.py. DO NOT EDIT.
|
||||
("MAX_INTERFACE_COUNT", 4),
|
||||
// END AUTOGENERATED CONFIG FEATURES
|
||||
];
|
||||
|
||||
struct ConfigState {
|
||||
value: usize,
|
||||
seen_feature: bool,
|
||||
seen_env: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let crate_name = env::var("CARGO_PKG_NAME")
|
||||
.unwrap()
|
||||
.to_ascii_uppercase()
|
||||
.replace('-', "_");
|
||||
|
||||
// only rebuild if build.rs changed. Otherwise Cargo will rebuild if any
|
||||
// other file changed.
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
// Rebuild if config envvar changed.
|
||||
for (name, _) in CONFIGS {
|
||||
println!("cargo:rerun-if-env-changed={crate_name}_{name}");
|
||||
}
|
||||
|
||||
let mut configs = HashMap::new();
|
||||
for (name, default) in CONFIGS {
|
||||
configs.insert(
|
||||
*name,
|
||||
ConfigState {
|
||||
value: *default,
|
||||
seen_env: false,
|
||||
seen_feature: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let prefix = format!("{crate_name}_");
|
||||
for (var, value) in env::vars() {
|
||||
if let Some(name) = var.strip_prefix(&prefix) {
|
||||
let Some(cfg) = configs.get_mut(name) else {
|
||||
panic!("Unknown env var {name}")
|
||||
};
|
||||
|
||||
let Ok(value) = value.parse::<usize>() else {
|
||||
panic!("Invalid value for env var {name}: {value}")
|
||||
};
|
||||
|
||||
cfg.value = value;
|
||||
cfg.seen_env = true;
|
||||
}
|
||||
|
||||
if let Some(feature) = var.strip_prefix("CARGO_FEATURE_") {
|
||||
if let Some(i) = feature.rfind('_') {
|
||||
let name = &feature[..i];
|
||||
let value = &feature[i + 1..];
|
||||
if let Some(cfg) = configs.get_mut(name) {
|
||||
let Ok(value) = value.parse::<usize>() else {
|
||||
panic!("Invalid value for feature {name}: {value}")
|
||||
};
|
||||
|
||||
// envvars take priority.
|
||||
if !cfg.seen_env {
|
||||
if cfg.seen_feature {
|
||||
panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value);
|
||||
}
|
||||
|
||||
cfg.value = value;
|
||||
cfg.seen_feature = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut data = String::new();
|
||||
|
||||
for (name, cfg) in &configs {
|
||||
writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap();
|
||||
}
|
||||
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
|
||||
fs::write(out_file, data).unwrap();
|
||||
}
|
73
embassy-usb/gen_config.py
Normal file
73
embassy-usb/gen_config.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
import os
|
||||
|
||||
abspath = os.path.abspath(__file__)
|
||||
dname = os.path.dirname(abspath)
|
||||
os.chdir(dname)
|
||||
|
||||
features = []
|
||||
|
||||
|
||||
def feature(name, default, min, max, pow2=None):
|
||||
vals = set()
|
||||
val = min
|
||||
while val <= max:
|
||||
vals.add(val)
|
||||
if pow2 == True or (isinstance(pow2, int) and val >= pow2):
|
||||
val *= 2
|
||||
else:
|
||||
val += 1
|
||||
vals.add(default)
|
||||
|
||||
features.append(
|
||||
{
|
||||
"name": name,
|
||||
"default": default,
|
||||
"vals": sorted(list(vals)),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
feature("max_interface_count", default=4, min=1, max=8)
|
||||
|
||||
# ========= Update Cargo.toml
|
||||
|
||||
things = ""
|
||||
for f in features:
|
||||
name = f["name"].replace("_", "-")
|
||||
for val in f["vals"]:
|
||||
things += f"{name}-{val} = []"
|
||||
if val == f["default"]:
|
||||
things += " # Default"
|
||||
things += "\n"
|
||||
things += "\n"
|
||||
|
||||
SEPARATOR_START = "# BEGIN AUTOGENERATED CONFIG FEATURES\n"
|
||||
SEPARATOR_END = "# END AUTOGENERATED CONFIG FEATURES\n"
|
||||
HELP = "# Generated by gen_config.py. DO NOT EDIT.\n"
|
||||
with open("Cargo.toml", "r") as f:
|
||||
data = f.read()
|
||||
before, data = data.split(SEPARATOR_START, maxsplit=1)
|
||||
_, after = data.split(SEPARATOR_END, maxsplit=1)
|
||||
data = before + SEPARATOR_START + HELP + things + SEPARATOR_END + after
|
||||
with open("Cargo.toml", "w") as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
# ========= Update build.rs
|
||||
|
||||
things = ""
|
||||
for f in features:
|
||||
name = f["name"].upper()
|
||||
things += f' ("{name}", {f["default"]}),\n'
|
||||
|
||||
SEPARATOR_START = "// BEGIN AUTOGENERATED CONFIG FEATURES\n"
|
||||
SEPARATOR_END = "// END AUTOGENERATED CONFIG FEATURES\n"
|
||||
HELP = " // Generated by gen_config.py. DO NOT EDIT.\n"
|
||||
with open("build.rs", "r") as f:
|
||||
data = f.read()
|
||||
before, data = data.split(SEPARATOR_START, maxsplit=1)
|
||||
_, after = data.split(SEPARATOR_END, maxsplit=1)
|
||||
data = before + SEPARATOR_START + HELP + \
|
||||
things + " " + SEPARATOR_END + after
|
||||
with open("build.rs", "w") as f:
|
||||
f.write(data)
|
|
@ -308,7 +308,10 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
|
|||
};
|
||||
|
||||
if self.builder.interfaces.push(iface).is_err() {
|
||||
panic!("max interface count reached")
|
||||
panic!(
|
||||
"embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
|
||||
MAX_INTERFACE_COUNT
|
||||
)
|
||||
}
|
||||
|
||||
InterfaceBuilder {
|
||||
|
|
|
@ -16,10 +16,16 @@ mod descriptor_reader;
|
|||
pub mod msos;
|
||||
pub mod types;
|
||||
|
||||
mod config {
|
||||
#![allow(unused)]
|
||||
include!(concat!(env!("OUT_DIR"), "/config.rs"));
|
||||
}
|
||||
|
||||
use embassy_futures::select::{select, Either};
|
||||
use heapless::Vec;
|
||||
|
||||
pub use crate::builder::{Builder, Config};
|
||||
use crate::config::*;
|
||||
use crate::control::*;
|
||||
use crate::descriptor::*;
|
||||
use crate::descriptor_reader::foreach_endpoint;
|
||||
|
@ -71,9 +77,6 @@ pub const CONFIGURATION_NONE: u8 = 0;
|
|||
/// The bConfiguration value for the single configuration supported by this device.
|
||||
pub const CONFIGURATION_VALUE: u8 = 1;
|
||||
|
||||
/// Maximum interface count, configured at compile time.
|
||||
pub const MAX_INTERFACE_COUNT: usize = 4;
|
||||
|
||||
const STRING_INDEX_MANUFACTURER: u8 = 1;
|
||||
const STRING_INDEX_PRODUCT: u8 = 2;
|
||||
const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
|
||||
|
|
Loading…
Reference in a new issue