You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: documentation/API-GUIDELINES.md
+29-3Lines changed: 29 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,16 +15,29 @@ The following paragraphs contain additional recommendations.
15
15
16
16
## Construction and Destruction of Drivers
17
17
18
-
- Drivers take peripherals and pins via the `PeripheralRef` pattern - they don't consume peripherals/pins.
18
+
- Drivers should take peripherals via the `PeripheralRef` pattern - they don't consume peripherals directly.
19
+
- If a driver requires pins, those pins should be configured using `fn with_signal_name(self, pin: impl Peripheral<P = InputConnection> + 'd) -> Self)` or `fn with_signal_name(self, pin: impl Peripheral<P = OutputConnection> + 'd) -> Self)`
20
+
- If a driver supports multiple peripheral instances (for example, I2C0 is one such instance):
21
+
- The peripheral instance type should be positioned as the last type parameter of the driver type.
22
+
- The peripheral instance type should default to a type that supports any of the peripheral instances.
23
+
- The author is encouraged to use `crate::any_peripheral` to define the "any" peripheral instance type.
24
+
- The driver should implement a `new` constructor that automatically converts the peripheral instance into the any type, and a `new_typed` that preserves the peripheral type.
25
+
- If a driver only supports a single peripheral instance, no instance type parameter is necessary.
26
+
- If a driver implements both blocking and async operations, or only implements blocking operations, but may support asynchronous ones in the future, the driver's type signature should include a `crate::Mode` type parameter.
27
+
- By default, constructors should configure the driver for blocking mode. The driver should implement `into_async` (and a matching `into_blocking`) function that reconfigures the driver.
28
+
-`into_async` should configure the driver and/or the associated DMA channels. This most often means enabling an interrupt handler.
29
+
-`into_blocking` should undo the configuration done by `into_async`.
30
+
- The asynchronous driver implemntation should also expose the blocking methods (except for interrupt related functions).
19
31
- Consider adding a `Drop` implementation resetting the peripheral to idle state.
20
-
- Consider using a builder-like pattern for configuration which must be done during initialization.
32
+
- Consider using a builder-like pattern for driver construction.
21
33
22
34
## Interoperability
23
35
24
36
-`cfg` gated `defmt` derives and impls are added to new structs and enums.
25
37
- see [this example](https://github.com/esp-rs/esp-hal/blob/df2b7bd8472cc1d18db0d9441156575570f59bb3/esp-hal/src/spi/mod.rs#L15)
26
38
- e.g. `#[cfg_attr(feature = "defmt", derive(defmt::Format))]`
27
39
- Don't use `log::XXX!` macros directly - use the wrappers in `fmt.rs` (e.g. just `info!` instead of `log::info!` or importing `log::*`)!
40
+
- Consider implementing common ecosystem traits, like the ones in `embedded-hal` or `embassy-embedded-hal`.
28
41
29
42
## API Surface
30
43
@@ -45,6 +58,9 @@ The following paragraphs contain additional recommendations.
45
58
- For example starting a timer is fine for `&self`, worst case a timer will be started twice if two parts of the program call it. You can see a real example of this [here](https://github.com/esp-rs/esp-hal/pull/1500#pullrequestreview-2015911974)
46
59
- Maintain order consistency in the API, such as in the case of pairs like RX/TX.
47
60
- If your driver provides a way to listen for interrupts, the interrupts should be listed in a `derive(EnumSetType)` enum as opposed to one function per interrupt flag.
61
+
- If a driver only implements a subset of a peripheral's capabilities, it should be placed in the `peripheral::subcategory` module.
62
+
- For example, if a driver implements the slave-mode I2C driver, it should be placed into `i2c::slave`.
63
+
- This helps us reducing the need of introducing breaking changes if we implement additional functionalities.
48
64
49
65
## Maintainability
50
66
@@ -56,6 +72,15 @@ The following paragraphs contain additional recommendations.
56
72
- All `Future` objects (public or private) must be marked with ``#[must_use = "futures do nothing unless you `.await` or poll them"]``.
57
73
- Prefer `cfg_if!` over multiple exclusive `#[cfg]` attributes. `cfg_if!` visually divides the options, often results in simpler conditions and simplifies adding new branches in the future.
58
74
75
+
## Driver implementation
76
+
77
+
- If a common `Instance` trait is used for multiple peripherals, those traits should not have any logic implemented in them.
78
+
- The `Instance` traits should only be used to access information about a peripheral instance.
79
+
- The internal implementation of the driver should be non-generic over the peripheral instance. This helps the compiler produce smaller code.
80
+
- The author is encouraged to return a static shared reference to an `Info` and a `State` structure from the `Instance` trait.
81
+
- The `Info` struct should describe the peripheral. Do not use any interior mutability.
82
+
- The `State` struct should contain counters, wakers and other, mutable state. As this is accessed via a shared reference, interior mutability and atomic variables are preferred.
83
+
59
84
## Modules Documentation
60
85
61
86
Modules should have the following documentation format:
@@ -88,4 +113,5 @@ Modules should have the following documentation format:
- Documentation examples should be short and basic, for more complex scenarios, create an example.
116
+
- In case of referencing a TRM chapter, use the `crate::trm_markdown_link!()` macro. If you are referring to a particular chapter, you may use `crate::trm_markdown_link!("#chapter_anchor")`.
117
+
- Documentation examples should be short and basic. For more complex scenarios, create an example.
0 commit comments