Skip to content

Commit

Permalink
Test passed
Browse files Browse the repository at this point in the history
  • Loading branch information
RainerZ committed Sep 8, 2024
1 parent dda814f commit 54be39e
Show file tree
Hide file tree
Showing 11 changed files with 463 additions and 75 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ Feature json and auto_reg must be enabled for testing.
```

cargo test --features=json --features=auto_reg -- --test-threads=1 --nocapture

cargo test --features=json --features=auto_reg -- --test-threads=1 --nocapture --test test_tokio_multi_thread

```
Expand Down
1 change: 0 additions & 1 deletion examples/tokio_demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Start tokio XCP server
// Initialize the xcplib transport and protocol layer only, not the server
let xcp: &'static Xcp = XcpBuilder::new("tokio_demo").set_log_level(XcpLogLevel::Debug).enable_a2l(true).tl_start().unwrap();

let xcp_task = tokio::spawn(xcp_server::xcp_task(xcp, [127, 0, 0, 1], 5555));

// let mut xcp_server = xcp_server::XcpServer::new([127, 0, 0, 1], 5555);
Expand Down
47 changes: 0 additions & 47 deletions examples/tokio_demo/src/xcp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,50 +76,3 @@ where
}
} // loop
}

//-----------------------------------------------------------------------------

// #[derive(Debug)]
// pub struct XcpServer {
// addr: Ipv4Addr,
// port: u16,
// task: Option<tokio::task::JoinHandle<Result<(), io::Error>>>,
// }

// impl Drop for XcpServer {
// fn drop(&mut self) {
// // Cancel the task
// if let Some(task) = self.task.take() {
// task.abort();
// }
// }
// }

// impl XcpServer {
// pub fn new<A>(addr: A, port: u16) -> Self
// where
// A: Into<Ipv4Addr>,
// {
// Self { addr: addr.into(), port, task: None }
// }

// pub async fn start_xcp(&mut self, xcp: &Xcp) -> Result<&Xcp, Box<dyn Error>> {
// // Start server
// let task = tokio::spawn(xcp_task(xcp, self.addr, self.port));
// self.task = Some(task);

// Ok(xcp)
// }

// pub fn get_xcp(&self) -> &Xcp {
// Xcp::get()
// }

// pub async fn stop_xcp(&mut self) -> Result<(), Box<dyn Error>> {
// // Cancel the task
// if let Some(task) = self.task.take() {
// task.abort();
// }
// Ok(())
// }
// }
2 changes: 1 addition & 1 deletion src/xcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ impl Xcp {
let mut buf_len: u16 = 0;
let buf_ptr = xcplib::XcpTlTransmitQueuePeek(&mut buf_len as *mut u16);
if !buf_ptr.is_null() {
info!("tl_transmit_queue_peek: len={}", buf_len);
//trace!("tl_transmit_queue_peek: len={}", buf_len);
return Some(std::slice::from_raw_parts(buf_ptr, buf_len as usize));
}
}
Expand Down
13 changes: 6 additions & 7 deletions tests/multi_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ use test_executor::MULTI_THREAD_TASK_COUNT;

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};

use serde::{Deserialize, Serialize};
use std::{fmt::Debug, thread};
use tokio::time::Duration;

//-----------------------------------------------------------------------------
// XCP
// Logging

const OPTION_SERVER_ADDR: [u8; 4] = [127, 0, 0, 1]; // Localhost
const OPTION_SERVER_PORT: u16 = 5555;
const OPTION_TRANSPORT_LAYER: XcpTransportLayer = XcpTransportLayer::Udp; // XcpTransportLayer::TcpIp or XcpTransportLayer::UdpIp
const OPTION_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;
const OPTION_XCP_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;

//-----------------------------------------------------------------------------
// Calibration Segment

Expand Down Expand Up @@ -151,7 +150,7 @@ fn task(cal_seg: CalSeg<CalPage1>) {
}

//-----------------------------------------------------------------------------
// Integration test single threads calibration
// Integration test multi thread measurememt and calibration

