Skip to content

Commit d5a0b04

Browse files
authored
Add 1.75 MSRV, optimise and unit test EEPROM reader (#134)
* Allow interchangeable EEPROM data provider backends * Disable nearly all replay tests They're flaky but kinda useful as sanity checks without having to plug in loads of different hardware :( * Rename `bench-hacks` feature to `__internals` * Add `internals` module * Add `dump-eeprom` "example" to write EEPROM to stdout * Upgrade heapless, add defmt-03 feature for it * Upgrade `smoltcp` and `embassy-time` * Bump MSRV to 1.75.0 * Add rust-version 1.75 to Cargo.toml
1 parent 53142be commit d5a0b04

32 files changed

Lines changed: 1311 additions & 516 deletions

.circleci/config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ miri_steps: &miri_steps
5050
key: v5-ethercrab-{{ .Environment.CIRCLE_JOB }}-{{ checksum "Cargo.toml" }}
5151

5252
# Arbitrary nightly version - just the latest at time of writing. This can be changed freely.
53-
- run: rustup toolchain add nightly-2023-11-02 --target $TARGET --component miri
53+
- run: rustup toolchain add nightly-2023-12-25 --target $TARGET --component miri
5454
- run: |
5555
export MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-disable-isolation"
5656
57-
cargo +nightly-2023-11-02 miri test --target $TARGET
57+
cargo +nightly-2023-12-25 miri test --target $TARGET
5858
5959
- save_cache:
6060
key: v5-ethercrab-{{ .Environment.CIRCLE_JOB }}-{{ checksum "Cargo.toml" }}

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ An EtherCAT master written in Rust.
66

77
## [Unreleased] - ReleaseDate
88

9+
### Changed
10+
11+
- **(breaking)** [#134](https://github.com/ethercrab-rs/ethercrab/pull/134) Bump MSRV to 1.75.0
12+
- [#134](https://github.com/ethercrab-rs/ethercrab/pull/134) Refactor sub device EEPROM reader to be
13+
more efficient when skipping sections of the device EEPROM map.
14+
915
## [0.3.5] - 2023-12-22
1016

1117
### Changed
@@ -244,8 +250,8 @@ An EtherCAT master written in Rust.
244250
- Initial release
245251

246252
<!-- next-url -->
247-
[unreleased]: https://github.com/ethercrab-rs/ethercrab/compare/v0.3.5...HEAD
248253

254+
[unreleased]: https://github.com/ethercrab-rs/ethercrab/compare/v0.3.5...HEAD
249255
[0.3.5]: https://github.com/ethercrab-rs/ethercrab/compare/v0.3.4...v0.3.5
250256
[0.3.4]: https://github.com/ethercrab-rs/ethercrab/compare/v0.3.3...v0.3.4
251257
[0.3.3]: https://github.com/ethercrab-rs/ethercrab/compare/v0.3.2...v0.3.3

Cargo.toml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ description = "An EtherCAT master in pure Rust that is no_std compatible"
1111
keywords = ["no-std", "ethercat", "beckhoff", "igh", "soem"]
1212
exclude = ["dumps", "doc", "NOTES.md", "SPECNOTES.md"]
1313
resolver = "2"
14+
rust-version = "1.75"
1415

1516
[package.metadata.docs.rs]
1617
default-target = "x86_64-unknown-linux-gnu"
@@ -24,17 +25,18 @@ atomic_refcell = "0.1.13"
2425
bitflags = "2.4.1"
2526
defmt = { version = "0.3.5", optional = true }
2627
embassy-futures = "0.1.0"
27-
embassy-time = "0.1.5"
28+
embassy-time = "0.2.0"
29+
embedded-io-async = { version = "0.6.0", default-features = false }
2830
futures-lite = { version = "2.0.0", default-features = false }
29-
heapless = "0.7.16"
31+
heapless = "0.8.0"
3032
log = { version = "0.4.20", optional = true, default-features = false }
3133
nom = { version = "7.1.3", default-features = false }
3234
num_enum = { version = "0.7.0", default-features = false }
3335
packed_struct = { version = "0.10.1", default-features = false }
3436
sealed = "0.5.0"
3537
serde = { version = "1.0.190", features = ["derive"], optional = true }
3638
smlang = "0.6.0"
37-
smoltcp = { version = "0.10.0", default-features = false, features = [
39+
smoltcp = { version = "0.11.0", default-features = false, features = [
3840
"proto-ipv4",
3941
"socket-raw",
4042
"medium-ethernet",
@@ -74,22 +76,28 @@ tokio = { version = "1.33.0", features = [
7476
rustix = { version = "0.38.21", default-features = false, features = [
7577
"process",
7678
] }
77-
thread-priority = "0.13.1"
79+
thread-priority = "0.15.1"
7880

7981
[features]
8082
default = ["std"]
81-
defmt = ["dep:defmt", "smoltcp/defmt"]
83+
defmt = [
84+
"dep:defmt",
85+
"smoltcp/defmt",
86+
"embedded-io-async/defmt-03",
87+
"heapless/defmt-03",
88+
]
8289
log = ["dep:log"]
8390
std = [
8491
"pnet_datalink",
8592
"async-io",
8693
"smoltcp/phy-raw_socket",
8794
"log",
8895
"futures-lite/std",
96+
"embedded-io-async/std",
8997
]
9098
serde = ["dep:serde", "bitflags/serde"]
9199
# Development only - DO NOT USE
92-
bench-hacks = []
100+
__internals = []
93101

94102
[[example]]
95103
name = "akd"
@@ -111,6 +119,10 @@ required-features = ["std"]
111119
name = "multiple-groups"
112120
required-features = ["std"]
113121

122+
[[example]]
123+
name = "dump-eeprom"
124+
required-features = ["std", "__internals"]
125+
114126
[[bench]]
115127
name = "pdu_loop"
116128
harness = false

Justfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ linux-test *args:
2828
cargo test {{args}}
2929
3030
linux-bench *args:
31-
cargo bench --features bench-hacks --no-run {{args}}
31+
cargo bench --features __internals --no-run {{args}}
3232
sudo echo
3333
fd . --type executable ./target/release/deps -x sudo setcap cap_net_raw=pe
34-
cargo bench --features bench-hacks {{args}}
34+
cargo bench --features __internals {{args}}
3535

3636
generate-readme:
3737
cargo readme > README.md
@@ -40,3 +40,8 @@ generate-readme:
4040

4141
check-readme: (generate-readme)
4242
git diff --quiet --exit-code README.md
43+
44+
dump-eeprom *args:
45+
cargo build --example dump-eeprom --features "std __internals" --release && \
46+
sudo setcap cap_net_raw=pe ./target/release/examples/dump-eeprom && \
47+
./target/release/examples/dump-eeprom {{args}}

dumps/eeprom/akd.hex

1.65 KB
Binary file not shown.

dumps/eeprom/ek1100.hex

240 Bytes
Binary file not shown.

dumps/eeprom/el2828.hex

572 Bytes
Binary file not shown.

dumps/eeprom/el2889.hex

730 Bytes
Binary file not shown.

examples/dump-eeprom.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//! Dump the EEPROM of a given sub device to stdout.
2+
//!
3+
//! Requires the unstable `__internals` feature to be enabled.
4+
5+
use std::io::Write;
6+
7+
use embedded_io_async::Read;
8+
use env_logger::Env;
9+
use ethercrab::{
10+
error::Error,
11+
internals::{DeviceEeprom, EepromDataProvider, SlaveClient},
12+
std::tx_rx_task,
13+
Client, ClientConfig, PduStorage, SlaveGroupState, Timeouts,
14+
};
15+
16+
/// Maximum number of slaves that can be stored. This must be a power of 2 greater than 1.
17+
const MAX_SLAVES: usize = 16;
18+
/// Maximum PDU data payload size - set this to the max PDI size or higher.
19+
const MAX_PDU_DATA: usize = 1100;
20+
/// Maximum number of EtherCAT frames that can be in flight at any one time.
21+
const MAX_FRAMES: usize = 16;
22+
/// Maximum total PDI length.
23+
const PDI_LEN: usize = 64;
24+
25+
static PDU_STORAGE: PduStorage<MAX_FRAMES, MAX_PDU_DATA> = PduStorage::new();
26+
27+
#[tokio::main]
28+
async fn main() -> Result<(), Error> {
29+
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
30+
31+
let interface = std::env::args()
32+
.nth(1)
33+
.expect("Provide network interface as first argument.");
34+
35+
let index: u16 = std::env::args()
36+
.nth(2)
37+
.expect("Provide device index (starting from zero) as second argument.")
38+
.parse()
39+
.expect("Invalid index: must be a number");
40+
41+
log::info!(
42+
"Starting EEPROM dump tool, interface {}, device index {}",
43+
interface,
44+
index
45+
);
46+
47+
let (tx, rx, pdu_loop) = PDU_STORAGE.try_split().expect("can only split once");
48+
49+
let client = Client::new(pdu_loop, Timeouts::default(), ClientConfig::default());
50+
51+
tokio::spawn(tx_rx_task(&interface, tx, rx).expect("spawn TX/RX task"));
52+
53+
let mut group = client
54+
.init_single_group::<MAX_SLAVES, PDI_LEN>()
55+
.await
56+
.expect("Init");
57+
58+
log::info!("Discovered {} slaves", group.len());
59+
60+
for slave in group.iter(&client) {
61+
log::info!(
62+
"--> Slave {:#06x} {} {}",
63+
slave.configured_address(),
64+
slave.name(),
65+
slave.identity()
66+
);
67+
}
68+
69+
let slave = group
70+
.slave(&client, usize::from(index))
71+
.expect("Could not find device for given index");
72+
73+
log::info!(
74+
"Dumping EEPROM for device index {}: {:#06x} {} {}...",
75+
index,
76+
slave.configured_address(),
77+
slave.name(),
78+
slave.identity()
79+
);
80+
81+
let base_address = 0x1000;
82+
83+
let slave_client = SlaveClient::new(&client, base_address + index);
84+
85+
let provider = DeviceEeprom::new(&slave_client);
86+
87+
let len = provider.len().await.expect("Len");
88+
89+
log::info!("--> Device EEPROM is {} bytes long", len);
90+
91+
let mut reader = provider.reader();
92+
93+
let mut buf = vec![0u8; usize::from(len)];
94+
95+
reader.read_exact(&mut buf).await.expect("Read exact");
96+
97+
std::io::stdout().write_all(&buf[..]).expect("Stdout write");
98+
99+
log::info!("Done, wrote {} bytes", buf.len());
100+
101+
Ok(())
102+
}

examples/embassy-stm32/Cargo.toml

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,39 +19,35 @@ embedded-hal = "0.2.6"
1919
embedded-io = "0.6.0"
2020
panic-probe = { version = "0.3", features = ["print-defmt"] }
2121
static_cell = { version = "1.1", features = ["nightly"] }
22-
smoltcp = { version = "0.10.0", features = ["defmt"], default-features = false }
22+
smoltcp = { version = "0.11.0", features = ["defmt"], default-features = false }
2323

24-
embassy-sync = { version = "0.3.0", features = ["defmt"] }
25-
embassy-executor = { version = "0.3.0", features = [
26-
"nightly",
24+
embassy-sync = { version = "0.5.0", features = ["defmt"] }
25+
embassy-executor = { version = "0.4.0", features = [
2726
"arch-cortex-m",
2827
"executor-thread",
2928
"executor-interrupt",
3029
"defmt",
3130
"integrated-timers",
3231
"arch-cortex-m",
32+
# TODO: Use stable when type_alias_impl_trait is stabilised.
33+
"nightly",
3334
] }
34-
embassy-time = { version = "0.1.2", features = [
35+
embassy-time = { version = "0.2.0", features = [
3536
"defmt",
3637
"defmt-timestamp-uptime",
37-
"unstable-traits",
3838
"tick-hz-1_000_000",
3939
] }
4040
embassy-stm32 = { version = "0.1.0", features = [
41-
"nightly",
42-
"unstable-traits",
4341
"defmt",
4442
"stm32f429zi",
45-
"unstable-pac",
4643
"memory-x",
4744
"time-driver-any",
4845
] }
49-
embassy-net = { version = "0.2.0", features = [
46+
embassy-net = { version = "0.2.1", features = [
5047
"defmt",
5148
"tcp",
5249
"dhcpv4",
5350
"medium-ethernet",
54-
"nightly",
5551
] }
5652
embassy-net-driver = { version = "0.2.0", features = ["defmt"] }
5753

@@ -62,9 +58,9 @@ lto = true
6258
codegen-units = 1
6359

6460
[patch.crates-io]
65-
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
66-
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
67-
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
68-
embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
69-
embassy-net = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
70-
embassy-net-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "b6fc682117a41e8e63a9632e06da5a17f46d9ab0" }
61+
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }
62+
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }
63+
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }
64+
embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }
65+
embassy-net = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }
66+
embassy-net-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "eebfee189a592427423d3a3ad22132d59926a0e8" }

0 commit comments

Comments
 (0)