Skip to content

Commit

Permalink
Prepare DAQ callback gets pointer to DAQ list structure
Browse files Browse the repository at this point in the history
  • Loading branch information
RainerZ committed Dec 30, 2024
1 parent f5b5cf1 commit 77bed97
Show file tree
Hide file tree
Showing 13 changed files with 784 additions and 174 deletions.
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Disclaimer: This code is in experimental state. There is no release yet.

xcp-lite is a Rust API for measurement and calibration, which uses the ASAM XCP protocol for communication with a measurement and calibration tool like CANape and ASAM A2L for data description.

This is no complete implementation of XCP in Rust, parts of it are still C/C++ from XCPlite.
This is no complete implementation of XCP in Rust, the protocoll and transport layer implementation is in C/C++ based on XCPlite.

Main purpose was to experiment with Rust and to demonstrate some more advanced features of measurement and calibration with CANape:
- Automatic A2L and IDL generation with proc-macros
Expand All @@ -17,7 +17,7 @@ Main purpose was to experiment with Rust and to demonstrate some more advanced f
- Data objects and containers with dynamic size like point clouds or detection lists, to demonstrate CANape ADAS features
- Support Google protobuf or OMG DDS/CDR serialized data objects with XCP and CANape

Requires CANape 22 SP2.
Requires CANape 22. Example projects are updated to CANape 23.


## Introduction
Expand Down Expand Up @@ -302,14 +302,11 @@ The EPK version string in the A2L file can be set by the application. It resides

## Possible improvements

- Create a minimal lock MPSC event queue, increase queue efficiency (optimize mutex contention) for many daq lists and events
- Support more types of calibration parameters, including types for curves and maps with axis
- Avoid the mutex lock in CalSeg::Sync when there is no pending parameter modification
- Create a lock free algorithm to aquire an entry in the MPSC event queue
- Support specialized types of calibration parameters, including types for curves and maps with axis
- Avoid the mutex lock in CalSeg::Sync when there is no pending parameter modification or switch to a mcu algorithm
- Improve the meta data annotations of the A2L serializer
- Reduce the number of heap allocations and strings, reduce the overall memory footprint
- Add sub groups of measurements for event instances
- Improve the pointer provenance checks in XcpEvent
- Add support to describe the application clock domain in rust
- Add support to describe the application clock domain
- Provide a no-std version and create an embassy example


