1use crate::attribute_set::EvdevEnum;
2use crate::compat::{ff_condition_effect, ff_envelope, ff_replay, ff_trigger};
3use crate::constants::FFEffectCode;
4use crate::sys;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct FFEnvelope {
9 pub attack_length: u16,
11 pub attack_level: u16,
13 pub fade_length: u16,
15 pub fade_level: u16,
17}
18
19impl From<ff_envelope> for FFEnvelope {
20 fn from(value: ff_envelope) -> Self {
21 Self {
22 attack_length: value.attack_length,
23 attack_level: value.attack_level,
24 fade_length: value.fade_length,
25 fade_level: value.fade_level,
26 }
27 }
28}
29
30impl From<FFEnvelope> for ff_envelope {
31 fn from(other: FFEnvelope) -> Self {
32 ff_envelope {
33 attack_length: other.attack_length,
34 attack_level: other.attack_level,
35 fade_length: other.fade_length,
36 fade_level: other.fade_level,
37 }
38 }
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
43pub enum FFWaveform {
44 Square,
46 Triangle,
48 Sine,
50 SawUp,
52 SawDown,
54}
55
56impl From<FFWaveform> for FFEffectCode {
57 fn from(other: FFWaveform) -> Self {
58 match other {
59 FFWaveform::Square => FFEffectCode::FF_SQUARE,
60 FFWaveform::Triangle => FFEffectCode::FF_TRIANGLE,
61 FFWaveform::Sine => FFEffectCode::FF_SINE,
62 FFWaveform::SawUp => FFEffectCode::FF_SAW_UP,
63 FFWaveform::SawDown => FFEffectCode::FF_SAW_DOWN,
64 }
65 }
66}
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub struct FFCondition {
71 pub right_saturation: u16,
73 pub left_saturation: u16,
75 pub right_coefficient: i16,
78 pub left_coefficient: i16,
80 pub deadband: u16,
82 pub center: i16,
84}
85
86impl From<ff_condition_effect> for FFCondition {
87 fn from(value: ff_condition_effect) -> Self {
88 Self {
89 right_saturation: value.right_saturation,
90 left_saturation: value.left_saturation,
91 right_coefficient: value.right_coeff,
92 left_coefficient: value.left_coeff,
93 deadband: value.deadband,
94 center: value.center,
95 }
96 }
97}
98
99impl From<FFCondition> for ff_condition_effect {
100 fn from(other: FFCondition) -> Self {
101 ff_condition_effect {
102 right_saturation: other.right_saturation,
103 left_saturation: other.left_saturation,
104 right_coeff: other.right_coefficient,
105 left_coeff: other.left_coefficient,
106 deadband: other.deadband,
107 center: other.center,
108 }
109 }
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
113pub enum FFEffectKind {
114 Damper,
115 Inertia,
116 Constant {
117 level: i16,
119 envelope: FFEnvelope,
121 },
122 Ramp {
123 start_level: i16,
125 end_level: i16,
127 envelope: FFEnvelope,
129 },
130 Periodic {
131 waveform: FFWaveform,
133 period: u16,
135 magnitude: i16,
137 offset: i16,
139 phase: u16,
141 envelope: FFEnvelope,
143 },
144 Spring {
145 condition: [FFCondition; 2],
147 },
148 Friction {
149 condition: [FFCondition; 2],
151 },
152 Rumble {
153 strong_magnitude: u16,
155 weak_magnitude: u16,
157 },
158}
159
160impl From<FFEffectKind> for FFEffectCode {
161 fn from(other: FFEffectKind) -> Self {
162 match other {
163 FFEffectKind::Damper => FFEffectCode::FF_DAMPER,
164 FFEffectKind::Inertia => FFEffectCode::FF_INERTIA,
165 FFEffectKind::Constant { .. } => FFEffectCode::FF_CONSTANT,
166 FFEffectKind::Ramp { .. } => FFEffectCode::FF_RAMP,
167 FFEffectKind::Periodic { .. } => FFEffectCode::FF_PERIODIC,
168 FFEffectKind::Spring { .. } => FFEffectCode::FF_SPRING,
169 FFEffectKind::Friction { .. } => FFEffectCode::FF_FRICTION,
170 FFEffectKind::Rumble { .. } => FFEffectCode::FF_RUMBLE,
171 }
172 }
173}
174
175#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
177pub struct FFTrigger {
178 pub button: u16,
180 pub interval: u16,
182}
183
184impl From<ff_trigger> for FFTrigger {
185 fn from(value: ff_trigger) -> Self {
186 Self {
187 button: value.button,
188 interval: value.interval,
189 }
190 }
191}
192
193impl From<FFTrigger> for ff_trigger {
194 fn from(other: FFTrigger) -> Self {
195 ff_trigger {
196 button: other.button,
197 interval: other.interval,
198 }
199 }
200}
201
202#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
204pub struct FFReplay {
205 pub length: u16,
207 pub delay: u16,
209}
210
211impl From<ff_replay> for FFReplay {
212 fn from(value: ff_replay) -> Self {
213 Self {
214 length: value.length,
215 delay: value.delay,
216 }
217 }
218}
219
220impl From<FFReplay> for ff_replay {
221 fn from(other: FFReplay) -> Self {
222 ff_replay {
223 length: other.length,
224 delay: other.delay,
225 }
226 }
227}
228
229#[derive(Clone, Copy, Debug, Eq, PartialEq)]
230pub struct FFEffectData {
231 pub direction: u16,
233 pub trigger: FFTrigger,
235 pub replay: FFReplay,
237 pub kind: FFEffectKind,
239}
240
241impl From<sys::ff_effect> for FFEffectData {
242 fn from(value: sys::ff_effect) -> Self {
243 let kind = match FFEffectCode::from_index(value.type_ as usize) {
244 FFEffectCode::FF_DAMPER => FFEffectKind::Damper,
245 FFEffectCode::FF_INERTIA => FFEffectKind::Inertia,
246 FFEffectCode::FF_CONSTANT => {
247 let constant = unsafe { value.u.constant };
248
249 FFEffectKind::Constant {
250 level: constant.level,
251 envelope: constant.envelope.into(),
252 }
253 }
254 FFEffectCode::FF_RAMP => {
255 let ramp = unsafe { value.u.ramp };
256
257 FFEffectKind::Ramp {
258 start_level: ramp.start_level,
259 end_level: ramp.end_level,
260 envelope: ramp.envelope.into(),
261 }
262 }
263 FFEffectCode::FF_PERIODIC => {
264 let periodic = unsafe { value.u.periodic };
265
266 FFEffectKind::Periodic {
267 waveform: match FFEffectCode::from_index(periodic.waveform as usize) {
268 FFEffectCode::FF_SQUARE => FFWaveform::Square,
269 FFEffectCode::FF_TRIANGLE => FFWaveform::Triangle,
270 FFEffectCode::FF_SINE => FFWaveform::Sine,
271 FFEffectCode::FF_SAW_UP => FFWaveform::SawUp,
272 FFEffectCode::FF_SAW_DOWN => FFWaveform::SawDown,
273 _ => unreachable!(),
274 },
275 period: periodic.period,
276 magnitude: periodic.magnitude,
277 offset: periodic.offset,
278 phase: periodic.phase,
279 envelope: periodic.envelope.into(),
280 }
281 }
282 FFEffectCode::FF_SPRING => {
283 let condition = unsafe { value.u.condition };
284
285 FFEffectKind::Spring {
286 condition: [condition[0].into(), condition[1].into()],
287 }
288 }
289 FFEffectCode::FF_FRICTION => {
290 let condition = unsafe { value.u.condition };
291
292 FFEffectKind::Friction {
293 condition: [condition[0].into(), condition[1].into()],
294 }
295 }
296 FFEffectCode::FF_RUMBLE => {
297 let rumble = unsafe { value.u.rumble };
298
299 FFEffectKind::Rumble {
300 strong_magnitude: rumble.strong_magnitude,
301 weak_magnitude: rumble.weak_magnitude,
302 }
303 }
304 _ => unreachable!(),
305 };
306
307 Self {
308 direction: value.direction,
309 trigger: value.trigger.into(),
310 replay: value.replay.into(),
311 kind,
312 }
313 }
314}
315
316impl From<FFEffectData> for sys::ff_effect {
317 fn from(other: FFEffectData) -> Self {
318 let mut effect: sys::ff_effect = unsafe { std::mem::zeroed() };
319
320 let type_: FFEffectCode = other.kind.into();
321 effect.type_ = type_.0;
322 effect.direction = other.direction;
323 effect.trigger = other.trigger.into();
324 effect.replay = other.replay.into();
325
326 match other.kind {
327 FFEffectKind::Constant { level, envelope } => {
328 effect.u.constant.level = level;
329 effect.u.constant.envelope = envelope.into();
330 }
331 FFEffectKind::Ramp {
332 start_level,
333 end_level,
334 envelope,
335 } => {
336 effect.u.ramp.start_level = start_level;
337 effect.u.ramp.end_level = end_level;
338 effect.u.ramp.envelope = envelope.into();
339 }
340 FFEffectKind::Periodic {
341 waveform,
342 period,
343 magnitude,
344 offset,
345 phase,
346 envelope,
347 } => {
348 let waveform: FFEffectCode = waveform.into();
349 effect.u.periodic.waveform = waveform.0;
350 effect.u.periodic.period = period;
351 effect.u.periodic.magnitude = magnitude;
352 effect.u.periodic.offset = offset;
353 effect.u.periodic.phase = phase;
354 effect.u.periodic.envelope = envelope.into();
355 }
356 FFEffectKind::Spring { condition } | FFEffectKind::Friction { condition } => {
357 effect.u.condition = [condition[0].into(), condition[1].into()];
358 }
359 FFEffectKind::Rumble {
360 strong_magnitude,
361 weak_magnitude,
362 } => {
363 effect.u.rumble.strong_magnitude = strong_magnitude;
364 effect.u.rumble.weak_magnitude = weak_magnitude;
365 }
366 _ => (),
367 }
368
369 effect
370 }
371}