Skip to content

Commit f8e33c5

Browse files
committed
tests: lib: rust: Add 'time' test
Add a test to test that the time values in Rust (Duration and Instance) and up calculating the same results as the various macros used in the C code. Signed-off-by: David Brown <[email protected]>
1 parent e9b1585 commit f8e33c5

File tree

6 files changed

+220
-0
lines changed

6 files changed

+220
-0
lines changed

tests/lib/rust/time/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(time_rust)
7+
8+
target_sources(app PRIVATE src/times.c)
9+
10+
rust_cargo_application()

tests/lib/rust/time/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) 2024 Linaro LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
[package]
5+
# This must be rustapp for now.
6+
name = "rustapp"
7+
version = "0.1.0"
8+
edition = "2021"
9+
description = "Tests of time"
10+
license = "Apache-2.0 or MIT"
11+
12+
[lib]
13+
crate-type = ["staticlib"]
14+
15+
[dependencies]
16+
zephyr = "0.1.0"

tests/lib/rust/time/prj.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright (c) 2024 Linaro LTD
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
CONFIG_RUST=y
5+
CONFIG_MAIN_STACK_SIZE=2048

tests/lib/rust/time/src/lib.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#![no_std]
5+
6+
use core::ffi::{
7+
c_char,
8+
CStr,
9+
};
10+
11+
use zephyr::printkln;
12+
use zephyr::time::{Duration, Instant, Tick, Timeout};
13+
use zephyr::raw::k_timeout_t;
14+
15+
#[no_mangle]
16+
extern "C" fn rust_main() {
17+
printkln!("Tick frequency: {}", zephyr::time::SYS_FREQUENCY);
18+
check_conversions();
19+
printkln!("All tests passed");
20+
}
21+
22+
/// Verify that the conversions are correct.
23+
fn check_conversions() {
24+
let mut index = 0;
25+
loop {
26+
// The entry returns is always valid, so is a valid reference.
27+
let entry = unsafe { &*get_time_entry(index) };
28+
if entry.name.is_null() {
29+
break;
30+
}
31+
let name = unsafe {
32+
CStr::from_ptr(entry.name).to_str().expect("Invalid C string")
33+
};
34+
printkln!("Testing: {}", name);
35+
36+
// The units must match the enum in the C code.
37+
match entry.units {
38+
// UNIT_FOREVER
39+
0 => {
40+
assert_eq!(entry.value.ticks, zephyr::sys::K_FOREVER.ticks);
41+
}
42+
// UNIT_NO_WAIT
43+
1 => {
44+
assert_eq!(entry.value.ticks, zephyr::sys::K_NO_WAIT.ticks);
45+
}
46+
// UNIT_DUR_MS
47+
2 => {
48+
let value = Duration::millis_at_least(entry.uvalue as Tick);
49+
let value: Timeout = value.into();
50+
assert_eq!(entry.value.ticks, value.0.ticks);
51+
}
52+
// UNIT_INST_MS
53+
3 => {
54+
let base = Instant::from_ticks(0);
55+
let value = Duration::millis_at_least(entry.uvalue as Tick);
56+
let value = base + value;
57+
let value: Timeout = value.into();
58+
let c_value = unsafe { ms_to_abs_timeout(entry.uvalue) };
59+
if c_value.ticks != value.0.ticks {
60+
printkln!("Mismatch C: {}, Rust: {}",
61+
c_value.ticks, value.0.ticks);
62+
}
63+
assert_eq!(c_value.ticks, value.0.ticks);
64+
}
65+
_ => {
66+
panic!("Invalid unit enum");
67+
}
68+
}
69+
70+
index += 1;
71+
}
72+
}
73+
74+
/// The time entry information.
75+
#[repr(C)]
76+
struct TimeEntry {
77+
name: *const c_char,
78+
units: u32,
79+
uvalue: i64,
80+
value: k_timeout_t,
81+
}
82+
83+
extern "C" {
84+
fn get_time_entry(index: usize) -> *const TimeEntry;
85+
fn ms_to_abs_timeout(ms: i64) -> k_timeout_t;
86+
}