Expand Down
7 changes: 5 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ fn main() {

// Generate XCPlite C code bindings
// Uncomment this to regenerate the bindings
/*

let bindings = bindgen::Builder::default()
.header("xcplib/wrapper.h")
.clang_arg("-Ixcplib/src")
.clang_arg("-Ixcplib")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
//
.blocklist_type("T_CLOCK_INFO")
.allowlist_type("tXcpDaqLists")
// Protocol layer
.allowlist_function("XcpInit")
//.allowlist_function("XcpStart")
Expand Down Expand Up @@ -42,7 +43,6 @@ fn main() {
.generate()
.expect("Unable to generate bindings");
bindings.write_to_file("src/xcp/xcplib.rs").expect("Couldn't write bindings!");
*/

// Build a XCP on ETH version of XCPlite as a library
cc::Build::new()
Expand All @@ -51,6 +51,7 @@ fn main() {
.file("xcplib/xcpAppl.c")
.file("xcplib/src/platform.c")
.file("xcplib/src/xcpLite.c")
.file("xcplib/src/xcpDaq.c")
.file("xcplib/src/xcpTlQueue.c")
.file("xcplib/src/xcpTl.c")
.file("xcplib/src/xcpEthTl.c")
Expand Down Expand Up @@ -78,4 +79,6 @@ fn main() {
println!("cargo:rerun-if-changed=xcplib/src/xcp.h");
println!("cargo:rerun-if-changed=xcplib/src/xcpLite.h");
println!("cargo:rerun-if-changed=xcplib/src/xcpLite.c");
println!("cargo:rerun-if-changed=xcplib/src/xcpDaq.h");
println!("cargo:rerun-if-changed=xcplib/src/xcpDaq.c");
}
5 changes: 2 additions & 3 deletions src/xcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::{
Arc,
},
};
use xcplib::tXcpDaqLists;

// Using sync version of OnceCell from once_cell crate for the static event remapping array
use once_cell::sync::OnceCell;
Expand Down Expand Up @@ -704,8 +705,6 @@ impl Xcp {
// @@@@ Unsafe - C library call
xcplib::ApplXcpSetEpk(epk.as_ptr());
std::mem::forget(epk); // This memory is never dropped, it is moved to xcplib singleton


}

// A2l is no longer needed yet, free memory
Expand Down Expand Up @@ -800,7 +799,7 @@ extern "C" fn cb_connect() -> u8 {
}

#[no_mangle]
extern "C" fn cb_prepare_daq() -> u8 {
extern "C" fn cb_prepare_daq(_daq: *const tXcpDaqLists) -> u8 {
log::trace!("cb_prepare_daq");
TRUE
}
Expand Down
230 changes: 210 additions & 20 deletions src/xcp/xcplib.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,197 @@
/* automatically generated by rust-bindgen 0.69.5 */

extern "C" {
pub fn ApplXcpSetLogLevel(level: u8);
pub fn XcpEthTlGetInfo(isTCP: *mut u8, mac: *mut u8, addr: *mut u8, port: *mut u16);
}
extern "C" {
pub fn ApplXcpRegisterCallbacks(
cb_connect: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_prepare_daq: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_start_daq: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_stop_daq: ::std::option::Option<unsafe extern "C" fn()>,
cb_get_cal_page: ::std::option::Option<unsafe extern "C" fn(segment: u8, mode: u8) -> u8>,
cb_set_cal_page: ::std::option::Option<unsafe extern "C" fn(segment: u8, page: u8, mode: u8) -> u8>,
cb_freeze_cal: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_init_cal: ::std::option::Option<unsafe extern "C" fn(src_page: u8, dst_page: u8) -> u8>,
cb_read: ::std::option::Option<unsafe extern "C" fn(src: u32, size: u8, dst: *mut u8) -> u8>,
cb_write: ::std::option::Option<unsafe extern "C" fn(dst: u32, size: u8, src: *const u8, delay: u8) -> u8>,
cb_flush: ::std::option::Option<unsafe extern "C" fn() -> u8>,
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct tXcpOdt {
pub first_odt_entry: u16,
pub last_odt_entry: u16,
pub size: u16,
}
#[test]
fn bindgen_test_layout_tXcpOdt() {
const UNINIT: ::std::mem::MaybeUninit<tXcpOdt> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(::std::mem::size_of::<tXcpOdt>(), 6usize, concat!("Size of: ", stringify!(tXcpOdt)));
assert_eq!(::std::mem::align_of::<tXcpOdt>(), 2usize, concat!("Alignment of ", stringify!(tXcpOdt)));
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).first_odt_entry) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpOdt), "::", stringify!(first_odt_entry))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).last_odt_entry) as usize - ptr as usize },
2usize,
concat!("Offset of field: ", stringify!(tXcpOdt), "::", stringify!(last_odt_entry))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize },
4usize,
concat!("Offset of field: ", stringify!(tXcpOdt), "::", stringify!(size))
);
}
extern "C" {
pub fn ApplXcpSetA2lName(name: *const ::std::os::raw::c_char);
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct tXcpDaqList {
pub last_odt: u16,
pub first_odt: u16,
pub event_channel: u16,
pub mode: u8,
pub state: u8,
pub priority: u8,
pub addr_ext: u8,
}
extern "C" {
pub fn ApplXcpSetEpk(epk: *const ::std::os::raw::c_char);
#[test]
fn bindgen_test_layout_tXcpDaqList() {
const UNINIT: ::std::mem::MaybeUninit<tXcpDaqList> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(::std::mem::size_of::<tXcpDaqList>(), 10usize, concat!("Size of: ", stringify!(tXcpDaqList)));
assert_eq!(::std::mem::align_of::<tXcpDaqList>(), 2usize, concat!("Alignment of ", stringify!(tXcpDaqList)));
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).last_odt) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(last_odt))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).first_odt) as usize - ptr as usize },
2usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(first_odt))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).event_channel) as usize - ptr as usize },
4usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(event_channel))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).mode) as usize - ptr as usize },
6usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(mode))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).state) as usize - ptr as usize },
7usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(state))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).priority) as usize - ptr as usize },
8usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(priority))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).addr_ext) as usize - ptr as usize },
9usize,
concat!("Offset of field: ", stringify!(tXcpDaqList), "::", stringify!(addr_ext))
);
}
extern "C" {
pub fn XcpEthTlGetInfo(isTCP: *mut u8, mac: *mut u8, addr: *mut u8, port: *mut u16);
#[repr(C)]
#[derive(Copy, Clone)]
pub struct tXcpDaqLists {
pub odt_entry_count: u16,
pub odt_count: u16,
pub daq_count: u16,
pub res: u16,
pub odt_entry_addr: *mut i32,
pub odt_entry_size: *mut u8,
pub odt: *mut tXcpOdt,
pub u: tXcpDaqLists__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union tXcpDaqLists__bindgen_ty_1 {
pub daq_list: [tXcpDaqList; 1500usize],
pub odt: [tXcpOdt; 2500usize],
pub odt_entry_addr: [u32; 3750usize],
pub odt_entry_size: [u8; 15000usize],
pub b: [u8; 15000usize],
}
#[test]
fn bindgen_test_layout_tXcpDaqLists__bindgen_ty_1() {
const UNINIT: ::std::mem::MaybeUninit<tXcpDaqLists__bindgen_ty_1> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<tXcpDaqLists__bindgen_ty_1>(),
30000usize,
concat!("Size of: ", stringify!(tXcpDaqLists__bindgen_ty_1))
);
assert_eq!(
::std::mem::align_of::<tXcpDaqLists__bindgen_ty_1>(),
8usize,
concat!("Alignment of ", stringify!(tXcpDaqLists__bindgen_ty_1))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).daq_list) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists__bindgen_ty_1), "::", stringify!(daq_list))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists__bindgen_ty_1), "::", stringify!(odt))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_entry_addr) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists__bindgen_ty_1), "::", stringify!(odt_entry_addr))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_entry_size) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists__bindgen_ty_1), "::", stringify!(odt_entry_size))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).b) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists__bindgen_ty_1), "::", stringify!(b))
);
}
#[test]
fn bindgen_test_layout_tXcpDaqLists() {
const UNINIT: ::std::mem::MaybeUninit<tXcpDaqLists> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(::std::mem::size_of::<tXcpDaqLists>(), 30032usize, concat!("Size of: ", stringify!(tXcpDaqLists)));
assert_eq!(::std::mem::align_of::<tXcpDaqLists>(), 8usize, concat!("Alignment of ", stringify!(tXcpDaqLists)));
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_entry_count) as usize - ptr as usize },
0usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(odt_entry_count))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_count) as usize - ptr as usize },
2usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(odt_count))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).daq_count) as usize - ptr as usize },
4usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(daq_count))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).res) as usize - ptr as usize },
6usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(res))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_entry_addr) as usize - ptr as usize },
8usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(odt_entry_addr))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt_entry_size) as usize - ptr as usize },
16usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(odt_entry_size))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).odt) as usize - ptr as usize },
24usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(odt))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).u) as usize - ptr as usize },
32usize,
concat!("Offset of field: ", stringify!(tXcpDaqLists), "::", stringify!(u))
);
}
extern "C" {
pub fn XcpInit();
Expand All @@ -45,6 +211,30 @@ extern "C" {
extern "C" {
pub fn ApplXcpGetAddr(p: *const u8) -> u32;
}
extern "C" {
pub fn ApplXcpSetLogLevel(level: u8);
}
extern "C" {
pub fn ApplXcpRegisterCallbacks(
cb_connect: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_prepare_daq: ::std::option::Option<unsafe extern "C" fn(daq: *const tXcpDaqLists) -> u8>,
cb_start_daq: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_stop_daq: ::std::option::Option<unsafe extern "C" fn()>,
cb_get_cal_page: ::std::option::Option<unsafe extern "C" fn(segment: u8, mode: u8) -> u8>,
cb_set_cal_page: ::std::option::Option<unsafe extern "C" fn(segment: u8, page: u8, mode: u8) -> u8>,
cb_freeze_cal: ::std::option::Option<unsafe extern "C" fn() -> u8>,
cb_init_cal: ::std::option::Option<unsafe extern "C" fn(src_page: u8, dst_page: u8) -> u8>,
cb_read: ::std::option::Option<unsafe extern "C" fn(src: u32, size: u8, dst: *mut u8) -> u8>,
cb_write: ::std::option::Option<unsafe extern "C" fn(dst: u32, size: u8, src: *const u8, delay: u8) -> u8>,
cb_flush: ::std::option::Option<unsafe extern "C" fn() -> u8>,
);
}
extern "C" {
pub fn ApplXcpSetA2lName(name: *const ::std::os::raw::c_char);
}
extern "C" {
pub fn ApplXcpSetEpk(name: *const ::std::os::raw::c_char);
}
extern "C" {
pub fn XcpEthServerInit(addr: *const u8, port: u16, useTCP: u8) -> u8;
}
Expand Down
3 changes: 2 additions & 1 deletion tests/xcp_test_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,8 @@ pub async fn xcp_test_executor(_xcp: &Xcp, test_mode_cal: TestModeCal, test_mode

// Consistent calibration test loop
// Do MAX_ITER consistent calibrations on cal_seg.sync_test1/2 cal_test, task will panic if different
/* @@@@ TODO reanbale this
warn!("Consistent calibration test disabled");
/* @@@@ TODO reenable this
{
tokio::time::sleep(Duration::from_micros(10000)).await;
Expand Down
Loading

0 comments on commit 77bed97

Please sign in to comment.