Skip to content

Commit b326bbd

Browse files
committed
review comment
1 parent 27c3f64 commit b326bbd

1 file changed

Lines changed: 53 additions & 10 deletions

File tree

src/can/bitrate.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use thiserror::Error;
2020

2121
const CAN_SYNC_SEG: u32 = 1;
2222
const CAN_CALC_MAX_ERROR: u32 = 50; // 0.50% in one-hundredth percent units
23-
const SAMPLE_POINT_SCALE: f64 = 1000.0;
23+
const SAMPLE_POINT_SCALE_INT: u32 = 1000;
24+
const SAMPLE_POINT_SCALE: f64 = SAMPLE_POINT_SCALE_INT as f64;
2425
const DEFAULT_SAMPLE_POINT_HIGH_BITRATE_THRESHOLD: u32 = 800_000;
2526
const DEFAULT_SAMPLE_POINT_MEDIUM_BITRATE_THRESHOLD: u32 = 500_000;
2627
const DEFAULT_SAMPLE_POINT_HIGH_BITRATE: u32 = 750;
@@ -85,13 +86,13 @@ pub struct BitrateConfig {
8586
pub timing: AdapterBitTiming,
8687
/// Actual bitrate in bits per second.
8788
pub bitrate: u32,
88-
/// Actual sample point in normalized form (`0.0..1.0`).
89+
/// Actual sample point in normalized form (`0.0 < sample_point < 1.0`).
8990
pub sample_point: f64,
9091
/// Optional CAN-FD data phase adapter-facing timing values.
9192
pub data_timing: Option<AdapterBitTiming>,
9293
/// Optional CAN-FD data phase bitrate in bits per second.
9394
pub data_bitrate: Option<u32>,
94-
/// Optional CAN-FD data phase sample point in normalized form (`0.0..1.0`).
95+
/// Optional CAN-FD data phase sample point in normalized form (`0.0 < sample_point < 1.0`).
9596
pub data_sample_point: Option<f64>,
9697
}
9798

@@ -140,7 +141,7 @@ pub enum BitrateError {
140141
InvalidSjwMax,
141142
#[error("bitrate must be greater than 0")]
142143
InvalidBitrate,
143-
#[error("sample_point must be in range [0.0, 1.0)")]
144+
#[error("sample_point must be in range (0.0, 1.0)")]
144145
InvalidSamplePoint,
145146
#[error("cannot mix bitrate-based and direct timing configuration")]
146147
MixedConfiguration,
@@ -395,7 +396,7 @@ impl BitrateBuilder {
395396
self
396397
}
397398

398-
/// Target sample point in normalized form (`0.0..1.0`).
399+
/// Target sample point in normalized form (`0.0 < sample_point < 1.0`).
399400
///
400401
/// If omitted, the default depends on bitrate:
401402
/// - `bitrate > 800_000`: `0.750`
@@ -442,7 +443,7 @@ impl BitrateBuilder {
442443
self
443444
}
444445

445-
/// Optional CAN-FD data phase sample point in normalized form (`0.0..1.0`).
446+
/// Optional CAN-FD data phase sample point in normalized form (`0.0 < sample_point < 1.0`).
446447
///
447448
/// If omitted, the default depends on `data_bitrate`:
448449
/// - `data_bitrate > 800_000`: `0.750`
@@ -805,11 +806,19 @@ fn calc_default_sample_point_nrz(bitrate: u32) -> u32 {
805806
}
806807

807808
fn sample_point_to_int(sample_point: f64) -> Result<u32, BitrateError> {
808-
if !sample_point.is_finite() || !(0.0..1.0).contains(&sample_point) {
809+
if !sample_point.is_finite() || !(0.0..1.0).contains(&sample_point) || sample_point == 0.0 {
809810
return Err(BitrateError::InvalidSamplePoint);
810811
}
811812

812-
Ok((sample_point * SAMPLE_POINT_SCALE) as u32)
813+
let mut sample_point_quantized = (sample_point * SAMPLE_POINT_SCALE).round() as u32;
814+
if sample_point_quantized == 0 {
815+
return Err(BitrateError::InvalidSamplePoint);
816+
}
817+
if sample_point_quantized >= SAMPLE_POINT_SCALE_INT {
818+
sample_point_quantized = SAMPLE_POINT_SCALE_INT - 1;
819+
}
820+
821+
Ok(sample_point_quantized)
813822
}
814823

815824
fn sample_point_to_float(sample_point: u32) -> f64 {
@@ -827,17 +836,22 @@ fn update_sample_point(
827836
let mut best_tseg2 = 0;
828837

829838
for i in 0..=1 {
839+
let tsegall = tseg + CAN_SYNC_SEG;
830840
let mut tseg2 =
831-
tseg + CAN_SYNC_SEG - (sample_point_reference * (tseg + CAN_SYNC_SEG)) / 1000 - i;
841+
tsegall.saturating_sub((sample_point_reference * tsegall) / SAMPLE_POINT_SCALE_INT + i);
832842
tseg2 = tseg2.clamp(btc.tseg2_min, btc.tseg2_max);
833843

844+
if tseg2 > tseg {
845+
continue;
846+
}
847+
834848
let mut tseg1 = tseg - tseg2;
835849
if tseg1 > btc.tseg1_max {
836850
tseg1 = btc.tseg1_max;
837851
tseg2 = tseg - tseg1;
838852
}
839853

840-
let sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / (tseg + CAN_SYNC_SEG);
854+
let sample_point = SAMPLE_POINT_SCALE_INT * (tsegall - tseg2) / tsegall;
841855
let sample_point_error = sample_point_reference.abs_diff(sample_point);
842856

843857
if sample_point <= sample_point_reference && sample_point_error < best_sample_point_error {
@@ -1042,6 +1056,35 @@ mod tests {
10421056
assert_eq!(err, BitrateError::InvalidSamplePoint);
10431057
}
10441058

1059+
#[test]
1060+
fn zero_sample_point_rejected() {
1061+
let err = BitrateBuilder::new::<DummyTimingAdapter>()
1062+
.bitrate(500_000)
1063+
.sample_point(0.0)
1064+
.build()
1065+
.unwrap_err();
1066+
1067+
assert_eq!(err, BitrateError::InvalidSamplePoint);
1068+
}
1069+
1070+
#[test]
1071+
fn too_small_sample_point_rejected() {
1072+
let err = BitrateBuilder::new::<DummyTimingAdapter>()
1073+
.bitrate(500_000)
1074+
.sample_point(0.0001)
1075+
.build()
1076+
.unwrap_err();
1077+
1078+
assert_eq!(err, BitrateError::InvalidSamplePoint);
1079+
}
1080+
1081+
#[test]
1082+
fn sample_point_conversion_rounds_and_clamps() {
1083+
assert_eq!(sample_point_to_int(0.8004).unwrap(), 800);
1084+
assert_eq!(sample_point_to_int(0.8005).unwrap(), 801);
1085+
assert_eq!(sample_point_to_int(0.9999).unwrap(), 999);
1086+
}
1087+
10451088
#[test]
10461089
fn invalid_timing_const_brp_inc_zero_rejected() {
10471090
let mut btc = PEAK_NOMINAL_BTC;

0 commit comments

Comments
 (0)