tests/lib/rust/time/src/times.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* Copyright (c) 2024 Linaro LTD */
2+
/* SPDX-License-Identifier: Apache-2.0 */
3+
4+
#include <zephyr/kernel.h>
5+
6+
/* Rather than trying to get C enums to match in size with Rust ones, just use a known integet type.
7+
*/
8+
enum units {
9+
UNIT_FOREVER,
10+
UNIT_NO_WAIT,
11+
UNIT_DUR_MSEC,
12+
UNIT_INST_MSEC,
13+
};
14+
15+
/* Data handed back from C containing processed time constant values.
16+
*/
17+
struct time_entry {
18+
const char *name;
19+
20+
uint32_t units;
21+
22+
/* Value in the given units. */
23+
int64_t uvalue;
24+
25+
/* Value in ticks. */
26+
k_timeout_t value;
27+
};
28+
29+
const struct time_entry time_entries[] = {
30+
{
31+
.name = "K_FOREVER",
32+
.units = UNIT_FOREVER,
33+
.uvalue = 0,
34+
.value = K_FOREVER,
35+
},
36+
{
37+
.name = "K_NO_WAIT",
38+
.units = UNIT_NO_WAIT,
39+
.uvalue = 0,
40+
.value = K_NO_WAIT,
41+
},
42+
#define DUR_TEST(unit, n) \
43+
{ \
44+
.name = "Duration " #unit " " #n, \
45+
.units = UNIT_DUR_ ## unit, \
46+
.uvalue = n, \
47+
.value = K_ ## unit(n) , \
48+
}
49+
// Test various values near typical clock boundaries.
50+
DUR_TEST(MSEC, 1),
51+
DUR_TEST(MSEC, 2),
52+
DUR_TEST(MSEC, 99),
53+
DUR_TEST(MSEC, 100),
54+
DUR_TEST(MSEC, 101),
55+
DUR_TEST(MSEC, 999),
56+
DUR_TEST(MSEC, 1000),
57+
DUR_TEST(MSEC, 1001),
58+
DUR_TEST(MSEC, 32767),
59+
DUR_TEST(MSEC, 32768),
60+
DUR_TEST(MSEC, 32769),
61+
#define INST_TEST(unit, n) \
62+
{ \
63+
.name = "Instant " #unit " " #n, \
64+
.units = UNIT_INST_ ## unit, \
65+
.uvalue = n, \
66+
}
67+
INST_TEST(MSEC, 1),
68+
INST_TEST(MSEC, 2),
69+
INST_TEST(MSEC, 99),
70+
INST_TEST(MSEC, 100),
71+
INST_TEST(MSEC, 101),
72+
INST_TEST(MSEC, 999),
73+
INST_TEST(MSEC, 1000),
74+
INST_TEST(MSEC, 1001),
75+
INST_TEST(MSEC, 32767),
76+
INST_TEST(MSEC, 32768),
77+
INST_TEST(MSEC, 32769),
78+
{
79+
.name = 0,
80+
},
81+
};
82+
83+
/* Return the indexed time entry. It is up to the Rust code to detect the null name, and handle it
84+
* properly.
85+
*/
86+
const struct time_entry *get_time_entry(uintptr_t index) {
87+
return &time_entries[index];
88+
}
89+
90+
/* The abs timeout is not constant, so provide this wrapper function.
91+
*/
92+
const k_timeout_t ms_to_abs_timeout(int64_t ms) {
93+
return K_TIMEOUT_ABS_MS(ms);
94+
}

tests/lib/rust/time/testcase.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
common:
2+
filter: CONFIG_RUST_SUPPORTED
3+
tests:
4+
test.rust.time:
5+
harness: console
6+
harness_config:
7+
type: one_line
8+
regex:
9+
- "All tests passed"

0 commit comments

Comments
 (0)