Skip to content

Commit

Permalink
Test for consistent calibration added
Browse files Browse the repository at this point in the history
  • Loading branch information
RainerZ committed Dec 4, 2024
1 parent da5e886 commit ffff87d
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 21 deletions.
12 changes: 5 additions & 7 deletions examples/hello_xcp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// cargo run --features serde --example hello_xcp

// Run the test XCP client in another terminal or start CANape with the project in folder examples/hello_xcp/CANape
// cargo run --example xcp_client
// cargo run --example xcp_client

use anyhow::Result;
#[allow(unused_imports)]
Expand Down Expand Up @@ -51,7 +51,6 @@ const CAL_PAGE: CalPage = CalPage {
delay: 100000,
};


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

fn main() -> Result<()> {
Expand Down Expand Up @@ -81,12 +80,14 @@ fn main() -> Result<()> {
let mut counter: u32 = cal_page.counter_min;
let mut counter_u64: u64 = 0;

// XCP: Register a measurement event and bind the measurement variables
// XCP: Register a measurement event and bind the measurement variables
let event = daq_create_event!("mainloop", 16);
daq_register!(counter, event);
daq_register!(counter_u64, event);

loop {
// XCP: Synchronize calibration parameters in cal_page and lock read access
let cal_page = cal_page.read_lock();

counter += 1;
counter_u64 += 1;
Expand All @@ -97,9 +98,6 @@ fn main() -> Result<()> {
// XCP: Trigger timestamped measurement data acquisition
event.trigger();

// XCP: Synchronize calibration parameters in cal_page
cal_page.sync();

thread::sleep(Duration::from_micros(cal_page.get_delay()));
}

Expand Down
15 changes: 9 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,15 @@ fn task2(instance_num: usize, calseg: CalSeg<CalPage>, calseg2: CalSeg<CalPage2>
// Sleep for a calibratable amount of microseconds
thread::sleep(Duration::from_micros(static_cal_page.task2_cycle_time_us as u64));

let calseg2 = calseg2.read_lock();

// Calculate demo measurement variable depending on calibration parameters (sine signal with ampl and period)
let time = START_TIME.elapsed().as_micros() as f64 * 0.000001; // s
let offset = instance_num as f64 * 10.0;
let channel = offset + calseg2.ampl * (PI * time / calseg2.period).sin(); // Use active page in calibration segment
let channel = {
// Synchronize calibration parameters in cal_page and lock read access
let calseg2 = calseg2.read_lock();

// Calculate demo measurement variable depending on calibration parameters (sine signal with ampl and period)
let time = START_TIME.elapsed().as_micros() as f64 * 0.000001; // s
let offset = instance_num as f64 * 10.0;
offset + calseg2.ampl * (PI * time / calseg2.period).sin()
};

// Measurement of local variables by capturing their value and association to the given XCP event

Expand Down
11 changes: 9 additions & 2 deletions src/xcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ impl EventList {
let r = Xcp::get().get_registry();
{
let mut l = r.lock();
self.0.iter().for_each(|e| l.add_event(e.name, e.event,e.cycle_time_ns));
self.0.iter().for_each(|e| l.add_event(e.name, e.event, e.cycle_time_ns));
}
}

Expand Down Expand Up @@ -1004,7 +1004,14 @@ pub mod xcp_test {
pub fn test_setup(x: log::LevelFilter) -> &'static Xcp {
log::info!("test_setup");
TEST_INIT.call_once(|| {
env_logger::Builder::new().target(env_logger::Target::Stdout).filter_level(x).init();
env_logger::Builder::new()
.target(env_logger::Target::Stdout)
.filter_level(x)
.format_timestamp(None)
//.format_timestamp_millis()
.format_module_path(false)
.format_target(false)
.init();
});

test_reinit()
Expand Down
24 changes: 22 additions & 2 deletions tests/test_multi_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct CalPage1 {
run: bool,
counter_max: u32,
cal_test: u64,
sync_test1: u16,
sync_test2: u16,
cycle_time_us: u32,
page: u8,
test_ints: TestInts,
Expand All @@ -54,6 +56,8 @@ const CAL_PAR1: CalPage1 = CalPage1 {
cycle_time_us: 100000, // Default cycle time 100ms, will be set by xcp_test_executor
counter_max: 0xFFFF,
cal_test: 0x5555555500000000u64,
sync_test1: 0,
sync_test2: 0,
page: XcpCalPage::Flash as u8,
test_ints: TestInts {
test_bool: false,
Expand Down Expand Up @@ -244,13 +248,22 @@ fn task(index: usize, cal_seg: CalSeg<CalPage1>) {
counter = 0;
}

// Test calibration - check cal_seg.cal_test is valid and report the number of changes
// Test atomic calibration
// Check that modified cal_seg.cal_test value is not corrupted and report the number of changes
if cal_test != cal_seg.cal_test {
changes += 1;
cal_test = cal_seg.cal_test;
assert_eq!((cal_test >> 32) ^ 0x55555555, cal_test & 0xFFFFFFFF);
}

// Test consistent calibration
{
// Syncronize the calibration segment and get a read lock
// Check that modified values of sync_test1/2 are always equal
let cal_seg = cal_seg.read_lock();
assert_eq!(cal_seg.sync_test1, cal_seg.sync_test2);
}

// Capture variable cal_test, to test capture buffer measurement mode
daq_capture_tli!(cal_test, event);

Expand Down Expand Up @@ -288,7 +301,14 @@ fn task(index: usize, cal_seg: CalSeg<CalPage1>) {

#[tokio::test]
async fn test_multi_thread() {
env_logger::Builder::new().target(env_logger::Target::Stdout).filter_level(OPTION_LOG_LEVEL).init();
env_logger::Builder::new()
.target(env_logger::Target::Stdout)
.format_timestamp(None)
//.format_timestamp_millis()
.format_module_path(false)
.format_target(false)
.filter_level(OPTION_LOG_LEVEL)
.init();

// Initialize XCP driver singleton, the transport layer server and enable the A2L writer
let xcp = match XcpBuilder::new("test_multi_thread")
Expand Down
18 changes: 16 additions & 2 deletions tests/test_single_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ fn task(cal_seg: CalSeg<CalPage1>) {
let event = daq_create_event!("task");

// Create static calibration variables
let static_vars: &'static mut StaticVars = STATIC_VARS.init(StaticVars { test_u32: 0x12345678, test_f64: 1.0 });
let static_vars: &'static mut StaticVars = STATIC_VARS.init(StaticVars {
test_u32: 0x12345678,
test_f64: 1.0,
});
let static_event = Xcp::get().create_event("static_event");
daq_register_static!(static_vars.test_u32, static_event, "Test static u32");
daq_register_static!(static_vars.test_f64, static_event, "Test static f64");
Expand Down Expand Up @@ -154,6 +157,10 @@ async fn test_single_thread() {
env_logger::Builder::new()
.target(env_logger::Target::Stdout)
.filter_level(OPTION_LOG_LEVEL)
.format_timestamp(None)
//.format_timestamp_millis()
.format_module_path(false)
.format_target(false)
.try_init()
.ok();

Expand Down Expand Up @@ -223,7 +230,14 @@ async fn test_single_thread() {
Ok(xcp) => xcp,
};

xcp_test_executor(xcp, xcp_test_executor::TestModeCal::None, xcp_test_executor::TestModeDaq::None, "test_single_thread.a2l", false).await; // Start the test executor XCP client
xcp_test_executor(
xcp,
xcp_test_executor::TestModeCal::None,
xcp_test_executor::TestModeDaq::None,
"test_single_thread.a2l",
false,
)
.await; // Start the test executor XCP client

xcp.stop_server();

Expand Down
66 changes: 66 additions & 0 deletions tests/xcp_test_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use log::{debug, error, info, trace, warn};
use parking_lot::Mutex;
use std::net::SocketAddr;
use std::num::Wrapping;
use std::sync::Arc;
use tokio::time::{Duration, Instant};
use xcp::Xcp;
Expand Down Expand Up @@ -608,6 +609,71 @@ pub async fn xcp_test_executor(xcp: &Xcp, test_mode_cal: TestModeCal, test_mode_
warn!("Calibration download time ({}us) is too high!", download_time);
}
}

// Consistent calibration test loop
// Do MAX_ITER consistent calibrations on cal_seg.sync_test1/2 cal_test, task will panic if different
{
tokio::time::sleep(Duration::from_micros(10000)).await;

// Create calibration variable CalPage1.sync_test1
let a2l = xcp_client.get_a2l_file().unwrap();
let sync_test1 = a2l_reader::a2l_find_characteristic(a2l, "CalPage1.sync_test1");
let sync_test2 = a2l_reader::a2l_find_characteristic(a2l, "CalPage1.sync_test2");
if sync_test1.is_some() && sync_test2.is_some() {
let addr_sync_test1 = sync_test1.unwrap().0.addr;
let addr_sync_test2 = sync_test2.unwrap().0.addr;

info!("start consistent calibration test loop");

// Calibration loop
// Set calibration variable cal_test to a defined pattern which will be checked by the server application task
for i in 0..CAL_TEST_MAX_ITER {
let value: u16 = (i & 0xFFFF) as u16;

xcp_client
.modify_begin()
.await
.map_err(|e| {
error_state = true;
error!("modify begin: {:?}", e);
})
.ok();

xcp_client // SHORT_DOWNLOAD cal_seg.test_u64
.short_download(addr_sync_test1, 0, &value.to_le_bytes())
.await
.map_err(|e| {
error_state = true;
error!("download CalPage1.sync_test1: {:?}", e);
})
.ok();

xcp_client // SHORT_DOWNLOAD cal_seg.test_u64
.short_download(addr_sync_test2, 0, &value.to_le_bytes())
.await
.map_err(|e| {
error_state = true;
error!("download CalPage1.sync_test2: {:?}", e);
})
.ok();

xcp_client
.modify_end()
.await
.map_err(|e| {
error_state = true;
error!("modify end: {:?}", e);
})
.ok();

if error_state {
break;
}
}

info!("consistent calibration test loop done, {} iterations", CAL_TEST_MAX_ITER);
}
}
}

// Stop test task
Expand Down
17 changes: 15 additions & 2 deletions xcp_client/src/xcp_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,12 @@ impl std::error::Error for XcpError {}
pub const CC_CONNECT: u8 = 0xFF;
pub const CC_DISCONNECT: u8 = 0xFE;
pub const CC_SHORT_DOWNLOAD: u8 = 0xED;
pub const CC_SYNC: u8 = 0xFC;
pub const CC_GET_ID: u8 = 0xFA;
pub const CC_UPLOAD: u8 = 0xF5;
pub const CC_SHORT_UPLOAD: u8 = 0xF4;
pub const CC_SYNC: u8 = 0xFC;
pub const CC_USER: u8 = 0xF1;
pub const CC_NOP: u8 = 0xC1;
pub const CC_GET_ID: u8 = 0xFA;
pub const CC_SET_CAL_PAGE: u8 = 0xEB;
pub const CC_GET_CAL_PAGE: u8 = 0xEA;
pub const CC_GET_SEGMENT_INFO: u8 = 0xE8;
Expand Down Expand Up @@ -234,6 +235,7 @@ enum XcpCommand {
ShortDownload = CC_SHORT_DOWNLOAD as isize,
Upload = CC_UPLOAD as isize,
ShortUpload = CC_SHORT_UPLOAD as isize,
User = CC_USER as isize,
Sync = CC_SYNC as isize,
Nop = CC_NOP as isize,
GetId = CC_GET_ID as isize,
Expand Down Expand Up @@ -272,6 +274,7 @@ impl From<u8> for XcpCommand {
CC_SHORT_DOWNLOAD => XcpCommand::ShortDownload,
CC_UPLOAD => XcpCommand::Upload,
CC_SHORT_UPLOAD => XcpCommand::ShortUpload,
CC_USER => XcpCommand::User,
CC_SYNC => XcpCommand::Sync,
CC_NOP => XcpCommand::Nop,
CC_GET_ID => XcpCommand::GetId,
Expand Down Expand Up @@ -953,6 +956,16 @@ impl XcpClient {
Ok(data)
}

pub async fn modify_begin(&mut self) -> Result<(), Box<dyn Error>> {
self.send_command(XcpCommandBuilder::new(CC_USER).add_u8(1).add_u8(0).add_u8(0).build()).await?;
Ok(())
}

pub async fn modify_end(&mut self) -> Result<(), Box<dyn Error>> {
self.send_command(XcpCommandBuilder::new(CC_USER).add_u8(2).add_u8(0).add_u8(0).build()).await?;
Ok(())
}

//------------------------------------------------------------------------
// XCP DAQ services

Expand Down

0 comments on commit ffff87d

Please sign in to comment.