usb: make max interface count configurable at compile time.
This commit is contained in:
parent
4a224efe75
commit
1d841cc8ac
@ -16,6 +16,19 @@ usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
|
|||||||
msos-descriptor = []
|
msos-descriptor = []
|
||||||
default = ["usbd-hid"]
|
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]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
||||||
|
@ -1,6 +1,28 @@
|
|||||||
# embassy-usb
|
# 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
|
## 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() {
|
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 {
|
InterfaceBuilder {
|
||||||
|
@ -16,10 +16,16 @@ mod descriptor_reader;
|
|||||||
pub mod msos;
|
pub mod msos;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
mod config {
|
||||||
|
#![allow(unused)]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/config.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
pub use crate::builder::{Builder, Config};
|
pub use crate::builder::{Builder, Config};
|
||||||
|
use crate::config::*;
|
||||||
use crate::control::*;
|
use crate::control::*;
|
||||||
use crate::descriptor::*;
|
use crate::descriptor::*;
|
||||||
use crate::descriptor_reader::foreach_endpoint;
|
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.
|
/// The bConfiguration value for the single configuration supported by this device.
|
||||||
pub const CONFIGURATION_VALUE: u8 = 1;
|
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_MANUFACTURER: u8 = 1;
|
||||||
const STRING_INDEX_PRODUCT: u8 = 2;
|
const STRING_INDEX_PRODUCT: u8 = 2;
|
||||||
const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
|
const STRING_INDEX_SERIAL_NUMBER: u8 = 3;
|
||||||
|
Loading…
Reference in New Issue
Block a user