aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-02-07 20:49:10 +0100
committerDario Nieuwenhuis <[email protected]>2023-02-08 00:16:04 +0100
commit1d841cc8ac74feacc4d231958ce2c46419ae3bda (patch)
tree44dbe827369eceb661c287d2c47ea17f00878c11 /embassy-usb
parent4a224efe75c7986f5b3d8c5d6083fa17cb774f12 (diff)
usb: make max interface count configurable at compile time.
Diffstat (limited to 'embassy-usb')
-rw-r--r--embassy-usb/Cargo.toml13
-rw-r--r--embassy-usb/README.md24
-rw-r--r--embassy-usb/build.rs93
-rw-r--r--embassy-usb/gen_config.py73
-rw-r--r--embassy-usb/src/builder.rs5
-rw-r--r--embassy-usb/src/lib.rs9
6 files changed, 212 insertions, 5 deletions
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index eb9ba36f4..463e1268c 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -16,6 +16,19 @@ usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
16msos-descriptor = [] 16msos-descriptor = []
17default = ["usbd-hid"] 17default = ["usbd-hid"]
18 18
19# BEGIN AUTOGENERATED CONFIG FEATURES
20# Generated by gen_config.py. DO NOT EDIT.
21max-interface-count-1 = []
22max-interface-count-2 = []
23max-interface-count-3 = []
24max-interface-count-4 = [] # Default
25max-interface-count-5 = []
26max-interface-count-6 = []
27max-interface-count-7 = []
28max-interface-count-8 = []
29
30# END AUTOGENERATED CONFIG FEATURES
31
19[dependencies] 32[dependencies]
20embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 33embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
21embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } 34embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
diff --git a/embassy-usb/README.md b/embassy-usb/README.md
index 581c3290f..a3d45b561 100644
--- a/embassy-usb/README.md
+++ b/embassy-usb/README.md
@@ -1,6 +1,28 @@
1# embassy-usb 1# embassy-usb
2 2
3TODO crate description/ 3TODO crate description
4
5## Configuration
6
7`embassy-usb` has some configuration settings that are set at compile time, affecting sizes
8and counts of buffers.
9
10They can be set in two ways:
11
12- Via Cargo features: enable a feature like `<name>-<value>`. `name` must be in lowercase and
13use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values
14is available, check `Cargo.toml` for the list.
15- Via environment variables at build time: set the variable named `EMBASSY_USB_<value>`. For example
16`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
17Any value can be set, unlike with Cargo features.
18
19Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
20with different values, compilation fails.
21
22### `MAX_INTERFACE_COUNT`
23
24Max amount of interfaces that can be created in one device. Default: 4.
25
4 26
5## Interoperability 27## Interoperability
6 28
diff --git a/embassy-usb/build.rs b/embassy-usb/build.rs
new file mode 100644
index 000000000..524bdc2f6
--- /dev/null
+++ b/embassy-usb/build.rs
@@ -0,0 +1,93 @@
1use std::collections::HashMap;
2use std::fmt::Write;
3use std::path::PathBuf;
4use std::{env, fs};
5
6static CONFIGS: &[(&str, usize)] = &[
7 // BEGIN AUTOGENERATED CONFIG FEATURES
8 // Generated by gen_config.py. DO NOT EDIT.
9 ("MAX_INTERFACE_COUNT", 4),
10 // END AUTOGENERATED CONFIG FEATURES
11];
12
13struct ConfigState {
14 value: usize,
15 seen_feature: bool,
16 seen_env: bool,
17}
18
19fn main() {
20 let crate_name = env::var("CARGO_PKG_NAME")
21 .unwrap()
22 .to_ascii_uppercase()
23 .replace('-', "_");
24
25 // only rebuild if build.rs changed. Otherwise Cargo will rebuild if any
26 // other file changed.
27 println!("cargo:rerun-if-changed=build.rs");
28
29 // Rebuild if config envvar changed.
30 for (name, _) in CONFIGS {
31 println!("cargo:rerun-if-env-changed={crate_name}_{name}");
32 }
33
34 let mut configs = HashMap::new();
35 for (name, default) in CONFIGS {
36 configs.insert(
37 *name,
38 ConfigState {
39 value: *default,
40 seen_env: false,
41 seen_feature: false,
42 },
43 );
44 }
45
46 let prefix = format!("{crate_name}_");
47 for (var, value) in env::vars() {
48 if let Some(name) = var.strip_prefix(&prefix) {
49 let Some(cfg) = configs.get_mut(name) else {
50 panic!("Unknown env var {name}")
51 };
52
53 let Ok(value) = value.parse::<usize>() else {
54 panic!("Invalid value for env var {name}: {value}")
55 };
56
57 cfg.value = value;
58 cfg.seen_env = true;
59 }
60
61 if let Some(feature) = var.strip_prefix("CARGO_FEATURE_") {
62 if let Some(i) = feature.rfind('_') {
63 let name = &feature[..i];
64 let value = &feature[i + 1..];
65 if let Some(cfg) = configs.get_mut(name) {
66 let Ok(value) = value.parse::<usize>() else {
67 panic!("Invalid value for feature {name}: {value}")
68 };
69
70 // envvars take priority.
71 if !cfg.seen_env {
72 if cfg.seen_feature {
73 panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value);
74 }
75
76 cfg.value = value;
77 cfg.seen_feature = true;
78 }
79 }
80 }
81 }
82 }
83
84 let mut data = String::new();
85
86 for (name, cfg) in &configs {
87 writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap();
88 }
89
90 let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
91 let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
92 fs::write(out_file, data).unwrap();
93}
diff --git a/embassy-usb/gen_config.py b/embassy-usb/gen_config.py
new file mode 100644
index 000000000..55a7fa3c0
--- /dev/null
+++ b/embassy-usb/gen_config.py
@@ -0,0 +1,73 @@
1import os
2
3abspath = os.path.abspath(__file__)
4dname = os.path.dirname(abspath)
5os.chdir(dname)
6
7features = []
8
9
10def feature(name, default, min, max, pow2=None):
11 vals = set()
12 val = min
13 while val <= max:
14 vals.add(val)
15 if pow2 == True or (isinstance(pow2, int) and val >= pow2):
16 val *= 2
17 else:
18 val += 1
19 vals.add(default)
20
21 features.append(
22 {
23 "name": name,
24 "default": default,
25 "vals": sorted(list(vals)),
26 }
27 )
28
29
30feature("max_interface_count", default=4, min=1, max=8)
31
32# ========= Update Cargo.toml
33
34things = ""
35for f in features:
36 name = f["name"].replace("_", "-")
37 for val in f["vals"]:
38 things += f"{name}-{val} = []"
39 if val == f["default"]:
40 things += " # Default"
41 things += "\n"
42 things += "\n"
43
44SEPARATOR_START = "# BEGIN AUTOGENERATED CONFIG FEATURES\n"
45SEPARATOR_END = "# END AUTOGENERATED CONFIG FEATURES\n"
46HELP = "# Generated by gen_config.py. DO NOT EDIT.\n"
47with open("Cargo.toml", "r") as f:
48 data = f.read()
49before, data = data.split(SEPARATOR_START, maxsplit=1)
50_, after = data.split(SEPARATOR_END, maxsplit=1)
51data = before + SEPARATOR_START + HELP + things + SEPARATOR_END + after
52with open("Cargo.toml", "w") as f:
53 f.write(data)
54
55
56# ========= Update build.rs
57
58things = ""
59for f in features:
60 name = f["name"].upper()
61 things += f' ("{name}", {f["default"]}),\n'
62
63SEPARATOR_START = "// BEGIN AUTOGENERATED CONFIG FEATURES\n"
64SEPARATOR_END = "// END AUTOGENERATED CONFIG FEATURES\n"
65HELP = " // Generated by gen_config.py. DO NOT EDIT.\n"
66with open("build.rs", "r") as f:
67 data = f.read()
68before, data = data.split(SEPARATOR_START, maxsplit=1)
69_, after = data.split(SEPARATOR_END, maxsplit=1)
70data = before + SEPARATOR_START + HELP + \
71 things + " " + SEPARATOR_END + after
72with open("build.rs", "w") as f:
73 f.write(data)
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index d1cbf674b..d89fc4017 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -308,7 +308,10 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
308 }; 308 };
309 309
310 if self.builder.interfaces.push(iface).is_err() { 310 if self.builder.interfaces.push(iface).is_err() {
311 panic!("max interface count reached") 311 panic!(
312 "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
313 MAX_INTERFACE_COUNT
314 )
312 } 315 }
313 316
314 InterfaceBuilder { 317 InterfaceBuilder {
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index aec18524b..f8983318e 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -16,10 +16,16 @@ mod descriptor_reader;
16pub mod msos; 16pub mod msos;
17pub mod types; 17pub mod types;
18 18
19mod config {
20 #![allow(unused)]
21 include!(concat!(env!("OUT_DIR"), "/config.rs"));
22}
23
19use embassy_futures::select::{select, Either}; 24use embassy_futures::select::{select, Either};
20use heapless::Vec; 25use heapless::Vec;
21 26
22pub use crate::builder::{Builder, Config}; 27pub use crate::builder::{Builder, Config};
28use crate::config::*;
23use crate::control::*; 29use crate::control::*;
24use crate::descriptor::*; 30use crate::descriptor::*;
25use crate::descriptor_reader::foreach_endpoint; 31use crate::descriptor_reader::foreach_endpoint;
@@ -71,9 +77,6 @@ pub const CONFIGURATION_NONE: u8 = 0;
71/// The bConfiguration value for the single configuration supported by this device. 77/// The bConfiguration value for the single configuration supported by this device.
72pub const CONFIGURATION_VALUE: u8 = 1; 78pub const CONFIGURATION_VALUE: u8 = 1;
73 79
74/// Maximum interface count, configured at compile time.
75pub const MAX_INTERFACE_COUNT: usize = 4;
76
77const STRING_INDEX_MANUFACTURER: u8 = 1; 80const STRING_INDEX_MANUFACTURER: u8 = 1;
78const STRING_INDEX_PRODUCT: u8 = 2; 81const STRING_INDEX_PRODUCT: u8 = 2;
79const STRING_INDEX_SERIAL_NUMBER: u8 = 3; 82const STRING_INDEX_SERIAL_NUMBER: u8 = 3;