Skip to content

Commit 5fc9add

Browse files
committed
xcp_client improvements and clock test
1 parent c4e78dd commit 5fc9add

12 files changed

+139
-49
lines changed

Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ thiserror = "1.0.64"
9090
# Command line parser
9191
clap = { version = "4.5.9", features = ["derive"] }
9292

93-
# Raw FFI bindings to platform libraries like libc
93+
# Raw FFI bindings to platform libraries
94+
# For XcpLite
9495
libc = "0.2.153"
9596

9697
# A macro to generate structures which behave like bitflags
@@ -145,7 +146,7 @@ tokio = { version = "1.37.0", features = ["full"] }
145146
a2lfile = { version="2.2.0", optional = false}
146147
xcp_client = { path = "xcp_client" }
147148

148-
# dependencies for rayon demo example
149+
# dependencies for point_cloud example
149150
cdr = "0.2.4"
150151

151152
# dependencies for rayon demo example

benches/xcp_benchmark.rs

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ async fn xcp_client(dest_addr: std::net::SocketAddr, local_addr: std::net::Socke
131131
xcp_client.create_measurement_object("signal7").expect("measurement signal not found");
132132
xcp_client.create_measurement_object("signal8").expect("measurement signal not found");
133133
// Measure start
134+
xcp_client.init_measurement().await.unwrap();
134135
xcp_client.start_measurement().await.expect("could not start measurement");
135136
}
136137

src/xcp/cal/cal_seg.rs

