Added more unittests

This commit is contained in:
Christoffer Martinsson 2025-09-16 08:37:06 +02:00
parent b98614fe8e
commit 9f95813f97
3 changed files with 86 additions and 15 deletions

View File

@ -416,6 +416,10 @@ pub fn calculate_axis_value(
) -> u16 { ) -> u16 {
use crate::hardware::{ADC_MAX, ADC_MIN, AXIS_CENTER}; use crate::hardware::{ADC_MAX, ADC_MIN, AXIS_CENTER};
if min >= max || center <= min || center >= max {
return center;
}
if value <= min { if value <= min {
return ADC_MIN; return ADC_MIN;
} }
@ -660,6 +664,20 @@ mod tests {
assert_eq!(result, AXIS_CENTER); assert_eq!(result, AXIS_CENTER);
} }
#[test]
fn test_calculate_axis_value_degenerate_calibration() {
let expo_lut = ExpoLUT::new(0.0);
// When calibration collapses to a single point (min=max=center),
// the output should remain at that center rather than clamping low/high.
let result = calculate_axis_value(2100, 2100, 2100, 2100, (0, 0, 0), false, &expo_lut);
assert_eq!(result, 2100);
// Also handle centers outside the valid window by returning center directly.
let result = calculate_axis_value(1500, 1400, 2000, 1400, (0, 0, 0), false, &expo_lut);
assert_eq!(result, 1400);
}
#[test] #[test]
fn test_remap_function() { fn test_remap_function() {
// Test basic remapping // Test basic remapping

View File

@ -8,9 +8,9 @@
//! - Evaluate special combinations (bootloader, calibration, etc.) //! - Evaluate special combinations (bootloader, calibration, etc.)
//! - Expose a compact state consumed by USB report generation //! - Expose a compact state consumed by USB report generation
use crate::mapping::*;
use crate::button_matrix::ButtonMatrix; use crate::button_matrix::ButtonMatrix;
use crate::hardware::{NUMBER_OF_BUTTONS, AXIS_CENTER, BUTTON_ROWS, BUTTON_COLS}; use crate::hardware::{AXIS_CENTER, BUTTON_COLS, BUTTON_ROWS, NUMBER_OF_BUTTONS};
use crate::mapping::*;
use embedded_hal::digital::InputPin; use embedded_hal::digital::InputPin;
use rp2040_hal::timer::Timer; use rp2040_hal::timer::Timer;
@ -39,7 +39,6 @@ pub struct Button {
// ==================== SPECIAL ACTIONS ==================== // ==================== SPECIAL ACTIONS ====================
/// Highlevel actions triggered by dedicated button combinations. /// Highlevel actions triggered by dedicated button combinations.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum SpecialAction { pub enum SpecialAction {
None, None,
@ -55,7 +54,6 @@ pub enum SpecialAction {
// ==================== BUTTON MANAGER ==================== // ==================== BUTTON MANAGER ====================
/// Aggregates and processes all buttons, exposing a stable API to the rest of the firmware. /// Aggregates and processes all buttons, exposing a stable API to the rest of the firmware.
pub struct ButtonManager { pub struct ButtonManager {
pub buttons: [Button; TOTAL_BUTTONS], pub buttons: [Button; TOTAL_BUTTONS],
} }
@ -77,7 +75,10 @@ impl ButtonManager {
} }
/// Update button states from the button matrix snapshot. /// Update button states from the button matrix snapshot.
pub fn update_from_matrix(&mut self, matrix: &mut ButtonMatrix<BUTTON_ROWS, BUTTON_COLS, NUMBER_OF_BUTTONS>) { pub fn update_from_matrix(
&mut self,
matrix: &mut ButtonMatrix<BUTTON_ROWS, BUTTON_COLS, NUMBER_OF_BUTTONS>,
) {
for (index, key) in matrix.buttons_pressed().iter().enumerate() { for (index, key) in matrix.buttons_pressed().iter().enumerate() {
self.buttons[index].pressed = *key; self.buttons[index].pressed = *key;
} }
@ -162,7 +163,11 @@ impl ButtonManager {
} }
/// Check for special button combinations (bootloader, calibration state/mode, VT, etc.). /// Check for special button combinations (bootloader, calibration state/mode, VT, etc.).
pub fn check_special_combinations(&self, unprocessed_axis_value: u16, calibration_active: bool) -> SpecialAction { pub fn check_special_combinations(
&self,
unprocessed_axis_value: u16,
calibration_active: bool,
) -> SpecialAction {
// Secondary way to enter bootloader // Secondary way to enter bootloader
if self.buttons[BUTTON_FRONT_LEFT_LOWER].pressed if self.buttons[BUTTON_FRONT_LEFT_LOWER].pressed
&& self.buttons[BUTTON_TOP_LEFT_MODE].pressed && self.buttons[BUTTON_TOP_LEFT_MODE].pressed
@ -297,13 +302,14 @@ fn update_button_press_type(button: &mut Button, current_time: u32) {
// Autorelease generated USB press after minimum hold time // Autorelease generated USB press after minimum hold time
const USB_MIN_HOLD_MS: u32 = 50; const USB_MIN_HOLD_MS: u32 = 50;
if button.usb_press_active let elapsed = current_time.saturating_sub(button.usb_press_start_time);
&& (!button.pressed let should_release = if button.long_press_handled {
&& !button.long_press_handled !button.enable_long_hold && elapsed >= USB_MIN_HOLD_MS
&& current_time - button.usb_press_start_time >= USB_MIN_HOLD_MS) } else {
|| (!button.enable_long_hold !button.pressed && elapsed >= USB_MIN_HOLD_MS
&& button.long_press_handled };
&& current_time - button.usb_press_start_time >= USB_MIN_HOLD_MS)
if button.usb_press_active && should_release
{ {
button.usb_changed = true; button.usb_changed = true;
button.usb_press_active = false; button.usb_press_active = false;
@ -483,6 +489,37 @@ mod tests {
assert!(button.long_press_handled); assert!(button.long_press_handled);
} }
#[test]
fn test_button_press_type_long_press_auto_release_once() {
let mut button = Button::default();
button.usb_button_long = 2;
button.enable_long_press = true;
button.enable_long_hold = false;
// Press the button
button.pressed = true;
update_button_press_type(&mut button, 0);
button.previous_pressed = button.pressed;
// Hold long enough to trigger the long press path
update_button_press_type(&mut button, 250);
assert!(button.usb_press_active);
assert_eq!(button.active_usb_button, 2);
// Clear the changed flag to emulate USB stack observing it
button.usb_changed = false;
// Keep holding and ensure we auto-release exactly once
update_button_press_type(&mut button, 320);
assert!(!button.usb_press_active);
assert!(button.usb_changed);
button.usb_changed = false;
update_button_press_type(&mut button, 400);
assert!(!button.usb_press_active);
assert!(!button.usb_changed);
}
#[test] #[test]
fn test_timer_integration_method_exists() { fn test_timer_integration_method_exists() {
let manager = ButtonManager::new(); let manager = ButtonManager::new();

View File

@ -135,7 +135,9 @@ impl CalibrationManager {
]; ];
// Save calibration data to storage // Save calibration data to storage
let _ = storage::write_calibration_data(write_fn, &axis_data, self.gimbal_mode); if storage::write_calibration_data(write_fn, &axis_data, self.gimbal_mode).is_err() {
return false;
}
// End calibration mode // End calibration mode
self.active = false; self.active = false;
@ -519,6 +521,20 @@ mod tests {
assert!(!manager.is_active()); // Should end calibration assert!(!manager.is_active()); // Should end calibration
} }
#[test]
fn test_save_calibration_failure_keeps_active() {
let mut manager = CalibrationManager::new();
manager.start_calibration();
let axes = [GimbalAxis::new(); NBR_OF_GIMBAL_AXIS];
let mut write_fn = |_page: u32, _data: &[u8]| Err(());
let result = manager.save_calibration(&axes, &mut write_fn);
assert!(!result);
assert!(manager.is_active());
}
#[test] #[test]
fn test_save_calibration_inactive() { fn test_save_calibration_inactive() {
let mut manager = CalibrationManager::new(); // Note: not starting calibration let mut manager = CalibrationManager::new(); // Note: not starting calibration