2 * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 use std::io::{Read, Write};
25 use std::os::unix::io::FromRawFd;
26 use common::buffer::{Buffer, BufferUserData};
27 use common::fixed15_49;
29 use common::storage::{Storage, Error};
30 use common::logger::{MEMORY_SIZE, Logger, Error as LoggerError};
32 type Fixed = fixed15_49::Fixed15_49;
40 fn new() -> FakeStorage {
42 expected: vec![0xff; MEMORY_SIZE].into_boxed_slice(),
43 actual: vec![0xff; MEMORY_SIZE].into_boxed_slice(),
48 impl Storage for FakeStorage {
49 fn size(&self) -> usize {
53 fn read(&self, address: usize, buffer: &mut [u8]) {
54 for i in 0..buffer.len() {
55 buffer[i] = self.actual[address + i];
59 fn write(&mut self, address: usize, buffer: &[u8; 4096]) -> Result<(), Error> {
60 if (address & 4095) != 0 {
61 return Err(Error::UnalignedAddress);
64 for i in 0..buffer.len() {
65 self.actual[address + i] = buffer[i];
71 fn erase(&mut self, address: usize) -> Result<(), Error> {
72 if (address & 4095) != 0 {
73 return Err(Error::UnalignedAddress);
77 self.actual[address + i] = 0xff;
85 self.actual = vec![0xff; MEMORY_SIZE].into_boxed_slice();
95 let mut pipe_fd = [-1i32; 2];
99 fn pipe2(pipefd: *mut i32, flags: i32) -> i32;
102 const O_NONBLOCK : i32 = 0x800;
104 pipe2(pipe_fd.as_mut_ptr(), O_NONBLOCK);
112 fn read_fd(&self) -> i32 {
116 fn write_fd(&self) -> i32 {
121 // Runs a couple of recordings on fully erased flash memory.
123 fn first_recording() {
124 let mut fake_storage = FakeStorage::new();
126 let mut logger = Logger::new(&mut fake_storage);
129 let tap = gps::TimeAndPos {
131 unix_time: 1478026311,
132 latitude_deg: 0x73234e,
133 longitude_deg: 0x73234f,
134 latitude_rad: Fixed::from_f32(12.57613).to_radians(),
135 longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
138 let recording_id = logger.start_recording(&tap);
139 assert_eq!(1, recording_id);
141 let sectors_written = logger.stop_recording(&tap);
142 assert_eq!(1, sectors_written);
146 0x01, 0x00, 0x01, 0x00,
147 0x47, 0xe4, 0x18, 0x58,
152 0x9c, 0x8d, 0x99, 0x07,
153 0x9e, 0x8d, 0x99, 0x07,
156 0xff, 0xff, 0xff, 0xff, 0x0f,
163 let end = start + expected.len();
164 fake_storage.expected[start..end].copy_from_slice(&expected);
166 assert_eq!(fake_storage.expected, fake_storage.actual);
170 fn second_recording() {
171 let mut fake_storage = FakeStorage::new();
173 // Mark first sector as in use.
176 0x01, 0x00, 0x01, 0x00,
179 fake_storage.expected[0..recording0.len()].copy_from_slice(&recording0);
180 fake_storage.actual[0..recording0.len()].copy_from_slice(&recording0);
182 let mut logger = Logger::new(&mut fake_storage);
185 let tap = gps::TimeAndPos {
187 unix_time: 1478026312,
188 latitude_deg: 0x73234e,
189 longitude_deg: 0x73234f,
190 latitude_rad: Fixed::from_f32(12.57613).to_radians(),
191 longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
194 let recording_id = logger.start_recording(&tap);
195 assert_eq!(2, recording_id);
197 let sectors_written = logger.stop_recording(&tap);
198 assert_eq!(1, sectors_written);
202 0x01, 0x00, 0x02, 0x00,
203 0x48, 0xe4, 0x18, 0x58,
208 0x9c, 0x8d, 0x99, 0x07,
209 0x9e, 0x8d, 0x99, 0x07,
212 0xff, 0xff, 0xff, 0xff, 0x0f,
219 let end = start + expected.len();
220 fake_storage.expected[start..end].copy_from_slice(&expected);
222 assert_eq!(fake_storage.expected, fake_storage.actual);
226 fn multi_sector_recording() {
227 let mut fake_storage = FakeStorage::new();
229 let mut logger = Logger::new(&mut fake_storage);
232 let tap = gps::TimeAndPos {
234 unix_time: 1578425250,
235 latitude_deg: 0x73234e,
236 longitude_deg: 0x73234f,
237 latitude_rad: Fixed::from_f32(12.57613).to_radians(),
238 longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
241 let recording_id = logger.start_recording(&tap);
242 assert_eq!(1, recording_id);
244 let mut prev_tap = tap;
247 let tap = gps::TimeAndPos {
249 unix_time: prev_tap.unix_time + 1,
250 latitude_deg: prev_tap.latitude_deg + 1,
251 longitude_deg: prev_tap.longitude_deg + 1,
252 latitude_rad: Fixed::from_f32(
253 (prev_tap.latitude_deg + 1) as f32 / 600000.0).to_radians(),
254 longitude_rad: Fixed::from_f32(
255 (prev_tap.longitude_deg + 1) as f32 / 600000.0).to_radians(),
258 logger.log(&prev_tap, &tap);
263 let sectors_written = logger.stop_recording(&tap);
264 assert_eq!(2, sectors_written);
267 0x01, 0x00, 0x01, 0x00,
271 0x03, 0x00, 0x01, 0x00,
274 assert_eq!(header0, fake_storage.actual[0..(0 + header0.len())]);
275 assert_eq!(header1, fake_storage.actual[4096..(4096 + header1.len())]);
278 extern "C" fn flush_write_buffer(user_data: *mut BufferUserData,
281 count: usize) -> isize {
282 let _file = user_data as *mut std::fs::File;
285 let file = &mut * _file;
287 file.write_all(std::slice::from_raw_parts(buf, count)).unwrap();
293 // Verifies that Logger::get_recording() detects unknown recording IDs.
295 fn get_recording_invalid() {
296 let pipe = Pipe::new();
298 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
300 let mut yenc_buffer_space = [0u8; 8192];
301 let mut yenc_buffer = Buffer::alloc();
303 let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
305 yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
306 yenc_buffer_space.len(),
310 let mut fake_storage = FakeStorage::new();
312 let mut logger = Logger::new(&mut fake_storage);
315 // Zero is never a valid recording id.
316 let result = logger.get_recording(0, &mut yenc_buffer);
317 assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
319 let result = logger.get_recording(1, &mut yenc_buffer);
320 assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
323 // Verifies that Logger::get_recording() can retrieve finished recordings.
325 fn get_recording_valid() {
326 let pipe = Pipe::new();
328 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
330 let mut yenc_buffer_space = [0u8; 8192];
331 let mut yenc_buffer = Buffer::alloc();
333 let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
335 yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
336 yenc_buffer_space.len(),
340 let mut fake_storage = FakeStorage::new();
342 let mut logger = Logger::new(&mut fake_storage);
345 let result = logger.get_recording(1, &mut yenc_buffer);
346 assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
348 let tap0 = gps::TimeAndPos {
350 unix_time: 1478026311,
351 latitude_deg: 0x73234e,
352 longitude_deg: 0x73234f,
353 latitude_rad: Fixed::from_f32(12.57613).to_radians(),
354 longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
357 logger.start_recording(&tap0);
359 let tap1 = gps::TimeAndPos {
361 unix_time: 1478026311 + 1,
362 latitude_deg: 0x73234e + 5,
363 longitude_deg: 0x73234f + 5,
364 latitude_rad: Fixed::from_f32(12.576138333333333).to_radians(),
365 longitude_rad: Fixed::from_f32(12.57614).to_radians(),
368 logger.log(&tap0, &tap1);
370 let tap2 = gps::TimeAndPos {
372 unix_time: 1478026311 + 2,
373 latitude_deg: 0x73234e + 10,
374 longitude_deg: 0x73234f + 10,
375 latitude_rad: Fixed::from_f32(12.576146666666666).to_radians(),
376 longitude_rad: Fixed::from_f32(12.576148333333334).to_radians(),
379 logger.log(&tap1, &tap2);
381 logger.stop_recording(&tap2);
383 assert!(logger.get_recording(1, &mut yenc_buffer).is_ok());
386 // Verifies that Logger::list_recordings() shows an empty listing
387 // if there are no recordings.
389 fn list_recordings0() {
390 let pipe = Pipe::new();
392 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
394 let mut ls_buffer_space = [0u8; 4096];
395 let mut ls_buffer = Buffer::alloc();
397 let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
399 ls_buffer.init(ls_buffer_space.as_mut_ptr(),
400 ls_buffer_space.len(),
404 let mut fake_storage = FakeStorage::new();
406 let mut logger = Logger::new(&mut fake_storage);
409 logger.list_recordings(&mut ls_buffer);
411 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.read_fd()) };
413 let mut listing_raw = [0u8; 256];
415 // There are no recordings, so there's no data in the pipe either.
416 assert!(file.read(&mut listing_raw).is_err());
419 // Verifies that Logger::list_recordings() shows a listing
420 // of a single recording in the very first sector.
422 fn list_recordings1() {
423 let pipe = Pipe::new();
425 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
427 let mut ls_buffer_space = [0u8; 4096];
428 let mut ls_buffer = Buffer::alloc();
430 let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
432 ls_buffer.init(ls_buffer_space.as_mut_ptr(),
433 ls_buffer_space.len(),
437 let mut fake_storage = FakeStorage::new();
439 // Mark first sector as in use.
442 0x01, 0x00, 0x01, 0x00,
443 0xa2, 0xdb, 0x14, 0x5e,
446 fake_storage.expected[0..recording0.len()].copy_from_slice(&recording0);
447 fake_storage.actual[0..recording0.len()].copy_from_slice(&recording0);
449 let mut logger = Logger::new(&mut fake_storage);
452 logger.list_recordings(&mut ls_buffer);
454 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.read_fd()) };
456 let mut listing_raw = [0u8; 256];
457 let num_bytes_read = file.read(&mut listing_raw).unwrap();
459 let expected_bytes = b"\
460 2020-01-07 19:27:30 4K 1\n";
462 assert_eq!(String::from_utf8(expected_bytes.to_vec()).unwrap(),
463 String::from_utf8(listing_raw[0..num_bytes_read].to_vec()).unwrap());
466 // Verifies that Logger::list_recordings() handles sectors holding
467 // additional recording data.
469 fn list_recording1_multi_sector() {
470 let pipe = Pipe::new();
472 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
474 let mut ls_buffer_space = [0u8; 4096];
475 let mut ls_buffer = Buffer::alloc();
477 let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
479 ls_buffer.init(ls_buffer_space.as_mut_ptr(),
480 ls_buffer_space.len(),
484 let mut fake_storage = FakeStorage::new();
486 // The first sector starts recording 1.
489 0x01, 0x00, 0x01, 0x00,
490 0x75, 0x18, 0x17, 0x5e,
493 // The second sector has additional data for recording 1.
495 0x03, 0x00, 0x01, 0x00,
498 fake_storage.actual[0..header0.len()].copy_from_slice(&header0);
499 fake_storage.actual[4096..4096 + header1.len()].copy_from_slice(&header1);
501 let mut logger = Logger::new(&mut fake_storage);
504 logger.list_recordings(&mut ls_buffer);
506 let mut file = unsafe { std::fs::File::from_raw_fd(pipe.read_fd()) };
508 let mut listing_raw = [0u8; 4096];
509 let num_bytes_read = file.read(&mut listing_raw).unwrap();
511 let expected_bytes = b"\
512 2020-01-09 12:11:33 8K 1\n";
514 assert_eq!(String::from_utf8(expected_bytes.to_vec()).unwrap(),
515 String::from_utf8(listing_raw[0..num_bytes_read].to_vec()).unwrap());
518 // Verifies that Logger::remove_recording() reports an error if there is no
519 // recording with the given ID.
521 fn remove_recording0() {
522 let mut fake_storage = FakeStorage::new();
524 let mut logger = Logger::new(&mut fake_storage);
527 let result = logger.remove_recording(42);
528 assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
531 // Verifies that Logger::remove_recording() clears consecutive sectors
532 // belonging to the recording identified by the given ID.
534 fn remove_recording1() {
535 let mut fake_storage = FakeStorage::new();
537 // Mark first sector as in use.
539 0x01, 0x00, 0x01, 0x00,
540 0xa2, 0xdb, 0x14, 0x5e,
543 // Mark second sector as in use by the same recording.
545 0x03, 0x00, 0x01, 0x00,
546 0x00, 0x00, 0x00, 0x00,
549 // Mark third sector as in use by another recording.
551 0x01, 0x00, 0x02, 0x00,
552 0xa2, 0xdb, 0x14, 0x5f,
555 fake_storage.actual[0..header0.len()].copy_from_slice(&header0);
556 fake_storage.actual[4096..4096 + header1.len()].copy_from_slice(&header1);
557 fake_storage.actual[8192..8192 + header2.len()].copy_from_slice(&header2);
559 let mut logger = Logger::new(&mut fake_storage);
562 assert!(logger.remove_recording(1).is_ok());
565 0xff, 0xff, 0xff, 0xff,
566 0xff, 0xff, 0xff, 0xff,
569 fake_storage.expected[0..cleared.len()].copy_from_slice(&cleared);
570 fake_storage.expected[4096..4096 + header1.len()].copy_from_slice(&cleared);
571 fake_storage.expected[8192..8192 + header2.len()].copy_from_slice(&header2);
573 assert_eq!(fake_storage.expected, fake_storage.actual);
578 let mut fake_storage = FakeStorage::new();
580 let mut logger = Logger::new(&mut fake_storage);
584 (49.372117, 8.820219),
585 (49.372229, 8.821636),
588 let template = gps::TimeAndPos {
593 latitude_rad: Fixed::from_f32(0.0),
594 longitude_rad: Fixed::from_f32(0.0),
597 let mut taps = [template; 11];
599 for i in 0..taps.len() {
600 taps[i].system_time = (i as u32) * 100;
601 taps[i].unix_time = i as u32;
602 taps[i].latitude_rad = Fixed::from_f32(lat_lon[i % lat_lon.len()].0).to_radians();
603 taps[i].longitude_rad = Fixed::from_f32(lat_lon[i % lat_lon.len()].1).to_radians();
606 logger.start_recording(&taps[0]);
608 for i in 0..(taps.len() - 1) {
609 logger.log(&taps[i], &taps[i + 1]);
612 assert_eq!(logger.pace_s, 10);