#[tokio::test]
async fn test_multi_thread() {
Expand All @@ -162,7 +161,7 @@ async fn test_multi_thread() {
.set_log_level(OPTION_XCP_LOG_LEVEL)
.enable_a2l(true)
.set_epk("EPK_TEST")
.start_server(OPTION_TRANSPORT_LAYER, OPTION_SERVER_ADDR, OPTION_SERVER_PORT)
.start_server(XcpTransportLayer::Udp, [127, 0, 0, 1], 5555)
{
Err(res) => {
error!("XCP initialization failed: {:?}", res);
Expand All @@ -184,7 +183,7 @@ async fn test_multi_thread() {
v.push(t);
}

test_executor(&xcp, false, true).await; // Start the test executor XCP client
test_executor(xcp, false, true).await; // Start the test executor XCP client

for t in v {
t.join().ok();
Expand Down
17 changes: 3 additions & 14 deletions tests/single_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ use tokio::time::Duration;
//-----------------------------------------------------------------------------
// XCP

const OPTION_SERVER_ADDR: [u8; 4] = [127, 0, 0, 1]; // Localhost
const OPTION_SERVER_PORT: u16 = 5555;
const OPTION_TRANSPORT_LAYER: XcpTransportLayer = XcpTransportLayer::Udp; // XcpTransportLayer::TcpIp or XcpTransportLayer::UdpIp
const OPTION_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;
const OPTION_XCP_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;

Expand Down Expand Up @@ -151,28 +148,20 @@ fn task(cal_seg: CalSeg<CalPage1>) {
}

//-----------------------------------------------------------------------------
// Integration test single threads calibration
// Integration test single thread measurement and calibration

#[tokio::test]
async fn test_single_thread() {
env_logger::Builder::new().filter_level(OPTION_LOG_LEVEL.to_log_level_filter()).init();
env_logger::Builder::new().filter_level(OPTION_LOG_LEVEL.to_log_level_filter()).try_init().ok();

info!("Running test_single_thread");
if cfg!(target_endian = "little") {
info!("The system is little endian! (Intel)");
} else {
error!("The system is big endian! (Motorola)");
panic!("Big endian is not supported!");
}
info!("The system usize has {} bytes", std::mem::size_of::<usize>());
info!("The system bool has {} bytes", std::mem::size_of::<bool>());

// Initialize XCP driver singleton, the transport layer server and enable the A2L writer
let xcp = match XcpBuilder::new("xcp_lite")
.set_log_level(OPTION_XCP_LOG_LEVEL)
.enable_a2l(true)
.set_epk("EPK_TEST")
.start_server(OPTION_TRANSPORT_LAYER, OPTION_SERVER_ADDR, OPTION_SERVER_PORT)
.start_server(XcpTransportLayer::Udp, [127, 0, 0, 1], 5555)
{
Err(res) => {
error!("XCP initialization failed: {:?}", res);
Expand Down
9 changes: 6 additions & 3 deletions tests/test_executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,6 @@ pub async fn test_executor(xcp: &Xcp, single_thread: bool, multi_thread: bool) {
// Check results
{
let d = daq_decoder.lock().unwrap();
assert_ne!(d.tot_events, 0);
info!("DAQ test cycle time = {}us", TASK_SLEEP_TIME_US);
if multi_thread {
info!("DAQ test thread count = {}", MULTI_THREAD_TASK_COUNT);
Expand All @@ -354,7 +353,7 @@ pub async fn test_executor(xcp: &Xcp, single_thread: bool, multi_thread: bool) {
info!(" cycles = {}", d.daq_events[0]);
info!(" events = {}", d.tot_events);
info!(" bytes per cycle = {}", bytes);
assert!(d.tot_events > 0);
assert_ne!(d.tot_events, 0);
assert!(d.daq_events[0] > 0);
info!(" test duration = {:.3}ms", duration_ms);
info!(" average datarate = {:.3} MByte/s", (bytes as f64 * d.tot_events as f64) / 1000.0 / duration_ms,);
Expand Down Expand Up @@ -470,13 +469,17 @@ pub async fn test_executor(xcp: &Xcp, single_thread: bool, multi_thread: bool) {
.unwrap();
}
let elapsed_time = start_time.elapsed().as_micros();
let download_time = elapsed_time as f64 / MAX_ITER as f64;
info!(
"calibration test loop done, {} iterations, duration={}ms, {}us per download, {:.1} KBytes/s",
MAX_ITER,
elapsed_time / 1000,
elapsed_time as f64 / MAX_ITER as f64,
download_time,
MAX_ITER as f64 * 8000.0 / elapsed_time as f64
);
if download_time > 100.0 {
warn!("Calibration download time ({}us) is too high!", download_time);
}
}
}

Expand Down
187 changes: 187 additions & 0 deletions tests/tokio_multi_thread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// multi_thread
// Integration test for XCP in a multi threaded application
// Uses the test XCP client in test_executor

use xcp::*;
use xcp_type_description::prelude::*;

mod xcp_server;

mod test_executor;
use test_executor::test_executor;
use test_executor::MULTI_THREAD_TASK_COUNT;

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};

use serde::{Deserialize, Serialize};
use std::{fmt::Debug, thread};
use tokio::time::Duration;

//-----------------------------------------------------------------------------
// Logging

const OPTION_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;
const OPTION_XCP_LOG_LEVEL: XcpLogLevel = XcpLogLevel::Info;

//-----------------------------------------------------------------------------
// Calibration Segment

use xcp_type_description_derive::XcpTypeDescription;

#[derive(Debug, Clone, Copy, Serialize, Deserialize, XcpTypeDescription)]
struct TestInts {
test_bool: bool,
test_u8: u8,
test_u16: u16,
test_u32: u32,
test_u64: u64,
test_i8: i8,
test_i16: i16,
test_i32: i32,
test_i64: i64,
test_f32: f32,
test_f64: f64,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, XcpTypeDescription)]
struct CalPage1 {
run: bool,
counter_max: u32,
cal_test: u64,
cycle_time_us: u32,
page: u8,
test_ints: TestInts,
}

// Default values for the calibration parameters
const CAL_PAR1: CalPage1 = CalPage1 {
run: true,
counter_max: 0xFFFF,
cal_test: 0x5555555500000000u64,
cycle_time_us: 1000,
page: XcpCalPage::Flash as u8,
test_ints: TestInts {
test_bool: false,
test_u8: 0x12,
test_u16: 0x1234,
test_u32: 0x12345678,
test_u64: 0x0102030405060708u64,
test_i8: -1,
test_i16: -1,
test_i32: -1,
test_i64: -1,
test_f32: 0.123456E-10,
test_f64: 0.123456789E-100,
},
};

//-----------------------------------------------------------------------------

// Test task will be instatiated multiple times
fn task(cal_seg: CalSeg<CalPage1>) {
let mut counter: u32 = 0;
let mut loop_counter: u64 = 0;
let mut changes: u64 = 0;
let mut cal_test: u64 = 0;
let mut counter_max: u32 = 0;
let mut test1: u64 = 0;
let mut test2: u64 = 0;
let mut test3: u64 = 0;
let mut test4: u64 = 0;

let mut event = daq_create_event_instance!("task");
daq_register_instance!(changes, event);
daq_register_instance!(loop_counter, event);
//daq_register_instance!(cal_test, event); // Measured with capture, pattern checked in DaqDecoder
daq_register_instance!(counter_max, event);
daq_register_instance!(counter, event);
daq_register_instance!(test1, event);
daq_register_instance!(test2, event);
daq_register_instance!(test3, event);
daq_register_instance!(test4, event);

loop {
thread::sleep(Duration::from_micros(cal_seg.cycle_time_us as u64)); // Sleep for a calibratable amount of microseconds
loop_counter += 1;

// Create a calibratable wrapping counter signal
counter_max = cal_seg.counter_max;
counter += 1;
if counter > counter_max {
counter = 0;
}

// Test calibration data validity
if cal_test != cal_seg.cal_test {
changes += 1;
cal_test = cal_seg.cal_test;
assert_eq!((cal_test >> 32) ^ 0x55555555, cal_test & 0xFFFFFFFF);
}

// DAQ
// daq_capture_instance!(changes, event);
// daq_capture_instance!(loop_counter, event);
daq_capture_instance!(cal_test, event);
// daq_capture_instance!(counter_max, event);
// daq_capture_instance!(counter, event);
event.trigger();

// Synchronize the calibration segment
cal_seg.sync();

if loop_counter % 256 == 0 {
test1 = loop_counter;
test2 = test1 + 1;
test3 = test2 + 2;
test4 = test3 + 3;
_ = test4;

// Check for termination
if !cal_seg.run {
break;
}
}
}

debug!("Task terminated, loop counter = {}, {} changes observed", loop_counter, changes);
}

//-----------------------------------------------------------------------------
// Integration test multi thread measurememt and calibration

#[tokio::test]
async fn test_tokio_multi_thread() {
env_logger::Builder::new().filter_level(OPTION_LOG_LEVEL.to_log_level_filter()).init();

// Start tokio XCP server
// Initialize the xcplib transport and protocol layer only, not the server
let xcp: &'static Xcp = XcpBuilder::new("tokio_demo")
.set_log_level(OPTION_XCP_LOG_LEVEL)
.enable_a2l(true)
.set_epk("EPK_TEST")
.tl_start()
.unwrap();
let _xcp_task = tokio::spawn(xcp_server::xcp_task(xcp, [127, 0, 0, 1], 5555));

// Create a calibration segment
let cal_seg = xcp.create_calseg("cal_seg", &CAL_PAR1, true);

// Create n test tasks
let mut v = Vec::new();
for _ in 0..MULTI_THREAD_TASK_COUNT {
let cal_seg = CalSeg::clone(&cal_seg);
let t = thread::spawn(move || {
task(cal_seg);
});
v.push(t);
}

test_executor(xcp, false, true).await; // Start the test executor XCP client

for t in v {
t.join().ok();
}

std::fs::remove_file("xcp_client.a2l").ok();
}
Loading

0 comments on commit 54be39e

Please sign in to comment.