dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_streamfs.c
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  */
26 
27 /* Project Includes */
28 #include "pios.h"
29 
30 #include "pios_flash.h" /* PIOS_FLASH_* */
31 #include "pios_streamfs_priv.h" /* Internal API */
32 #include "pios_mutex.h"
33 #include "pios_semaphore.h"
34 #include "pios_thread.h"
35 
36 #include <stdbool.h>
37 #include <stddef.h> /* NULL */
38 
39 #define MIN(x,y) ((x) < (y) ? (x) : (y))
40 
55 #include <pios_com.h>
56 
57 #define PIOS_STREAMFS_TASK_PRIORITY PIOS_THREAD_PRIO_LOW
58 #define PIOS_STREAMFS_TASK_STACK_BYTES 1000
59 
60 /* Provide a COM driver */
61 static void PIOS_STREAMFS_RegisterTxCallback(uintptr_t fs_id, pios_com_callback tx_out_cb, uintptr_t context);
62 static void PIOS_STREAMFS_TxStart(uintptr_t fs_id, uint16_t tx_bytes_avail);
63 
67 };
68 
69 /*
70  * Filesystem state data tracked in RAM
71  */
72 
75 };
76 
79  const struct streamfs_cfg *cfg;
80 
81  /* pios_com interface */
82  struct pios_mutex *mutex;
84  struct pios_thread *task;
85 
87  uintptr_t rx_in_context;
89  uintptr_t tx_out_context;
90  uint8_t *com_buffer;
91 
92  /* Information for current file handle */
95  int32_t active_file_id;
99 
100  /* Information about file system contents */
101  int32_t min_file_id;
102  int32_t max_file_id;
103 
104  /* Underlying flash partition handle */
105  uintptr_t partition_id;
106  uint32_t partition_size;
108 };
109 
110 /*
111  * Internal Utility functions
112  */
113 
118 static uintptr_t streamfs_get_addr(const struct streamfs_state *streamfs, uint32_t arena_id, uint16_t arena_offset)
119 {
120  PIOS_Assert(arena_id < (streamfs->partition_size / streamfs->cfg->arena_size));
121  PIOS_Assert(arena_offset < streamfs->cfg->arena_size);
123  return (arena_id * streamfs->cfg->arena_size) + arena_offset;
124 }
125 
127  uint32_t magic;
128  uint32_t written_bytes;
129  uint32_t file_id;
130  uint16_t file_segment;
131 } __attribute__((packed));
132 
133 
134 /****************************************
135  * Arena life-cycle transition functions
136  ****************************************/
137 
143 static int32_t streamfs_erase_arena(const struct streamfs_state *streamfs, uint32_t arena_id)
144 {
145  uintptr_t arena_addr = streamfs_get_addr(streamfs, arena_id, 0);
146 
147  /* Erase all of the sectors in the arena */
148  if (PIOS_FLASH_erase_range(streamfs->partition_id, arena_addr, streamfs->cfg->arena_size) != 0) {
149  return -1;
150  }
151 
152  /* Arena is ready to be written to */
153  return 0;
154 }
155 
161 static int32_t streamfs_erase_all_arenas(const struct streamfs_state *streamfs)
162 {
163  uint32_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
164 
165  for (uint32_t arena = 0; arena < num_arenas; arena++) {
166  if (streamfs_erase_arena(streamfs, arena) != 0)
167  return -1;
168  }
169 
170  return 0;
171 }
172 
173 static bool streamfs_validate(const struct streamfs_state *streamfs)
174 {
175  return (streamfs && (streamfs->magic == PIOS_FLASHFS_STREAMFS_DEV_MAGIC));
176 }
177 
178 static struct streamfs_state *streamfs_alloc(void)
179 {
180  struct streamfs_state *streamfs;
181 
182  streamfs = (struct streamfs_state *)PIOS_malloc_no_dma(sizeof(*streamfs));
183  if (!streamfs) return (NULL);
184 
186  return(streamfs);
187 }
188 
193 /* NOTE: Must be called while holding the flash transaction lock */
194 static int32_t streamfs_new_sector(struct streamfs_state *streamfs)
195 {
196  struct streamfs_footer footer;
197  footer.magic = streamfs->cfg->fs_magic;
198  footer.written_bytes = streamfs->active_file_arena_offset;
199  footer.file_id = streamfs->active_file_id;
200  footer.file_segment = streamfs->active_file_segment;
201 
202  uint32_t start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
203  streamfs->cfg->arena_size - sizeof(footer));
204 
205  if (PIOS_FLASH_write_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
206  return -1;
207  }
208 
209  // Reset pointers for writing to next sector
210  streamfs->active_file_arena = (streamfs->active_file_arena + 1) % streamfs->partition_arenas;
211  streamfs->active_file_arena_offset = 0;
212  streamfs->active_file_segment++;
213 
214  // Test whether the sector has already been erased by checking the footer
215  start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
216  streamfs->cfg->arena_size - sizeof(footer));
217  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
218  return -2;
219  }
220 
221  for (int i=0; i < sizeof(footer); i++) {
222  if (((uint8_t*)&footer)[i] != 0xFF) {
223  if (streamfs_erase_arena(streamfs, streamfs->active_file_arena) != 0) {
224  return -3;
225  }
226  break;
227  }
228  }
229 
230  return 0;
231 }
232 
236 /* NOTE: Must be called while holding the flash transaction lock */
237 static int32_t streamfs_close_sector(struct streamfs_state *streamfs)
238 {
239  struct streamfs_footer footer;
240  footer.magic = streamfs->cfg->fs_magic;
241  footer.written_bytes = streamfs->active_file_arena_offset;
242  footer.file_id = streamfs->active_file_id;
243  footer.file_segment = streamfs->active_file_segment;
244 
245  uint32_t start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
246  streamfs->cfg->arena_size - sizeof(footer));
247 
248  if (PIOS_FLASH_write_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
249  return -1;
250  }
251 
252  return 0;
253 }
254 
255 
264 static int32_t streamfs_find_first_arena(struct streamfs_state *streamfs, int32_t file_id)
265 {
266  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
267 
268  bool found_file = false;
269  uint32_t min_segment = 0xFFFFFFFF;
270  uint32_t sector = 0xFFFFFFFF;
271 
272  for (uint16_t arena = 0; arena < num_arenas; arena++) {
273  // Read footer for each arena
274  struct streamfs_footer footer;
275  uint32_t start_address = streamfs_get_addr(streamfs, arena,
276  streamfs->cfg->arena_size - sizeof(footer));
277  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
278  return -1;
279  }
280 
281  if (footer.magic == streamfs->cfg->fs_magic && footer.file_id == file_id) {
282  found_file = true;
283  if (footer.file_segment < min_segment) {
284  min_segment = footer.file_segment;
285  sector = arena;
286  }
287  }
288  }
289 
290  if (found_file) {
291  return sector;
292  }
293 
294  return -2;
295 }
296 
305 static int32_t streamfs_find_last_arena(struct streamfs_state *streamfs, int32_t file_id)
306 {
307  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
308 
309  bool found_file = false;
310  int32_t max_segment = -1;
311  uint32_t sector = 0;
312 
313  for (uint16_t arena = 0; arena < num_arenas; arena++) {
314  // Read footer for each arena
315  struct streamfs_footer footer;
316  uint32_t start_address = streamfs_get_addr(streamfs, arena,
317  streamfs->cfg->arena_size - sizeof(footer));
318  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
319  return -3;
320  }
321 
322  if (footer.magic == streamfs->cfg->fs_magic && footer.file_id == file_id) {
323  found_file = true;
324  if (footer.file_segment > max_segment) {
325  max_segment = footer.file_segment;
326  sector = arena;
327  }
328  }
329  }
330 
331  if (found_file) {
332  return sector;
333  }
334 
335  return -4;
336 }
337 
345 static int32_t streamfs_find_new_sector(struct streamfs_state *streamfs)
346 {
347  // No files on file system
348  if (streamfs->max_file_id < 0) {
349  return 0;
350  }
351 
352  int32_t last_sector = streamfs_find_last_arena(streamfs, streamfs->max_file_id);
353  PIOS_Assert(last_sector >= 0);
354 
355  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
356  return (last_sector + 1) % num_arenas;
357 }
358 
359 /* NOTE: Must be called while holding the flash transaction lock */
360 static int32_t streamfs_append_to_file(struct streamfs_state *streamfs, uint8_t *data, uint32_t len)
361 {
362  if (!streamfs->file_open_writing)
363  return -1;
364 
365  if (streamfs->file_open_reading)
366  return -2;
367 
368  uint32_t total_written = 0;
369 
370  while (len > 0) {
371  uint32_t start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
372  streamfs->active_file_arena_offset);
373 
374  // Make sure not to write into the space for the footer
375  uint32_t bytes_to_write = len;
376  if ((streamfs->active_file_arena_offset + bytes_to_write) > (streamfs->cfg->arena_size - sizeof(struct streamfs_footer))) {
377  bytes_to_write = streamfs->cfg->arena_size - sizeof(struct streamfs_footer) - streamfs->active_file_arena_offset;
378  }
379 
380  if (PIOS_FLASH_write_data(streamfs->partition_id, start_address, data, bytes_to_write) != 0) {
381  return -3;
382  }
383 
384  // Increment pointers
385  streamfs->active_file_arena_offset += bytes_to_write;
386  len -= bytes_to_write;
387  total_written += bytes_to_write;
388  data = &data[bytes_to_write];
389 
390 
391  if (streamfs->active_file_arena_offset >= (streamfs->cfg->arena_size - sizeof(struct streamfs_footer))) {
392  if (streamfs_new_sector(streamfs) != 0) {
393  return -4;
394  }
395  }
396  }
397 
398  return total_written;
399 }
400 
401 /* NOTE: Must be called while holding the flash transaction lock */
402 static int32_t streamfs_read_from_file(struct streamfs_state *streamfs, uint8_t *data, uint32_t len)
403 {
404  if (streamfs->file_open_writing)
405  return -1;
406 
407  if (!streamfs->file_open_reading)
408  return -2;
409 
410  uint32_t total_read_len = 0;
411  int32_t current_segment = 0;
412  while (len > 0) {
413  struct streamfs_footer footer;
414  uint32_t start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
415  streamfs->cfg->arena_size - sizeof(footer));
416 
417  PIOS_Assert(start_address < streamfs->partition_size);
418  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
419  return -3;
420  }
421 
422  // Return error if at the end of the file
423  if (footer.magic != streamfs->cfg->fs_magic && footer.file_id != streamfs->active_file_id) {
424  return total_read_len;
425  }
426 
427  // Detected wrap around of file
428  if (footer.file_segment < current_segment) {
429  return total_read_len;
430  }
431 
432  // End of file
433  if (streamfs->active_file_arena_offset == footer.written_bytes) {
434  return total_read_len;
435  }
436 
437  start_address = streamfs_get_addr(streamfs, streamfs->active_file_arena,
438  streamfs->active_file_arena_offset);
439 
440  // Read either remaining bytes or until the footer
441  int32_t bytes_to_read = len;
442  if ((streamfs->active_file_arena_offset + bytes_to_read) > (streamfs->cfg->arena_size - sizeof(struct streamfs_footer))) {
443  bytes_to_read = streamfs->cfg->arena_size - sizeof(struct streamfs_footer) - streamfs->active_file_arena_offset;
444  }
445 
446  // Do not read more than valid bytes
447  if ((streamfs->active_file_arena_offset + bytes_to_read) > footer.written_bytes) {
448  bytes_to_read = footer.written_bytes - streamfs->active_file_arena_offset;
449  }
450 
451  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, data, bytes_to_read) != 0) {
452  return -3;
453  }
454 
455  // Increment pointers
456  len -= bytes_to_read;
457  total_read_len += bytes_to_read;
458  data = &data[bytes_to_read];
459 
460  streamfs->active_file_arena_offset += bytes_to_read;
461  PIOS_Assert(streamfs->active_file_arena_offset <= (streamfs->cfg->arena_size - sizeof(struct streamfs_footer)));
462  if (streamfs->active_file_arena_offset == streamfs->cfg->arena_size - sizeof(struct streamfs_footer)) {
463  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
464  streamfs->active_file_arena = (streamfs->active_file_arena + 1) % num_arenas;
465  streamfs->active_file_arena_offset = 0;
466  }
467  }
468 
469  return total_read_len;
470 }
471 
472 /* NOTE: Must be called while holding the flash transaction lock */
473 static int32_t streamfs_scan_filesystem(struct streamfs_state *streamfs)
474 {
475  // Don't try and read while actively writing
476  if (streamfs->file_open_writing)
477  return -1;
478  if (streamfs->file_open_reading)
479  return -2;
480 
481  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
482  streamfs->min_file_id = -1;
483  streamfs->max_file_id = 0;
484 
485  bool found_file = false;
486 
487  for (uint16_t arena = 0; arena < num_arenas; arena++) {
488  // Read footer for each arena
489  struct streamfs_footer footer;
490  uint32_t start_address = streamfs_get_addr(streamfs, arena,
491  streamfs->cfg->arena_size - sizeof(footer));
492  if (PIOS_FLASH_read_data(streamfs->partition_id, start_address, (uint8_t *) &footer, sizeof(footer)) != 0) {
493  return -3;
494  }
495 
496  if (footer.magic == streamfs->cfg->fs_magic) {
497  found_file = true;
498  if (footer.file_id < streamfs->min_file_id)
499  streamfs->min_file_id = footer.file_id;
500  if (footer.file_id > streamfs->max_file_id)
501  streamfs->max_file_id = footer.file_id;
502  }
503  }
504 
505  if (!found_file) {
506  streamfs->min_file_id = -1;
507  streamfs->max_file_id = -1;
508  }
509 
510  return 0;
511 }
512 
513 static void PIOS_STREAMFS_Task(void *parameters)
514 {
515  struct streamfs_state *streamfs = parameters;
516 
517  bool tmp = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
518  PIOS_Assert(tmp);
519 
520  while (1) {
521  int32_t bytes_to_write = 0;
522 
523  if (streamfs->tx_out_cb) {
524  bytes_to_write = (streamfs->tx_out_cb)(
525  streamfs->tx_out_context,
526  streamfs->com_buffer,
527  streamfs->cfg->write_size,
528  NULL, NULL);
529  }
530 
531  if (bytes_to_write <= 0) {
532  // Block here until woken.
533  PIOS_Mutex_Unlock(streamfs->mutex);
535  tmp = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
536  PIOS_Assert(tmp);
537  continue;
538  }
539 
540  if (!streamfs->file_open_writing) {
541  // Drain out pending data while file not open
542  continue;
543  }
544 
545  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
546  PIOS_Mutex_Unlock(streamfs->mutex);
547  PIOS_Thread_Sleep(50); // Don't spin
548  tmp = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
549  PIOS_Assert(tmp);
550  continue;
551  }
552 
553  // Flush available data from PIOS_COM interface to
554  // file system
555  while (bytes_to_write > 0) {
556  if (streamfs_append_to_file(streamfs, streamfs->com_buffer, bytes_to_write) != 0) {
557  break;
558  }
559 
560  bytes_to_write = (streamfs->tx_out_cb)(
561  streamfs->tx_out_context,
562  streamfs->com_buffer,
563  streamfs->cfg->write_size,
564  NULL, NULL);
565  }
566 
568  }
569 }
570 
571 /**********************************
572  *
573  * Public API
574  *
575  *********************************/
576 
581 int32_t PIOS_STREAMFS_Init(uintptr_t *fs_id, const struct streamfs_cfg *cfg, enum pios_flash_partition_labels partition_label)
582 {
583  PIOS_Assert(cfg);
584 
585  /* Find the partition id for the requested partition label */
586  uintptr_t partition_id;
587  if (PIOS_FLASH_find_partition_id(partition_label, &partition_id) != 0) {
588  return -1;
589  }
590 
591  /* Query the total partition size */
592  uint32_t partition_size;
593  if (PIOS_FLASH_get_partition_size(partition_id, &partition_size) != 0) {
594  return -1;
595  }
596 
597  /* sector_size must exactly divide the partition size */
598  PIOS_Assert((partition_size % cfg->arena_size) == 0);
599 
600  /* sector_size must exceed write_size */
601  PIOS_Assert(cfg->arena_size > cfg->write_size);
602 
603  int8_t rc;
604 
605  struct streamfs_state *streamfs;
606 
607  streamfs = (struct streamfs_state *) streamfs_alloc();
608  if (!streamfs) {
609  rc = -1;
610  goto out_exit;
611  }
612 
613  streamfs->com_buffer = (uint8_t *)PIOS_malloc(cfg->write_size);
614  if (!streamfs->com_buffer) {
615  PIOS_free(streamfs);
616  return -1;
617  }
618 
619  /* Bind configuration parameters to this filesystem instance */
620  streamfs->cfg = cfg; /* filesystem configuration */
621  streamfs->partition_id = partition_id; /* underlying partition */
622  streamfs->partition_size = partition_size; /* size of underlying partition */
623  streamfs->partition_arenas = partition_size / cfg->arena_size;
624 
625  streamfs->file_open_writing = false;
626  streamfs->file_open_reading = false;
627  streamfs->active_file_id = 0;
628  streamfs->active_file_arena = 0;
629  streamfs->active_file_arena_offset = 0;
630 
631  streamfs->mutex = PIOS_Mutex_Create();
632 
633  if (!streamfs->mutex) {
634  rc = -1;
635  goto out_exit;
636  }
637 
638  streamfs->sem = PIOS_Semaphore_Create();
639 
640  if (!streamfs->sem) {
641  rc = -1;
642  goto out_exit;
643  }
644 
645  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
646  rc = -1;
647  goto out_exit;
648  }
649 
650  // TODO: find the first sector after the last file
651  // TODO: validate that the partition is valid for streaming (magic?)
652 
653  // Scan filesystem contents
654  streamfs_scan_filesystem(streamfs);
655 
656  rc = 0;
657 
658  *fs_id = (uintptr_t) streamfs;
659 
660 //out_end_trans:
662 
664  "pios_streamfs", PIOS_STREAMFS_TASK_STACK_BYTES,
665  streamfs, PIOS_STREAMFS_TASK_PRIORITY);
666 
667 out_exit:
668  return rc;
669 }
670 
681 int32_t PIOS_STREAMFS_Format(uintptr_t fs_id)
682 {
683  int32_t rc;
684 
685  struct streamfs_state *streamfs = (struct streamfs_state *)
686  PIOS_COM_GetDriverCtx(fs_id);
687 
688  if (!streamfs_validate(streamfs)) {
689  rc = -1;
690  goto out_exit;
691  }
692 
693  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
694  rc = -2;
695  goto out_exit;
696  }
697 
698  if (streamfs_erase_all_arenas(streamfs) != 0) {
699  rc = -3;
700  goto out_end_trans;
701  }
702 
703  /* Chip erased and log remounted successfully */
704  rc = 0;
705 
706 out_end_trans:
708 
709 out_exit:
710  return rc;
711 }
712 
713 
714 /*
715  * File opening and closing utilities
716  */
717 
724 int32_t PIOS_STREAMFS_OpenWrite(uintptr_t fs_id)
725 {
726  int32_t rc;
727 
728  struct streamfs_state *streamfs = (struct streamfs_state *)
729  PIOS_COM_GetDriverCtx(fs_id);
730 
731  bool locked = false;
732 
733  if (!streamfs_validate(streamfs)) {
734  rc = -1;
735  goto out_exit;
736  }
737 
738  locked = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
739 
740  if (!locked) {
741  rc = -6;
742  goto out_exit;
743  }
744 
745  if (streamfs->file_open_writing) {
746  rc = -2;
747  goto out_exit;
748  }
749 
750  if (streamfs->file_open_reading) {
751  rc = -3;
752  goto out_exit;
753  }
754 
755  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
756  rc = -4;
757  goto out_exit;
758  }
759 
760  // TODO: use clever scheme to find where to start a new file
761  streamfs->active_file_id = streamfs->max_file_id + 1;
762  streamfs->active_file_segment = 0;
763  streamfs->active_file_arena = streamfs_find_new_sector(streamfs);
764  streamfs->active_file_arena_offset = 0;
765  streamfs->file_open_writing = true;
766 
767  // Erase this sector to prepare for streaming
768  if (streamfs_erase_arena(streamfs, streamfs->active_file_arena) != 0) {
769  rc = -5;
770  goto out_end_trans;
771  }
772 
773  rc = 0;
774 
775 out_end_trans:
777 
778 out_exit:
779  if (locked) {
780  PIOS_Mutex_Unlock(streamfs->mutex);
781  }
782 
783  return rc;
784 }
785 
786 int32_t PIOS_STREAMFS_OpenRead(uintptr_t fs_id, uint32_t file_id)
787 {
788  int32_t rc;
789 
790  struct streamfs_state *streamfs = (struct streamfs_state *)
791  PIOS_COM_GetDriverCtx(fs_id);
792  bool locked = false;
793 
794  if (!streamfs_validate(streamfs)) {
795  rc = -1;
796  goto out_exit;
797  }
798 
799  locked = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
800 
801  if (!locked) {
802  rc = -6;
803  goto out_exit;
804  }
805 
806  if (streamfs->file_open_writing) {
807  rc = -2;
808  goto out_exit;
809  }
810 
811  if (streamfs->file_open_reading) {
812  rc = -3;
813  goto out_exit;
814  }
815 
816  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
817  rc = -4;
818  goto out_exit;
819  }
820 
821  // Find start of file
822  streamfs->active_file_arena = streamfs_find_first_arena(streamfs, file_id);
823  if (streamfs->active_file_arena >= 0) {
824  streamfs->active_file_id = file_id;
825  streamfs->active_file_segment = 0;
826  streamfs->active_file_arena_offset = 0;
827  streamfs->file_open_reading = true;
828  } else {
829  streamfs->active_file_arena = 0;
830  rc = -5;
831  goto out_end_trans;
832  }
833 
834  rc = 0;
835 
836 out_end_trans:
838 
839 out_exit:
840  if (locked) {
841  PIOS_Mutex_Unlock(streamfs->mutex);
842  }
843 
844  return rc;
845 }
846 
847 int32_t PIOS_STREAMFS_MinFileId(uintptr_t fs_id)
848 {
849  struct streamfs_state *streamfs = (struct streamfs_state *)
850  PIOS_COM_GetDriverCtx(fs_id);
851 
852  if (!streamfs_validate(streamfs)) {
853  return -1;
854  }
855 
856  return streamfs->min_file_id;
857 }
858 
859 int32_t PIOS_STREAMFS_MaxFileId(uintptr_t fs_id)
860 {
861  struct streamfs_state *streamfs = (struct streamfs_state *)
862  PIOS_COM_GetDriverCtx(fs_id);
863 
864  if (!streamfs_validate(streamfs)) {
865  return -1;
866  }
867 
868  return streamfs->max_file_id;
869 }
870 
871 int32_t PIOS_STREAMFS_Close(uintptr_t fs_id)
872 {
873  int32_t rc;
874 
875  struct streamfs_state *streamfs = (struct streamfs_state *)
876  PIOS_COM_GetDriverCtx(fs_id);
877 
878  bool locked = false;
879 
880  if (!streamfs_validate(streamfs)) {
881  rc = -1;
882  goto out_exit;
883  }
884 
885  locked = PIOS_Mutex_Lock(streamfs->mutex, PIOS_MUTEX_TIMEOUT_MAX);
886 
887  if (!locked) {
888  rc = -6;
889  goto out_exit;
890  }
891 
892  if (streamfs->file_open_reading) {
893  streamfs->file_open_reading = false;
894  rc = 0;
895  goto out_exit;
896  }
897 
898  if (!streamfs->file_open_writing) {
899  rc = -2;
900  goto out_exit;
901  }
902 
903  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
904  rc = -2;
905  goto out_exit;
906  }
907 
908  if (streamfs->active_file_arena_offset != 0) {
909  // Close segment when something has been written. This avoids creating
910  // null files with an open/close operation
911  if (streamfs_close_sector(streamfs) != 0) {
912  rc = -3;
913  goto out_end_trans;
914  }
915  }
916 
917 
918  // TODO: make sure to flush remaining data
919  streamfs->file_open_writing = false;
920 
921  if (streamfs_scan_filesystem(streamfs) != 0) {
922  rc = -4;
923  goto out_end_trans;
924  }
925 
926  rc = 0;
927 
928 out_end_trans:
930 
931 out_exit:
932  if (locked) {
933  PIOS_Mutex_Unlock(streamfs->mutex);
934  }
935 
936  return rc;
937 }
938 
939 /* Read API */
940 
941 int32_t PIOS_STREAMFS_Read(uintptr_t fs_id, uint8_t *data, uint32_t len) {
942  int32_t rc;
943 
944  struct streamfs_state *streamfs = (struct streamfs_state *)
945  PIOS_COM_GetDriverCtx(fs_id);
946 
947  bool valid = streamfs_validate(streamfs);
948  PIOS_Assert(valid);
949 
950  uint16_t num_arenas = streamfs->partition_size / streamfs->cfg->arena_size;
951  if (streamfs->file_open_writing)
952  return -3;
953 
954  if (!streamfs->file_open_reading)
955  return -4;
956 
957  if (streamfs->active_file_arena >= num_arenas)
958  return -1;
959 
960  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
961  return -2;
962  }
963 
964  rc = streamfs_read_from_file(streamfs, data, len);
965  if (rc < 0) {
966  rc = -5;
967  }
968 
970 
971  return rc;
972 }
973 
974 // Testing methods for unit tests
975 int32_t PIOS_STREAMFS_Testing_Write(uintptr_t fs_id, uint8_t *data, uint32_t len)
976 {
977  int32_t rc;
978 
979  struct streamfs_state *streamfs = (struct streamfs_state *)fs_id;
980 
981  bool valid = streamfs_validate(streamfs);
982  PIOS_Assert(valid);
983 
984  if (PIOS_FLASH_start_transaction(streamfs->partition_id) != 0) {
985  rc = -1;
986  goto out_exit;
987  }
988 
989  rc = streamfs_append_to_file (streamfs, data, len);
990  if (rc < 0) {
991  rc = -2;
992  goto out_end_trans;
993  }
994 
995  rc = 0;
996 
997 out_end_trans:
999 
1000 out_exit:
1001  return rc;
1002 }
1003 
1004 
1005 /**********************************
1006  *
1007  * Provide a PIOS_COM driver for TX (logging) side
1008  *
1009  *********************************/
1010 
1011 static void PIOS_STREAMFS_TxStart(uintptr_t fs_id, uint16_t tx_bytes_avail)
1012 {
1013  struct streamfs_state *streamfs = (struct streamfs_state *)fs_id;
1014 
1015  bool valid = streamfs_validate(streamfs);
1016  PIOS_Assert(valid);
1017 
1018  PIOS_Semaphore_Give(streamfs->sem);
1019 }
1020 
1021 static void PIOS_STREAMFS_RegisterTxCallback(uintptr_t fs_id, pios_com_callback tx_out_cb, uintptr_t context)
1022 {
1023  struct streamfs_state *streamfs = (struct streamfs_state *)fs_id;
1024 
1025  bool valid = streamfs_validate(streamfs);
1026  PIOS_Assert(valid);
1027 
1028  /*
1029  * Order is important in these assignments since ISR uses _cb
1030  * field to determine if it's ok to dereference _cb and _context
1031  */
1032  streamfs->tx_out_context = context;
1033  streamfs->tx_out_cb = tx_out_cb;
1034 
1035  /* Wake up the TX thread, justin case */
1036  PIOS_Semaphore_Give(streamfs->sem);
1037 }
1038 
struct pios_mutex * mutex
Definition: pios_streamfs.c:82
int32_t PIOS_STREAMFS_Init(uintptr_t *fs_id, const struct streamfs_cfg *cfg, enum pios_flash_partition_labels partition_label)
Initialize the flash object setting FS.
int32_t PIOS_FLASH_find_partition_id(enum pios_flash_partition_labels label, uintptr_t *partition_id)
int32_t active_file_arena
Definition: pios_streamfs.c:97
pios_flashfs_streamfs_dev_magic
Definition: pios_streamfs.c:73
static void PIOS_STREAMFS_TxStart(uintptr_t fs_id, uint16_t tx_bytes_avail)
#define PIOS_SEMAPHORE_TIMEOUT_MAX
const struct pios_com_driver pios_streamfs_com_driver
Definition: pios_streamfs.c:64
Main PiOS header to include all the compiled in PiOS options.
static int32_t streamfs_find_new_sector(struct streamfs_state *streamfs)
struct pios_semaphore * sem
Definition: pios_streamfs.c:83
static int32_t streamfs_close_sector(struct streamfs_state *streamfs)
const struct streamfs_cfg * cfg
Definition: pios_streamfs.c:79
COM layer functions header.
int32_t PIOS_FLASH_get_partition_size(uintptr_t partition_id, uint32_t *partition_size)
#define PIOS_STREAMFS_TASK_PRIORITY
Definition: pios_streamfs.c:57
int32_t min_file_id
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
int32_t max_file_id
int32_t PIOS_STREAMFS_OpenRead(uintptr_t fs_id, uint32_t file_id)
static int32_t streamfs_erase_arena(const struct streamfs_state *streamfs, uint32_t arena_id)
Erases all sectors within the given arena and sets arena to erased state.
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
pios_com_callback tx_out_cb
Definition: pios_streamfs.c:88
bool PIOS_Mutex_Unlock(struct pios_mutex *mtx)
Definition: pios_mutex.c:104
static int32_t streamfs_find_first_arena(struct streamfs_state *streamfs, int32_t file_id)
struct pios_mutex * PIOS_Mutex_Create(void)
Definition: pios_mutex.c:43
int32_t PIOS_STREAMFS_Close(uintptr_t fs_id)
int32_t PIOS_STREAMFS_MinFileId(uintptr_t fs_id)
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
static void PIOS_STREAMFS_RegisterTxCallback(uintptr_t fs_id, pios_com_callback tx_out_cb, uintptr_t context)
uintptr_t rx_in_context
Definition: pios_streamfs.c:87
static uintptr_t streamfs_get_addr(const struct streamfs_state *streamfs, uint32_t arena_id, uint16_t arena_offset)
Return the offset in flash of a particular slot within an arena.
int32_t PIOS_FLASH_write_data(uintptr_t partition_id, uint32_t offset, const uint8_t *data, uint16_t len)
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
uint32_t partition_arenas
int32_t PIOS_FLASH_end_transaction(uintptr_t partition_id)
int32_t PIOS_STREAMFS_Testing_Write(uintptr_t fs_id, uint8_t *data, uint32_t len)
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
uintptr_t PIOS_COM_GetDriverCtx(uintptr_t com_id)
bool file_open_writing
Definition: pios_streamfs.c:93
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
static int32_t streamfs_find_last_arena(struct streamfs_state *streamfs, int32_t file_id)
struct pios_thread * task
Definition: pios_streamfs.c:84
static int32_t streamfs_append_to_file(struct streamfs_state *streamfs, uint8_t *data, uint32_t len)
int32_t PIOS_STREAMFS_OpenWrite(uintptr_t fs_id)
uint32_t partition_size
#define PIOS_STREAMFS_TASK_STACK_BYTES
Definition: pios_streamfs.c:58
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
static bool streamfs_validate(const struct streamfs_state *streamfs)
bool file_open_reading
Definition: pios_streamfs.c:94
static int32_t streamfs_new_sector(struct streamfs_state *streamfs)
int32_t active_file_id
Definition: pios_streamfs.c:95
int32_t PIOS_FLASH_erase_range(uintptr_t partition_id, uint32_t start_offset, uint32_t size)
static int32_t streamfs_scan_filesystem(struct streamfs_state *streamfs)
enum pios_flashfs_streamfs_dev_magic magic
Definition: pios_streamfs.c:78
int32_t active_file_arena_offset
Definition: pios_streamfs.c:98
void PIOS_free(void *buf)
Definition: pios_heap.c:174
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
static int32_t streamfs_erase_all_arenas(const struct streamfs_state *streamfs)
Erases all arenas available to this filesystem instance.
uintptr_t tx_out_context
Definition: pios_streamfs.c:89
int32_t PIOS_STREAMFS_Read(uintptr_t fs_id, uint8_t *data, uint32_t len)
uintptr_t partition_id
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
pios_flash_partition_labels
Definition: pios_flash.h:31
static void PIOS_STREAMFS_Task(void *parameters)
int32_t active_file_segment
Definition: pios_streamfs.c:96
int32_t PIOS_FLASH_read_data(uintptr_t partition_id, uint32_t offset, uint8_t *data, uint16_t len)
uint32_t file_id
int32_t PIOS_FLASH_start_transaction(uintptr_t partition_id)
int32_t PIOS_STREAMFS_Format(uintptr_t fs_id)
Erases all filesystem arenas and activate the first arena.
static int32_t streamfs_read_from_file(struct streamfs_state *streamfs, uint8_t *data, uint32_t len)
int32_t PIOS_STREAMFS_MaxFileId(uintptr_t fs_id)
static struct streamfs_state * streamfs_alloc(void)
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void(* tx_start)(uintptr_t id, uint16_t tx_bytes_avail)
Definition: pios_com.h:45
uint8_t * com_buffer
Definition: pios_streamfs.c:90
uint16_t(* pios_com_callback)(uintptr_t context, uint8_t *buf, uint16_t buf_len, uint16_t *headroom, bool *task_woken)
Definition: pios_com.h:41
pios_com_callback rx_in_cb
Definition: pios_streamfs.c:86
#define PIOS_MUTEX_TIMEOUT_MAX
Definition: pios_mutex.h:30
typedef __attribute__
Definition: serial_4way.h:43
bool PIOS_Mutex_Lock(struct pios_mutex *mtx, uint32_t timeout_ms)
Definition: pios_mutex.c:66