@@ -7,51 +7,94 @@ pub struct Movement {
77}
88
99impl Movement {
10- pub const fn new ( ) -> Self {
10+ pub const fn _new ( upper_limit : u8 , lower_limit : u8 , step : i8 ) -> Self {
11+ Self {
12+ upper_limit : upper_limit,
13+ lower_limit : lower_limit,
14+ step : step as i8 ,
15+ }
16+ }
17+
18+ pub const fn default ( ) -> Self {
1119 Self {
1220 upper_limit : 32 ,
1321 lower_limit : 6 ,
1422 step : 6 ,
1523 }
1624 }
1725
18- /// Generate a relative movement vector suitable for use in a mouse HID report
19- /// The generated vector is a for a single axis, and returns to the starting position
20- pub fn generate_vector < const N : usize > ( & self , seed : u32 , vec : & mut heapless:: Vec < i8 , N > ) {
21- // Scale rng_value into the range [LOWER, UPPER] inclusive.
22- // Use 64-bit intermediate to avoid overflow and get decent distribution.
26+ fn xorshift32 ( & self , mut x : u32 ) -> u32 {
27+ x ^= x << 13 ;
28+ x ^= x >> 17 ;
29+ x ^= x << 5 ;
30+ x
31+ }
32+
33+ fn scale_seed ( & self , seed : u32 ) -> i8 {
2334 let range: u32 = ( self . upper_limit - self . lower_limit ) as u32 ;
2435 let scaled: u32 = if seed == u32:: MAX {
2536 range
2637 } else {
2738 ( ( seed as u64 * range as u64 ) / ( u32:: MAX as u64 ) ) as u32
2839 } ;
29- let x_u8 = ( self . lower_limit as u32 + scaled) as u8 ;
30- let mut remaining: i8 = x_u8 as i8 ;
31-
32- // Populate forward movement in STEP-sized chunks (last chunk may be smaller).
33- while remaining > 0 && !vec. is_full ( ) {
34- let to_push: i8 = if remaining >= self . step {
35- self . step
36- } else {
37- remaining
38- } ;
39- if vec. push ( to_push) . is_err ( ) {
40- break ;
41- }
42- remaining -= to_push;
40+
41+ let value = ( self . lower_limit as u32 + scaled) as u8 ;
42+ value as i8
43+ }
44+
45+ fn step_toward_zero ( & self , remaining : i8 , rng : u32 , max_step : i8 ) -> i8 {
46+ if remaining == 0 {
47+ return 0 ;
48+ }
49+
50+ let step = remaining. abs ( ) . min ( max_step) ;
51+ let jitter = ( ( rng & 0x3 ) as i8 ) - 1 ; // [-1,0,1]
52+ let mut s = step + jitter;
53+ s = s. clamp ( 1 , step) ; // ensure at least 1 and not overshoot
54+
55+ if remaining < 0 { -s } else { s }
56+ }
57+
58+ pub fn generate_vector < const N : usize > ( & self , seed : u32 ) -> heapless:: Vec < ( i8 , i8 ) , N > {
59+ let mut vec: heapless:: Vec < ( i8 , i8 ) , N > = heapless:: Vec :: new ( ) ;
60+ let mut rng = seed;
61+
62+ // Total magnitude per axis
63+ let x_total = self . scale_seed ( seed) ;
64+ let y_total = self . scale_seed ( seed. rotate_left ( 13 ) ) ;
65+
66+ // Determine direction: 50% chance to flip axes
67+ let flip = ( rng & 1 ) == 1 ; // true => invert direction
68+ let ( mut x_remaining, mut y_remaining) = if flip {
69+ ( -x_total, -y_total)
70+ } else {
71+ ( x_total, y_total)
72+ } ;
73+
74+ // ---- Forward path with jitter + easing ----
75+ while ( x_remaining != 0 || y_remaining != 0 ) && !vec. is_full ( ) {
76+ rng = self . xorshift32 ( rng) ;
77+
78+ let x_step = self . step_toward_zero ( x_remaining, rng, self . step ) ;
79+ let y_step = self . step_toward_zero ( y_remaining, rng. rotate_left ( 5 ) , self . step ) ;
80+
81+ x_remaining -= x_step;
82+ y_remaining -= y_step;
83+
84+ vec. push ( ( x_step, y_step) ) . ok ( ) ;
4385 }
4486
45- // Mirror back to origin. Iterate in reverse over current values and push negated values
46- // until the vector is full.
47- // Note: negating a value in the expected range (1..=16) is safe for i8.
48- let clone = vec. clone ( ) ;
49- for & v in clone. iter ( ) . rev ( ) {
87+ // ---- Mirror back exactly ----
88+ let len = vec. len ( ) ;
89+ for i in ( 0 ..len) . rev ( ) {
5090 if vec. is_full ( ) {
5191 break ;
5292 }
53- // push negated value; ignore push failure because we checked is_full above
54- let _ = vec. push ( -v) ;
93+
94+ let ( x, y) = vec[ i] ;
95+ vec. push ( ( -x, -y) ) . ok ( ) ;
5596 }
97+
98+ vec
5699 }
57100}
0 commit comments