1use super::*;
10
11const CATEGORY_FLASH: u32 = 1;
12
13const CMD_ERASE: u32 = 0;
14const CMD_READ: u32 = 1;
15const CMD_WRITE: u32 = 2;
16const CMD_STATUS: u32 = 3;
17const CMD_SESSION_BASE: u32 = 4;
18const CMD_LOCK: u32 = 5;
19
20pub const BLOCK_QUADLET_COUNT: usize = 64;
22
23#[derive(Default, Debug, Clone, PartialEq, Eq)]
25pub struct EfwFlashErase {
26 pub offset: u32,
28}
29
30impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwFlashErase> for O
31where
32 O: EfwHardwareSpecification,
33 P: EfwProtocolExtManual,
34{
35 fn update_wholly(proto: &mut P, states: &EfwFlashErase, timeout_ms: u32) -> Result<(), Error> {
36 assert_eq!(states.offset % 4, 0);
37
38 let args = [states.offset];
39 let mut params = Vec::new();
40 proto.transaction(CATEGORY_FLASH, CMD_ERASE, &args, &mut params, timeout_ms)
41 }
42}
43
44#[derive(Default, Debug, Clone, PartialEq, Eq)]
46pub struct EfwFlashRead {
47 pub offset: u32,
49 pub data: Vec<u32>,
51}
52
53impl<O, P> EfwWhollyCachableParamsOperation<P, EfwFlashRead> for O
54where
55 O: EfwHardwareSpecification,
56 P: EfwProtocolExtManual,
57{
58 fn cache_wholly(
59 proto: &mut P,
60 states: &mut EfwFlashRead,
61 timeout_ms: u32,
62 ) -> Result<(), Error> {
63 assert_eq!(states.offset % 4, 0);
64 assert!(states.data.len() <= BLOCK_QUADLET_COUNT);
65
66 let count = states.data.len();
67 let args = [states.offset, count as u32];
68 let mut params = vec![0; 2 + BLOCK_QUADLET_COUNT];
69
70 proto
71 .transaction(CATEGORY_FLASH, CMD_READ, &args, &mut params, timeout_ms)
72 .map(|_| states.data.copy_from_slice(¶ms[2..(2 + count)]))
73 }
74}
75
76#[derive(Default, Debug, Clone, PartialEq, Eq)]
78pub struct EfwFlashWrite {
79 pub offset: u32,
81 pub data: Vec<u32>,
83}
84
85impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwFlashWrite> for O
86where
87 O: EfwHardwareSpecification,
88 P: EfwProtocolExtManual,
89{
90 fn update_wholly(proto: &mut P, states: &EfwFlashWrite, timeout_ms: u32) -> Result<(), Error> {
91 assert_eq!(states.offset % 4, 0);
92 assert!(states.data.len() <= BLOCK_QUADLET_COUNT);
93
94 let mut args = vec![0; 2 + BLOCK_QUADLET_COUNT];
95 args[0] = states.offset;
96 args[1] = states.data.len() as u32;
97 args[2..(2 + states.data.len())].copy_from_slice(&states.data);
98
99 let mut params = Vec::new();
100
101 proto.transaction(CATEGORY_FLASH, CMD_WRITE, &args, &mut params, timeout_ms)
102 }
103}
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq)]
107pub enum EfwFlashState {
108 Unlocked,
110 Locked,
112}
113
114impl Default for EfwFlashState {
115 fn default() -> Self {
116 Self::Unlocked
117 }
118}
119
120impl<O, P> EfwWhollyCachableParamsOperation<P, EfwFlashState> for O
121where
122 O: EfwHardwareSpecification,
123 P: EfwProtocolExtManual,
124{
125 fn cache_wholly(
126 proto: &mut P,
127 states: &mut EfwFlashState,
128 timeout_ms: u32,
129 ) -> Result<(), Error> {
130 let args = Vec::new();
131 let mut params = Vec::new();
132 proto
133 .transaction(CATEGORY_FLASH, CMD_STATUS, &args, &mut params, timeout_ms)
134 .map(|_| *states = EfwFlashState::Unlocked)
135 .or_else(|e| {
136 if e.kind::<EfwProtocolError>() == Some(EfwProtocolError::FlashBusy) {
137 *states = EfwFlashState::Locked;
138 Ok(())
139 } else {
140 Err(e)
141 }
142 })
143 }
144}
145
146impl<O, P> EfwWhollyUpdatableParamsOperation<P, EfwFlashState> for O
147where
148 O: EfwHardwareSpecification,
149 P: EfwProtocolExtManual,
150{
151 fn update_wholly(proto: &mut P, states: &EfwFlashState, timeout_ms: u32) -> Result<(), Error> {
152 let args = vec![states.eq(&EfwFlashState::Locked) as u32];
153 let mut params = Vec::new();
154 proto.transaction(CATEGORY_FLASH, CMD_LOCK, &args, &mut params, timeout_ms)
155 }
156}
157
158#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
160pub struct EfwFlashSessionBase(pub u32);
161
162impl<O, P> EfwWhollyCachableParamsOperation<P, EfwFlashSessionBase> for O
163where
164 O: EfwHardwareSpecification,
165 P: EfwProtocolExtManual,
166{
167 fn cache_wholly(
168 proto: &mut P,
169 states: &mut EfwFlashSessionBase,
170 timeout_ms: u32,
171 ) -> Result<(), Error> {
172 let args = Vec::new();
173 let mut params = vec![0];
174 proto
175 .transaction(
176 CATEGORY_FLASH,
177 CMD_SESSION_BASE,
178 &args,
179 &mut params,
180 timeout_ms,
181 )
182 .map(|_| states.0 = params[0])
183 }
184}
185
186#[cfg(test)]
187mod test {
188 use super::*;
189 use glib::{translate::FromGlib, SignalHandlerId};
190 use std::cell::RefCell;
191
192 const BLOCK_SIZE: usize = 4 * BLOCK_QUADLET_COUNT as usize;
193 const TIMEOUT: u32 = 10;
194
195 struct TestProtocol;
196
197 impl EfwHardwareSpecification for TestProtocol {
198 const SUPPORTED_SAMPLING_RATES: &'static [u32] = &[];
199 const SUPPORTED_SAMPLING_CLOCKS: &'static [ClkSrc] = &[];
200 const CAPABILITIES: &'static [HwCap] = &[];
201 const RX_CHANNEL_COUNTS: [usize; 3] = [0; 3];
202 const TX_CHANNEL_COUNTS: [usize; 3] = [0; 3];
203 const MONITOR_SOURCE_COUNT: usize = 0;
204 const MONITOR_DESTINATION_COUNT: usize = 0;
205 const MIDI_INPUT_COUNT: usize = 0;
206 const MIDI_OUTPUT_COUNT: usize = 0;
207 const PHYS_INPUT_GROUPS: &'static [(PhysGroupType, usize)] = &[];
208 const PHYS_OUTPUT_GROUPS: &'static [(PhysGroupType, usize)] = &[];
209 }
210
211 #[derive(Default)]
212 struct TestInstance(RefCell<StateMachine>);
213
214 #[test]
215 fn flash_lock_test() {
216 let mut proto = TestInstance::default();
217
218 let mut state = EfwFlashState::default();
220 TestProtocol::cache_wholly(&mut proto, &mut state, TIMEOUT).unwrap();
221
222 let erase = EfwFlashErase { offset: 256 };
224 let err = TestProtocol::update_wholly(&mut proto, &erase, TIMEOUT).unwrap_err();
225 assert_eq!(
226 err.kind::<EfwProtocolError>(),
227 Some(EfwProtocolError::FlashBusy)
228 );
229
230 let write = EfwFlashWrite {
232 offset: 256,
233 data: vec![0; 16],
234 };
235 let err = TestProtocol::update_wholly(&mut proto, &write, TIMEOUT).unwrap_err();
236 assert_eq!(
237 err.kind::<EfwProtocolError>(),
238 Some(EfwProtocolError::FlashBusy)
239 );
240
241 let mut read = EfwFlashRead {
243 offset: 0,
244 data: vec![0; 64],
245 };
246 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
247
248 let state = EfwFlashState::Unlocked;
250 TestProtocol::update_wholly(&mut proto, &state, TIMEOUT).unwrap();
251
252 TestProtocol::update_wholly(&mut proto, &erase, TIMEOUT).unwrap();
254
255 TestProtocol::update_wholly(&mut proto, &write, TIMEOUT).unwrap();
257
258 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
260
261 let state = EfwFlashState::Locked;
263 TestProtocol::update_wholly(&mut proto, &state, TIMEOUT).unwrap();
264
265 let mut state = EfwFlashState::default();
266 TestProtocol::cache_wholly(&mut proto, &mut state, TIMEOUT).unwrap();
267 assert_eq!(state, EfwFlashState::Locked);
268
269 let err = TestProtocol::update_wholly(&mut proto, &erase, TIMEOUT).unwrap_err();
271 assert_eq!(
272 err.kind::<EfwProtocolError>(),
273 Some(EfwProtocolError::FlashBusy)
274 );
275
276 let err = TestProtocol::update_wholly(&mut proto, &write, TIMEOUT).unwrap_err();
278 assert_eq!(
279 err.kind::<EfwProtocolError>(),
280 Some(EfwProtocolError::FlashBusy)
281 );
282
283 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
285 }
286
287 #[test]
288 fn flash_update_test() {
289 let mut proto = TestInstance::default();
290
291 let count = proto.0.borrow().memory.len() / 4;
292 (0..count).for_each(|i| {
293 let pos = i * 4;
294 proto.0.borrow_mut().memory[pos..(pos + 4)].copy_from_slice(&(i as u32).to_be_bytes());
295 });
296
297 let state = EfwFlashState::Unlocked;
298 TestProtocol::update_wholly(&mut proto, &state, TIMEOUT).unwrap();
299
300 let erase = EfwFlashErase { offset: 256 };
301 TestProtocol::update_wholly(&mut proto, &erase, TIMEOUT).unwrap();
302
303 let mut read = EfwFlashRead {
305 offset: 248,
306 data: vec![0; 16],
307 };
308 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
309
310 let mut read = EfwFlashRead {
312 offset: 504,
313 data: vec![0; 8],
314 };
315 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
316 assert_eq!(&read.data, &[0, 0, 128, 129, 130, 131, 132, 133]);
317
318 let data = (0..BLOCK_QUADLET_COUNT)
320 .map(|i| u32::MAX - i as u32)
321 .collect();
322 let write = EfwFlashWrite { offset: 256, data };
323 TestProtocol::update_wholly(&mut proto, &write, TIMEOUT).unwrap();
324
325 let mut read = EfwFlashRead {
327 offset: 504,
328 data: vec![0; 6],
329 };
330 TestProtocol::cache_wholly(&mut proto, &mut read, TIMEOUT).unwrap();
331 assert_eq!(&read.data, &[4294967233, 4294967232, 128, 129, 130, 131]);
332 }
333
334 struct StateMachine {
335 memory: [u8; 4 * BLOCK_SIZE],
338 locked: bool,
340 }
341
342 impl Default for StateMachine {
343 fn default() -> Self {
344 Self {
345 memory: [0; 4 * BLOCK_SIZE],
346 locked: true,
347 }
348 }
349 }
350
351 impl StateMachine {
352 fn erase_block(&mut self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
353 if params.len() > 0 {
354 Err(Error::new(
355 EfwProtocolError::BadParameter,
356 "Useless parameter is given",
357 ))
358 } else if args.len() < 1 {
359 Err(Error::new(
360 EfwProtocolError::BadCommand,
361 "Argument is shorter than expected",
362 ))
363 } else {
364 let pos = (args[0] as usize) / BLOCK_SIZE * BLOCK_SIZE;
366 if pos == 0 {
367 Err(Error::new(
368 EfwProtocolError::BadCommand,
369 "The first block is immutable",
370 ))
371 } else if pos > self.memory.len() {
372 Err(Error::new(
373 EfwProtocolError::BadCommand,
374 "The offset is out of range",
375 ))
376 } else if self.locked {
377 Err(Error::new(
378 EfwProtocolError::FlashBusy,
379 "The flash memory is locked",
380 ))
381 } else {
382 self.memory[pos..(pos + BLOCK_SIZE)].fill(0);
383 Ok(())
384 }
385 }
386 }
387
388 fn read_data(&self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
389 if args.len() < 2 {
390 Err(Error::new(
391 EfwProtocolError::BadCommand,
392 "Argument is shorter than expected",
393 ))
394 } else {
395 let offset = args[0] as usize;
396 let count = args[1] as usize;
397 if count >= BLOCK_SIZE {
398 let msg = "The count of data should be less than size of block";
399 Err(Error::new(EfwProtocolError::BadCommand, &msg))
400 } else if offset + 4 * count > self.memory.len() {
401 Err(Error::new(
402 EfwProtocolError::BadCommand,
403 "The offset plus count is out of range",
404 ))
405 } else {
406 if params.len() < 2 + count {
407 Err(Error::new(
408 EfwProtocolError::BadParameter,
409 "Parameter is shorter than expected",
410 ))
411 } else {
412 params[0] = offset as u32;
413 params[1] = count as u32;
414
415 let mut quadlet = [0; 4];
416 params[2..].iter_mut().enumerate().for_each(|(i, d)| {
417 let pos = offset as usize + i * 4;
418 quadlet.copy_from_slice(&self.memory[pos..(pos + 4)]);
419 *d = u32::from_be_bytes(quadlet);
420 });
421 Ok(())
422 }
423 }
424 }
425 }
426
427 fn write_data(&mut self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
428 if params.len() > 0 {
429 Err(Error::new(
430 EfwProtocolError::BadParameter,
431 "Useless parameter is given",
432 ))
433 } else if args.len() < 3 {
434 Err(Error::new(
435 EfwProtocolError::BadCommand,
436 "Argument is shorter than expected",
437 ))
438 } else {
439 let offset = args[0] as usize;
440 if offset < BLOCK_SIZE {
441 Err(Error::new(
442 EfwProtocolError::BadCommand,
443 "The first block is immutable",
444 ))
445 } else {
446 let count = args[1] as usize;
447 let data = &args[2..];
448
449 if data.len() < count {
450 Err(Error::new(
451 EfwProtocolError::BadCommand,
452 "Contradiction between count and data",
453 ))
454 } else if data.len() > BLOCK_QUADLET_COUNT {
455 let msg = "The count of data should be less than size of block";
456 Err(Error::new(EfwProtocolError::BadCommand, msg))
457 } else if offset + 4 * data.len() > self.memory.len() {
458 Err(Error::new(
459 EfwProtocolError::BadCommand,
460 "The offset plus length is out of range",
461 ))
462 } else if self.locked {
463 Err(Error::new(
464 EfwProtocolError::FlashBusy,
465 "The flash memory is locked",
466 ))
467 } else {
468 data.iter().enumerate().for_each(|(i, d)| {
469 let pos = offset + i * 4;
470 self.memory[pos..(pos + 4)].copy_from_slice(&d.to_be_bytes());
471 });
472 Ok(())
473 }
474 }
475 }
476 }
477
478 fn get_status(&self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
479 if args.len() > 0 {
480 Err(Error::new(
481 EfwProtocolError::BadCommand,
482 "Useless argument is given",
483 ))
484 } else if params.len() > 0 {
485 Err(Error::new(
486 EfwProtocolError::BadParameter,
487 "Useless parameter is given",
488 ))
489 } else if self.locked {
490 Err(Error::new(
491 EfwProtocolError::FlashBusy,
492 "The flash memory is locked",
493 ))
494 } else {
495 Ok(())
496 }
497 }
498
499 fn get_session_base(&self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
500 if args.len() > 0 {
501 Err(Error::new(
502 EfwProtocolError::BadCommand,
503 "Useless argument is given",
504 ))
505 } else if params.len() < 1 {
506 Err(Error::new(
507 EfwProtocolError::BadParameter,
508 "Parameter is shorter than expected",
509 ))
510 } else {
511 params[0] = BLOCK_SIZE as u32;
512 Ok(())
513 }
514 }
515
516 fn lock_memory(&mut self, args: &[u32], params: &mut Vec<u32>) -> Result<(), Error> {
517 if params.len() > 0 {
518 Err(Error::new(
519 EfwProtocolError::BadCommand,
520 "Useless parameter is given",
521 ))
522 } else if args.len() < 1 {
523 Err(Error::new(
524 EfwProtocolError::BadParameter,
525 "Argument is shorter than expected",
526 ))
527 } else {
528 self.locked = args[0] > 0;
529 Ok(())
530 }
531 }
532 }
533
534 impl EfwProtocolExtManual for TestInstance {
535 fn transaction(
536 &self,
537 category: u32,
538 command: u32,
539 args: &[u32],
540 params: &mut Vec<u32>,
541 _: u32,
542 ) -> Result<(), glib::Error> {
543 assert_eq!(category, CATEGORY_FLASH);
544 match command {
545 CMD_ERASE => self.0.borrow_mut().erase_block(args, params),
546 CMD_READ => self.0.borrow_mut().read_data(args, params),
547 CMD_WRITE => self.0.borrow_mut().write_data(args, params),
548 CMD_STATUS => self.0.borrow_mut().get_status(args, params),
549 CMD_SESSION_BASE => self.0.borrow_mut().get_session_base(args, params),
550 CMD_LOCK => self.0.borrow_mut().lock_memory(args, params),
551 _ => unreachable!(),
552 }
553 }
554
555 fn emit_responded(&self, _: u32, _: u32, _: u32, _: u32, _: EfwProtocolError, _: &[u32]) {
556 }
558
559 fn connect_responded<F>(&self, _f: F) -> SignalHandlerId
560 where
561 F: Fn(&Self, u32, u32, u32, u32, EfwProtocolError, &[u32]) + 'static,
562 {
563 unsafe { SignalHandlerId::from_glib(0) }
565 }
566 }
567}