+18-17
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ macro_rules! calseg_field {
109109
// Calibration parameter page wrapper for T with modification counter, init and freeze requests
110110

111111
#[derive(Debug, Copy, Clone)]
112-
struct CalPage<T: Sized + Send + Sync + Copy + Clone + 'static> {
112+
struct CalPage<T: CalPageTrait> {
113113
ctr: u16,
114114
init_request: bool,
115115
freeze_request: bool,
@@ -155,7 +155,7 @@ impl<T> CalPageTrait for T where T: Sized + Send + Sync + Copy + Clone + 'static
155155
#[derive(Debug)]
156156
pub struct CalSeg<T>
157157
where
158-
T: Sized + Send + Sync + Copy + Clone + 'static,
158+
T: CalPageTrait,
159159
{
160160
index: usize,
161161
default_page: &'static T,
@@ -167,7 +167,7 @@ where
167167
// Impl register_fields for types which implement RegisterFieldsTrait
168168
impl<T> CalSeg<T>
169169
where
170-
T: RegisterFieldsTrait,
170+
T: CalPageTrait + RegisterFieldsTrait,
171171
{
172172
/// Register all fields of a calibration segment in the registry
173173
/// Requires the calibration page to implement XcpTypeDescription
@@ -181,7 +181,7 @@ where
181181
#[cfg(feature = "serde")]
182182
impl<T> CalSeg<T>
183183
where
184-
T: Sized + Send + Sync + Copy + Clone + 'static + serde::Serialize + serde::de::DeserializeOwned,
184+
T: CalPageTrait,
185185
{
186186
/// Load a calibration segment from json file
187187
/// Requires the calibration page type to implement serde::Serialize + serde::de::DeserializeOwned
@@ -313,7 +313,7 @@ where
313313

314314
let file = std::fs::File::create(path).unwrap();
315315
let mut writer = std::io::BufWriter::new(file);
316-
let s = serde_json::to_string(&self.xcp_page.lock().page)
316+
let s = serde_json::to_string(&xcp_page.page)
317317
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("serde_json::to_string failed: {}", e)))
318318
.unwrap();
319319
std::io::Write::write_all(&mut writer, s.as_ref()).unwrap();
@@ -399,7 +399,7 @@ where
399399

400400
impl<T> CalSegTrait for CalSeg<T>
401401
where
402-
T: Sized + Send + Sync + Copy + Clone + 'static,
402+
T: CalPageTrait,
403403
{
404404
fn get_name(&self) -> &'static str {
405405
Xcp::get().get_calseg_name(self.index)
@@ -463,7 +463,7 @@ where
463463

464464
impl<T> Deref for CalSeg<T>
465465
where
466-
T: Sized + Send + Sync + Copy + Clone + 'static,
466+
T: CalPageTrait,
467467
{
468468
type Target = T;
469469

@@ -484,7 +484,7 @@ where
484484
// This is undefined behaviour, because the reference to XCP data page will escape from its mutex
485485
impl<T> std::ops::DerefMut for CalSeg<T>
486486
where
487-
T: Sized + Send + Sync + Copy + Clone + 'static,
487+
T: CalPageTrait,
488488
{
489489
fn deref_mut(&mut self) -> &mut Self::Target {
490490
warn!("Unsafe deref mut to XCP page of {}, this is undefined behaviour !!", self.get_name());
@@ -500,7 +500,7 @@ where
500500

501501
impl<T> Clone for CalSeg<T>
502502
where
503-
T: Sized + Send + Sync + Copy + Clone + 'static,
503+
T: CalPageTrait,
504504
{
505505
fn clone(&self) -> Self {
506506
CalSeg {
@@ -519,7 +519,7 @@ where
519519

520520
// impl<T> Drop for CalSeg<T>
521521
// where
522-
// T: Sized + Send + Sync + Copy + Clone + 'static,
522+
// T: CalPageTrait,
523523
// {
524524
// fn drop(&mut self) {
525525
// let clone_count = self.get_clone_count();
@@ -546,7 +546,7 @@ where
546546
/// Send is reimplemented here
547547
/// Sync stays disabled, because this would allow to call calseg.sync() from multiple threads with references to the same CalSeg
548548
// @@@@ unsafe - Implementation of Send marker for CalSeg
549-
unsafe impl<T> Send for CalSeg<T> where T: Sized + Send + Sync + Copy + Clone + 'static {}
549+
unsafe impl<T> Send for CalSeg<T> where T: CalPageTrait {}
550550

551551
//----------------------------------------------------------------------------------------------
552552
// Test
@@ -592,11 +592,13 @@ mod cal_tests {
592592
Ok(())
593593
}
594594

595+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
595596
#[derive(Debug, Clone, Copy)]
596597
struct CalPage0 {
597598
stop: u8,
598599
}
599600

601+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
600602
#[derive(Debug, Clone, Copy, XcpTypeDescription)]
601603
struct CalPageTest {
602604
test: u8,
@@ -774,7 +776,7 @@ mod cal_tests {
774776
save(&mut_page, "test_cal_seg.json").unwrap();
775777

776778
// Create a cal_seg with a mut_page from file test_cal_seg.json aka CAL_PAR_RAM, and a default page from CAL_PAR_FLASH
777-
let mut cal_seg = xcp.create_calseg("test_cal_seg", &CAL_PAR_FLASH);
779+
let cal_seg = xcp.create_calseg("test_cal_seg", &CAL_PAR_FLASH);
778780
cal_seg.load("test_cal_seg.json").unwrap();
779781

780782
let cal_seg1 = cal_seg.clone();
@@ -855,7 +857,7 @@ mod cal_tests {
855857
let mut_page: CalPage2 = CalPage2 { a: 1, b: 3, c: 5 };
856858
save(&mut_page, "test1.json").unwrap();
857859
save(&mut_page, "test2.json").unwrap();
858-
let mut cal_seg = xcp.create_calseg("test1", &FLASH_PAGE2);
860+
let cal_seg = xcp.create_calseg("test1", &FLASH_PAGE2);
859861
cal_seg.load("test1.json").unwrap();
860862
cal_seg.sync();
861863
assert_eq!(xcp.get_ecu_cal_page(), XcpCalPage::Ram, "XCP should be on RAM page here, there is no independant page switching yet");
@@ -886,11 +888,10 @@ mod cal_tests {
886888

887889
//-----------------------------------------------------------------------------
888890
// Test cal page freeze
889-
890891
#[cfg(feature = "serde")]
891892
#[test]
892893
fn test_cal_page_freeze() {
893-
let xcp = xcp_test::test_setup(log::LevelFilter::Warn);
894+
let xcp = xcp_test::test_setup(log::LevelFilter::Info);
894895

895896
assert!(std::mem::size_of::<CalPage1>() == 12);
896897
assert!(std::mem::size_of::<CalPage2>() == 12);
@@ -900,7 +901,7 @@ mod cal_tests {
900901
save(&mut_page1, "test1.json").unwrap();
901902

902903
// Create calseg1 from def
903-
let mut calseg1 = xcp.create_calseg("test1", &FLASH_PAGE1);
904+
let calseg1 = xcp.create_calseg("test1", &FLASH_PAGE1);
904905
calseg1.load("test1.json").unwrap();
905906

906907
test_is_mut!(calseg1);
@@ -912,7 +913,7 @@ mod cal_tests {
912913

913914
// Create calseg2 from freeze file test1.json of calseg1
914915
std::fs::copy("test1.json", "test2.json").unwrap();
915-
let mut calseg2 = xcp.create_calseg("test2", &FLASH_PAGE2);
916+
let calseg2 = xcp.create_calseg("test2", &FLASH_PAGE2);
916917
calseg2.load("test2.json").unwrap();
917918

918919
test_is_mut!(calseg2);

tests/test_tokio_multi_thread.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ async fn task(index: usize, cal_seg: CalSeg<CalPage1>) {
276276
//-----------------------------------------------------------------------------
277277
// Integration test multi thread measurememt and calibration
278278

279-
#[ignore]
279+
//#[ignore]
280280
#[tokio::test]
281281
async fn test_tokio_multi_thread() {
282282
env_logger::Builder::new()

tests/test_tokio_single_thread.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn task(cal_seg: CalSeg<CalPage1>) {
145145
//-----------------------------------------------------------------------------
146146
// Integration test single thread measurement and calibration
147147

148-
#[ignore]
148+
//#[ignore]
149149
#[tokio::test]
150150
async fn test_tokio_single_thread() {
151151
env_logger::Builder::new()

tests/xcp_test_executor.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ impl XcpTextDecoder for ServTextDecoder {
6464

6565
#[derive(Debug, Clone, Copy)]
6666
struct DaqDecoder {
67+
timestamp_resolution: u64,
6768
tot_events: u32,
6869
packets_lost: u32,
6970
counter_errors: u32,
@@ -78,6 +79,7 @@ struct DaqDecoder {
7879
impl DaqDecoder {
7980
pub fn new() -> DaqDecoder {
8081
DaqDecoder {
82+
timestamp_resolution: 1,
8183
tot_events: 0,
8284
packets_lost: 0,
8385
counter_errors: 0,
@@ -107,6 +109,11 @@ impl XcpDaqDecoder for DaqDecoder {
107109
}
108110
}
109111

112+
// Set timestamp resolution
113+
fn set_timestamp_resolution(&mut self, timestamp_resolution: u64) {
114+
self.timestamp_resolution = timestamp_resolution;
115+
}
116+
110117
// Handle incomming DAQ DTOs from XCP server
111118
fn decode(&mut self, lost: u32, daq: u16, odt: u8, timestamp: u32, data: &[u8]) {
112119
assert!(daq < MULTI_THREAD_TASK_COUNT as u16);
@@ -120,7 +127,7 @@ impl XcpDaqDecoder for DaqDecoder {
120127
self.daq_max = daq;
121128
}
122129

123-
// Decode time as u64
130+
// Decode raw timestamp as u64
124131
// Check declining timestamps
125132
if odt == 0 {
126133
let t_last = self.daq_timestamp[daq as usize];
@@ -325,7 +332,6 @@ pub async fn xcp_test_executor(xcp: &Xcp, test_mode_cal: TestModeCal, test_mode_
325332
// DAQ test single_thread or multi_thread
326333
if test_mode_daq == TestModeDaq::SingleThreadDAQ || test_mode_daq == TestModeDaq::MultiThreadDAQ {
327334
tokio::time::sleep(Duration::from_micros(10000)).await;
328-
info!("Start data acquisition test");
329335

330336
// Create a calibration object for CalPage1.counter_max
331337
// Set counter_max to 15
@@ -339,6 +345,21 @@ pub async fn xcp_test_executor(xcp: &Xcp, test_mode_cal: TestModeCal, test_mode_
339345
// Set cycle time
340346
xcp_client.set_value_u64(cycle_time_us, DAQ_TEST_TASK_SLEEP_TIME_US).await.unwrap();
341347

348+
// Check the DAQ clock
349+
info!("Start clock test");
350+
let t10 = Instant::now();
351+
let t1 = xcp_client.get_daq_clock().await.unwrap();
352+
tokio::time::sleep(Duration::from_micros(1000)).await;
353+
let t20 = t10.elapsed();
354+
let t2 = xcp_client.get_daq_clock().await.unwrap();
355+
let dt12 = (t2 - t1) / 1000;
356+
let dt120 = t20.as_micros() as u64;
357+
info!("t1 = {}ns, t2 = {}ns, dt={}us / elapsed={}us", t1, t2, dt12, dt120);
358+
assert!(dt12 > dt120 - 100, "DAQ clock too slow");
359+
assert!(dt12 < dt120 + 100, "DAQ clock too fast");
360+
361+
info!("Start data acquisition test");
362+
342363
// Measurement test loop
343364
// Create a measurement DAQ list with all instances MULTI_THREAD_TASK_COUNT of measurement counter and counter_max
344365
// Hard coded order and size in DaqDecoder (counter_max, counter, cal_test, ...)

xcp_client/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ Using tokio and a2lfile.
3333

3434
// Measurement
3535
// Create a measurement for signal counter:u32
36+
xcp_client.init_measurement().await?;
3637
xcp_client.create_measurement_object("counter").await?;
3738
xcp_client.start_measurement().await?;
38-
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
39+
sleep(Duration::from_secs(1)).await;
3940
xcp_client.stop_measurement().await?;
4041

4142
// Disconnect

xcp_client/src/main.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const MAX_EVENT: usize = 16;
4040

4141
#[derive(Debug)]
4242
struct DaqDecoder {
43+
timestamp_resolution: u64,
4344
event_count: usize,
4445
byte_count: usize,
4546
daq_timestamp: [u64; MAX_EVENT],
@@ -48,6 +49,7 @@ struct DaqDecoder {
4849
impl DaqDecoder {
4950
pub fn new() -> DaqDecoder {
5051
DaqDecoder {
52+
timestamp_resolution: 0,
5153
event_count: 0,
5254
byte_count: 0,
5355
daq_timestamp: [0; MAX_EVENT],
@@ -68,6 +70,11 @@ impl XcpDaqDecoder for DaqDecoder {
6870
}
6971
}
7072

73+
// Set timestamp resolution
74+
fn set_timestamp_resolution(&mut self, timestamp_resolution: u64) {
75+
self.timestamp_resolution = timestamp_resolution;
76+
}
77+
7178
// Decode DAQ data
7279
fn decode(&mut self, lost: u32, daq: u16, odt: u8, timestamp: u32, data: &[u8]) {
7380
assert!(daq < MAX_EVENT as u16);
@@ -93,7 +100,8 @@ impl XcpDaqDecoder for DaqDecoder {
93100
assert!(data.len() >= 4);
94101
let counter = data[0] as u32 | (data[1] as u32) << 8 | (data[2] as u32) << 16 | (data[3] as u32) << 24;
95102
//trace!("DAQ: lost={}, daq={}, odt={}: timestamp={} counter={} data={:?}", lost, daq, odt, t, counter, data);
96-
info!("DAQ: lost={}, daq={}, odt={}, t={}, counter={}", lost, daq, odt, t, counter);
103+
let t = t * self.timestamp_resolution;
104+
info!("DAQ: lost={}, daq={}, odt={}, t={}ns, counter={}", lost, daq, odt, t, counter);
97105
}
98106

99107
self.byte_count += data.len(); // overall payload byte count

0 commit comments

Comments
 (0)