Contiki-Inga 3.x
fat_coop.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Institute of Operating Systems and Computer Networks (TU Brunswick).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Author: Christoph Peltz <peltz@ibr.cs.tu-bs.de>
30  */
31 
32 /**
33  * \addtogroup cfs
34  * @{
35  *
36  * \addtogroup fat_coop_driver
37  * @{
38  */
39 
40 /**
41  * \file
42  * FAT driver coop additions implementation
43  * \author
44  * Christoph Peltz <peltz@ibr.cs.tu-bs.de>
45  */
46 
47 #include "cfs-fat.h"
48 #include "fat_coop.h"
49 #include "watchdog.h"
50 #include "fat-coop-arch.h"
51 
52 #define DEBUG 0
53 #if DEBUG
54 #include <stdio.h>
55 #define PRINTF(...) printf(__VA_ARGS__)
56 #else
57 #define PRINTF(...)
58 #endif
59 
60 #define MS_TO_TICKS(ms) ((uint32_t)(ms * (RTIMER_SECOND / 1000.0f)))
61 
62 #define FAT_COOP_SLOT_SIZE_TICKS MS_TO_TICKS(FAT_COOP_SLOT_SIZE_MS)
63 #define FAT_COOP_TIME_READ_BLOCK_TICKS MS_TO_TICKS(FAT_COOP_TIME_READ_BLOCK_MS)
64 #define FAT_COOP_TIME_WRITE_BLOCK_TICKS MS_TO_TICKS(FAT_COOP_TIME_WRITE_BLOCK_MS)
65 
66 enum {
67  READ = 1,
68  WRITE,
69  INTERNAL
70 };
71 
72 static process_event_t coop_global_event_id = 0;
73 static uint8_t next_token = 0;
74 
75 uint8_t writeBuffer[FAT_COOP_BUFFER_SIZE];
76 uint16_t writeBuffer_start, writeBuffer_len;
77 
78 QueueEntry queue[FAT_COOP_QUEUE_SIZE];
79 Event_OperationFinished op_results[FAT_COOP_QUEUE_SIZE];
80 uint16_t queue_start, queue_len;
81 
82 uint8_t coop_step_allowed = 0;
83 
84 uint8_t next_step_type = INTERNAL;
85 
86 /** From fat.c */
87 extern struct file_system mounted;
88 
89 /** From fat.c */
90 extern struct file fat_file_pool[FAT_FD_POOL_SIZE];
91 
92 /** From fat.c */
93 extern struct file_desc fat_fd_pool[FAT_FD_POOL_SIZE];
94 
95 void coop_mt_init(void *data);
96 void coop_switch_sp();
97 QueueEntry* queue_current_entry();
98 void perform_next_step(QueueEntry *entry);
99 void finish_operation(QueueEntry *entry);
100 uint8_t time_left_for_step(uint8_t step_type);
101 uint8_t try_internal_operation();
102 uint8_t queue_rm_top_entry();
103 uint8_t queue_add_entry(QueueEntry *entry);
104 void pop_from_buffer(uint16_t length);
105 uint32_t time_left();
106 uint8_t time_for_step(uint8_t step_type);
107 
108 PROCESS(fsp, "FileSystemProcess");
109 /*----------------------------------------------------------------------------*/
110 process_event_t
111 get_coop_event_id()
112 {
113  if (coop_global_event_id == 0) {
114  // Request global ID from contiki
115  coop_global_event_id = process_alloc_event();
116  }
117 
118  return coop_global_event_id;
119 }
120 /*----------------------------------------------------------------------------*/
121 void
122 printQueueEntry(QueueEntry *entry)
123 {
124  printf("\nQueueEntry %u", (uint16_t) entry);
125  printf("\n\ttoken = %u", entry->token);
126  printf("\n\tsource_process = %u", (uint16_t) entry->source_process);
127  printf("\n\top = ");
128 
129  switch (entry->op) {
130  case COOP_CFS_OPEN:
131  printf("COOP_CFS_OPEN");
132  printf("\n\tname = %s", entry->parameters.open.name);
133  printf("\n\tflags = %d", entry->parameters.open.flags);
134  break;
135  case COOP_CFS_CLOSE:
136  printf("COOP_CFS_CLOSE");
137  printf("\n\tfd = %d", entry->parameters.generic.fd);
138  printf("\n\tbuffer = %u", (uint16_t) entry->parameters.generic.buffer);
139  printf("\n\tlength = %u", entry->parameters.generic.length);
140  break;
141  case COOP_CFS_WRITE:
142  printf("COOP_CFS_WRITE");
143  printf("\n\tfd = %d", entry->parameters.generic.fd);
144  printf("\n\tbuffer = %u", (uint16_t) entry->parameters.generic.buffer);
145  printf("\n\tlength = %u", entry->parameters.generic.length);
146  break;
147  case COOP_CFS_READ:
148  printf(" COOP_CFS_READ");
149  printf("\n\tfd = %d", entry->parameters.generic.fd);
150  printf("\n\tbuffer = %u", (uint16_t) entry->parameters.generic.buffer);
151  printf("\n\tlength = %u", entry->parameters.generic.length);
152  break;
153  case COOP_CFS_SEEK:
154  printf(" COOP_CFS_SEEK");
155  printf("\n\tfd = %d", entry->parameters.seek.fd);
156  printf("\n\toffset = %lu", (uint32_t) entry->parameters.seek.offset);
157  printf("\n\twhence = %d", entry->parameters.seek.whence);
158  break;
159  case COOP_CFS_REMOVE:
160  printf("OOP_CFS_REMOVE");
161  printf("\n\tname = %s", entry->parameters.open.name);
162  break;
163  case COOP_CFS_OPENDIR:
164  printf("OP_CFS_OPENDIR");
165  break;
166  case COOP_CFS_READDIR:
167  printf("OP_CFS_READDIR");
168  break;
169  case COOP_CFS_CLOSEDIR:
170  printf("OP_CFS_CLOSEDIR");
171  break;
172  }
173 
174  printf("\n\tstate = %u", entry->state);
175  printf("\n\tret_value = %d", entry->ret_value);
176 }
177 /*----------------------------------------------------------------------------*/
178 void
179 operation(void *data)
180 {
181  QueueEntry *entry = (QueueEntry *) data;
182 
183  coop_step_allowed = 1;
184 
185  if (entry->state != STATUS_INPROGRESS) {
186  entry->state = STATUS_INPROGRESS;
187  }
188 
189  switch (entry->op) {
190  case COOP_CFS_OPEN:
191  PRINTF("FSP: opening file %s\n", entry->parameters.open.name);
192  int fd = entry->ret_value;
193  entry->ret_value = cfs_open(entry->parameters.open.name, entry->parameters.open.flags);
194  if (entry->ret_value == -1) {
195  fat_fd_pool[fd].file = NULL;
196  }
197  break;
198  case COOP_CFS_CLOSE:
199  PRINTF("FSP: closing file\n");
200  cfs_close(entry->parameters.generic.fd);
201  break;
202  case COOP_CFS_WRITE:
203  PRINTF("FSP: write to file\n");
204  /** FIXME: Ring Buffer functionality does not work, because cfs_write does not know, that the buffer may wrap around */
205  entry->ret_value = cfs_write(entry->parameters.generic.fd, entry->parameters.generic.buffer,
206  entry->parameters.generic.length);
207  pop_from_buffer(entry->parameters.generic.length);
208  break;
209  case COOP_CFS_READ:
210  PRINTF("FSP: read from file\n");
211  entry->ret_value = cfs_read(entry->parameters.generic.fd, entry->parameters.generic.buffer,
212  entry->parameters.generic.length);
213  break;
214  case COOP_CFS_SEEK:
215  PRINTF("FSP: seek in file\n");
216  entry->ret_value = cfs_seek(entry->parameters.seek.fd, entry->parameters.seek.offset,
217  entry->parameters.seek.whence);
218  break;
219  case COOP_CFS_REMOVE:
220  PRINTF("FSP: removing file %s\n", entry->parameters.open.name);
221  entry->ret_value = cfs_remove(entry->parameters.open.name);
222  break;
223  case COOP_CFS_OPENDIR:
224  entry->ret_value = cfs_opendir(entry->parameters.dir.dirp, entry->parameters.dir.u.name);
225  break;
226  case COOP_CFS_READDIR:
227  entry->ret_value = cfs_readdir(entry->parameters.dir.dirp, entry->parameters.dir.u.dirent);
228  break;
229  case COOP_CFS_CLOSEDIR:
230  cfs_closedir(entry->parameters.dir.dirp);
231  break;
232  }
233 
234  entry->state = STATUS_DONE;
235  op_results[queue_start].token = entry->token;
236  op_results[queue_start].ret_value = entry->ret_value;
237 }
238 /*----------------------------------------------------------------------------*/
239 PROCESS_THREAD(fsp, ev, data)
240 {
241  static uint32_t deadline = 0;
242  static QueueEntry *entry;
243  static uint16_t operations = 0;
244 
245  PROCESS_BEGIN();
246 
247  while (1) {
249 
250  // How long is time for processing?
251  deadline = RTIMER_NOW() + time_left();
252 
253  entry = queue_current_entry();
254 
255  while (entry != NULL && deadline > RTIMER_NOW()) {
256  uint32_t my_end = RTIMER_NOW() + time_for_step(next_step_type);
257 
259  perform_next_step(entry);
260 
261  if (entry->state == STATUS_DONE) {
262  PRINTF("FSP: Operation finished\n");
263  finish_operation(entry);
264  entry = queue_current_entry();
265  operations ++;
266  }
267  }
268  }
269 
270  PROCESS_END();
271 }
272 /*----------------------------------------------------------------------------*/
273 uint8_t
274 try_internal_operation()
275 {
276  // Write dirty cache back
277  // fat_flush()
278  // Write max. n changed sectors of the FAT (To be implemented in FAT-Driver)
279  // fat_sync_fats(x);
280  return 0;
281 }
282 /*----------------------------------------------------------------------------*/
283 /**
284  * Sends a Message to the source_process of the Entry and removes the Entry from the queue.
285  *
286  * \param *entry The entry which should be finished.
287  */
288 void
289 finish_operation(QueueEntry *entry)
290 {
291  // Send Event to source process
292  process_post(entry->source_process, get_coop_event_id(), &(op_results[queue_start]));
293 
294  // Remove entry
295  queue_rm_top_entry();
296 
297  /* Init the internal Stack for the next Operation */
298  entry = queue_current_entry();
299 
300  if (entry != NULL) {
301  coop_mt_init((void *) entry);
302  } else {
303  coop_mt_stop();
304  }
305 }
306 /*----------------------------------------------------------------------------*/
307 uint32_t time_left()
308 {
309  uint32_t time_left = 0;
310 
311  // We have time for maximum one step
312  time_left = FAT_COOP_SLOT_SIZE_TICKS;
313 
314  // If we do have a timer, maximum time may also be shorter
315  if( etimer_next_expiration_time() != 0 ) {
316  uint32_t time_left_etimer = (((uint32_t) (etimer_next_expiration_time() - clock_time())) * ((uint32_t) RTIMER_ARCH_SECOND)) / CLOCK_SECOND;
317 
318  // Safety margin
319  time_left_etimer -= 5;
320 
321  if( time_left_etimer < time_left ) {
322  time_left = time_left_etimer;
323  }
324  }
325 
326  return time_left;
327 }
328 /*----------------------------------------------------------------------------*/
329 uint8_t
330 time_for_step(uint8_t step_type)
331 {
332  uint8_t result = 0;
333 
334  if (step_type == INTERNAL ) {
335  result = 0;
336  }
337 
338  if (step_type == READ ) {
339  result = FAT_COOP_TIME_READ_BLOCK_TICKS;
340  }
341 
342  if (step_type == WRITE ) {
343  result = FAT_COOP_TIME_WRITE_BLOCK_TICKS;
344  }
345 
346  // Add a 5 tick safety margin
347  result += 5;
348 
349  return result;
350 }
351 /*----------------------------------------------------------------------------*/
352 uint8_t
353 time_left_for_step(uint8_t step_type)
354 {
355  if( time_left() > time_for_step(step_type) ) {
356  return 1;
357  }
358 
359  return 0;
360 }
361 /*----------------------------------------------------------------------------*/
362 QueueEntry*
363 queue_current_entry()
364 {
365  if (queue_len == 0) {
366  return NULL;
367  }
368 
369  return &(queue[queue_start]);
370 }
371 uint8_t
372 queue_add_entry(QueueEntry *entry)
373 {
374  uint16_t pos = (queue_start + queue_len) % FAT_COOP_QUEUE_SIZE;
375 
376  if (pos == queue_start && queue_len > 0) {
377  return 1;
378  }
379 
380  memcpy(&(queue[pos]), entry, sizeof (QueueEntry));
381  queue_len++;
382 
383  return 0;
384 }
385 /*----------------------------------------------------------------------------*/
386 uint8_t
387 queue_rm_top_entry()
388 {
389  if (queue_len == 0) {
390  return 1;
391  }
392 
393  queue_start = (queue_start + 1) % FAT_COOP_QUEUE_SIZE;
394  queue_len--;
395 
396  return 0;
397 }
398 /*----------------------------------------------------------------------------*/
399 /**
400  * This function is used to buffer the payload of write requests in a ring buffer
401  * However, the ring functionality does not work
402  */
403 uint8_t
404 push_on_buffer(uint8_t *source, uint16_t length)
405 {
406  uint16_t pos = (writeBuffer_start + writeBuffer_len) % FAT_COOP_BUFFER_SIZE;
407  uint16_t free = 0;
408 
409  // Test if writeBuffer is full
410  if (pos == writeBuffer_start - 1) {
411  return 1;
412  }
413 
414  // Calculate free space in Buffer
415  if (pos < writeBuffer_start) {
416  free = writeBuffer_start - pos;
417  } else {
418  free = (FAT_COOP_BUFFER_SIZE - pos) + writeBuffer_start;
419  }
420 
421  if (length > free) {
422  return 2;
423  }
424 
425  if (pos + length > FAT_COOP_BUFFER_SIZE) {
426  memcpy(&(writeBuffer[pos]), source, FAT_COOP_BUFFER_SIZE - pos);
427  memcpy(&(writeBuffer[0]), source, length - (FAT_COOP_BUFFER_SIZE - pos));
428  } else {
429  memcpy(&(writeBuffer[pos]), source, length);
430  }
431 
432  writeBuffer_len += length;
433 
434  return 0;
435 }
436 /*----------------------------------------------------------------------------*/
437 void
438 pop_from_buffer(uint16_t length)
439 {
440  if (length > writeBuffer_len) {
441  return;
442  }
443 
444  writeBuffer_start = (writeBuffer_start + length) % FAT_COOP_BUFFER_SIZE;
445  writeBuffer_len -= length;
446 
447  if (writeBuffer_len == 0) {
448  // If the buffer is empty, we can set the start pointer to the beginning
449  writeBuffer_start = 0;
450  }
451 }
452 /*----------------------------------------------------------------------------*/
453 uint8_t
454 get_item_from_buffer(uint8_t *start, uint16_t index)
455 {
456  // Calculate the start_index from the start-Buffer Offset from the writeBuffer
457  uint16_t start_index = (uint16_t) (start - writeBuffer);
458  return writeBuffer[(start_index + index) % FAT_COOP_BUFFER_SIZE];
459 }
460 /*----------------------------------------------------------------------------*/
461 int8_t
462 ccfs_open(const char *name, int flags, uint8_t *token)
463 {
464  int fd = -1;
465  uint8_t i = 0;
466  QueueEntry entry;
467 
468  for (i = 0; i < FAT_FD_POOL_SIZE; i++) {
469  if (fat_fd_pool[i].file == 0) {
470  fd = i;
471  break;
472  }
473  }
474 
475  if (fd == -1) {
476  return 2;
477  }
478 
479  if (queue_len == FAT_COOP_QUEUE_SIZE) {
480  return 1;
481  }
482 
483  process_start(&fsp, NULL);
484  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
485  return 3;
486  }
487 
488  entry.token = next_token++;
489  if (token != NULL) {
490  *token = entry.token;
491  }
492 
493  entry.op = COOP_CFS_OPEN;
494  entry.source_process = PROCESS_CURRENT();
495  entry.parameters.open.name = name;
496  entry.parameters.open.flags = flags;
497  entry.ret_value = fd;
498  entry.state = STATUS_QUEUED;
499 
500  fat_fd_pool[fd].file = &(fat_file_pool[fd]);
501 
502  queue_add_entry(&entry);
503 
504  return 0;
505 }
506 /*----------------------------------------------------------------------------*/
507 int8_t
508 ccfs_close(int fd, uint8_t *token)
509 {
510  QueueEntry entry;
511 
512  if (queue_len == FAT_COOP_QUEUE_SIZE) {
513  return 1;
514  }
515 
516  process_start(&fsp, NULL);
517  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
518  return 3;
519  }
520 
521  entry.token = next_token++;
522  if (token != NULL) {
523  *token = entry.token;
524  }
525 
526  entry.op = COOP_CFS_CLOSE;
527  entry.source_process = PROCESS_CURRENT();
528  entry.parameters.generic.fd = fd;
529  entry.state = STATUS_QUEUED;
530 
531  queue_add_entry(&entry);
532 
533  return 0;
534 }
535 /*----------------------------------------------------------------------------*/
536 int8_t
537 ccfs_read(int fd, uint8_t *buf, uint16_t length, uint8_t *token)
538 {
539  QueueEntry entry;
540 
541  if (queue_len == FAT_COOP_QUEUE_SIZE) {
542  return 1;
543  }
544 
545  process_start(&fsp, NULL);
546  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
547  return 3;
548  }
549 
550  entry.token = next_token++;
551  if (token != NULL) {
552  *token = entry.token;
553  }
554 
555  entry.op = COOP_CFS_READ;
556  entry.source_process = PROCESS_CURRENT();
557  entry.parameters.generic.fd = fd;
558  entry.parameters.generic.buffer = buf;
559  entry.parameters.generic.length = length;
560  entry.state = STATUS_QUEUED;
561 
562  queue_add_entry(&entry);
563 
564  return 0;
565 }
566 /*----------------------------------------------------------------------------*/
567 int8_t
568 ccfs_write(int fd, uint8_t *buf, uint16_t length, uint8_t *token)
569 {
570  QueueEntry entry;
571 
572  memset(&entry, 0, sizeof(QueueEntry));
573 
574  if (queue_len == FAT_COOP_QUEUE_SIZE) {
575  PRINTF("ccfs_write: Buffer full\n");
576  return 1;
577  }
578 
579  process_start(&fsp, NULL);
580  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
581  PRINTF("ccfs_write: Event Queue full\n");
582  return 3;
583  }
584 
585  entry.token = next_token++;
586  if (token != NULL) {
587  *token = entry.token;
588  }
589 
590  entry.op = COOP_CFS_WRITE;
591  entry.source_process = PROCESS_CURRENT();
592  entry.parameters.generic.fd = fd;
593 
594  if (!fat_buffer_available(length)) {
595  PRINTF("ccfs_write: Buffer full\n");
596  return 2;
597  }
598 
599  entry.parameters.generic.buffer = &(writeBuffer[(writeBuffer_start + writeBuffer_len) % FAT_COOP_BUFFER_SIZE]);
600 
601  /** FIXME: We push information in a ring buffer, which actually does not work as a ring, because the eventual cfs_write call does not know anything about rings */
602  if (push_on_buffer(buf, length) != 0) {
603  return 4;
604  }
605  entry.parameters.generic.length = length;
606  entry.state = STATUS_QUEUED;
607 
608  queue_add_entry(&entry);
609 
610  return 0;
611 }
612 /*----------------------------------------------------------------------------*/
613 int8_t
614 ccfs_seek(int fd, cfs_offset_t offset, int whence, uint8_t *token)
615 {
616  QueueEntry entry;
617 
618  if (queue_len == FAT_COOP_QUEUE_SIZE) {
619  return 1;
620  }
621 
622  process_start(&fsp, NULL);
623  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
624  return 3;
625  }
626 
627  entry.token = next_token++;
628  if (token != NULL) {
629  *token = entry.token;
630  }
631 
632  entry.op = COOP_CFS_SEEK;
633  entry.source_process = PROCESS_CURRENT();
634  entry.parameters.seek.fd = fd;
635  entry.parameters.seek.offset = offset;
636  entry.parameters.seek.whence = whence;
637  entry.state = STATUS_QUEUED;
638 
639  queue_add_entry(&entry);
640 
641  return 0;
642 }
643 /*----------------------------------------------------------------------------*/
644 int8_t
645 ccfs_remove(const char *name, uint8_t *token)
646 {
647  QueueEntry entry;
648 
649  if (queue_len == FAT_COOP_QUEUE_SIZE) {
650  return 1;
651  }
652 
653  process_start(&fsp, NULL);
654  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
655  return 3;
656  }
657 
658  entry.token = next_token++;
659  if (token != NULL) {
660  *token = entry.token;
661  }
662 
663  entry.op = COOP_CFS_REMOVE;
664  entry.source_process = PROCESS_CURRENT();
665  entry.parameters.open.name = name;
666  entry.state = STATUS_QUEUED;
667 
668  queue_add_entry(&entry);
669 
670  return 0;
671 }
672 /*----------------------------------------------------------------------------*/
673 int8_t
674 ccfs_opendir(struct cfs_dir *dirp, const char *name, uint8_t *token)
675 {
676  QueueEntry entry;
677 
678  if (queue_len == FAT_COOP_QUEUE_SIZE) {
679  return 1;
680  }
681 
682  process_start(&fsp, NULL);
683  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
684  return 3;
685  }
686 
687  entry.token = next_token++;
688  if (token != NULL) {
689  *token = entry.token;
690  }
691 
692  entry.op = COOP_CFS_OPENDIR;
693  entry.source_process = PROCESS_CURRENT();
694  entry.parameters.dir.dirp = dirp;
695  entry.parameters.dir.u.name = name;
696  entry.state = STATUS_QUEUED;
697 
698  queue_add_entry(&entry);
699 
700  return 0;
701 }
702 /*----------------------------------------------------------------------------*/
703 int8_t
704 ccfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *dirent, uint8_t *token)
705 {
706  QueueEntry entry;
707 
708  if (queue_len == FAT_COOP_QUEUE_SIZE) {
709  return 1;
710  }
711 
712  process_start(&fsp, NULL);
713  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
714  return 3;
715  }
716 
717  entry.token = next_token++;
718  if (token != NULL) {
719  *token = entry.token;
720  }
721 
722  entry.op = COOP_CFS_READDIR;
723  entry.source_process = PROCESS_CURRENT();
724  entry.parameters.dir.dirp = dirp;
725  entry.parameters.dir.u.dirent = dirent;
726  entry.state = STATUS_QUEUED;
727 
728  queue_add_entry(&entry);
729 
730  return 0;
731 }
732 /*----------------------------------------------------------------------------*/
733 int8_t
734 ccfs_closedir(struct cfs_dir *dirp, uint8_t *token)
735 {
736  QueueEntry entry;
737 
738  if (queue_len == FAT_COOP_QUEUE_SIZE) {
739  return 1;
740  }
741 
742  process_start(&fsp, NULL);
743  if (process_post(&fsp, PROCESS_EVENT_CONTINUE, NULL) == PROCESS_ERR_FULL) {
744  return 3;
745  }
746 
747  entry.token = next_token++;
748  if (token != NULL) {
749  *token = entry.token;
750  }
751 
752  entry.op = COOP_CFS_CLOSEDIR;
753  entry.source_process = PROCESS_CURRENT();
754  entry.parameters.dir.dirp = dirp;
755  entry.state = STATUS_QUEUED;
756 
757  queue_add_entry(&entry);
758 
759  return 0;
760 }
761 /*----------------------------------------------------------------------------*/
762 uint8_t
763 fat_op_status(uint8_t token)
764 {
765  uint16_t i = 0;
766  QueueEntry *entry;
767 
768  for (i = 0; i < queue_len; i++) {
769  entry = &(queue[(queue_start + i) % FAT_COOP_QUEUE_SIZE]);
770  if (entry->token == token) {
771  return entry->state;
772  }
773  }
774 
775  return 0;
776 }
777 /*----------------------------------------------------------------------------*/
778 uint16_t
779 _get_time_of_operation(Operation op, uint16_t length)
780 {
781  uint8_t op_multiplikator = (length / 512) + ((length % 512 != 0) ? 1 : 0);
782 
783  switch (op) {
784  case COOP_CFS_OPENDIR:
785  case COOP_CFS_READDIR:
786  case COOP_CFS_READ:
787  case COOP_CFS_OPEN:
788  return (FAT_COOP_TIME_READ_BLOCK_MS) * op_multiplikator;
789  case COOP_CFS_CLOSEDIR:
790  case COOP_CFS_SEEK:
791  case COOP_CFS_CLOSE:
792  return 0;
793  case COOP_CFS_REMOVE:
794  case COOP_CFS_WRITE:
795  return (FAT_COOP_TIME_READ_BLOCK_MS + FAT_COOP_TIME_WRITE_BLOCK_MS) * op_multiplikator;
796  }
797 
798  return 0;
799 }
800 /*----------------------------------------------------------------------------*/
801 uint16_t
802 fat_estimate_by_token(uint8_t token)
803 {
804  uint16_t estimated_time = 0;
805  uint16_t i;
806  int length;
807 
808  QueueEntry *entry;
809  for (i = 0; i < queue_len; i++) {
810  entry = &(queue[(queue_start + i) % FAT_COOP_QUEUE_SIZE]);
811 
812  length = 0;
813  if (entry->op == COOP_CFS_CLOSE || entry->op == COOP_CFS_READ || entry->op == COOP_CFS_WRITE) {
814  length = entry->parameters.generic.length;
815  }
816 
817  estimated_time += _get_time_of_operation(entry->op, length);
818  if (entry->token == token) {
819  break;
820  }
821  }
822 
823  return estimated_time;
824 }
825 /*----------------------------------------------------------------------------*/
826 uint16_t
827 fat_estimate_by_parameter(Operation type, uint16_t length)
828 {
829  uint16_t estimated_time = _get_time_of_operation(type, length);
830  uint16_t i;
831  int sublength = 0;
832 
833  QueueEntry *entry;
834  for (i = 0; i < queue_len; i++) {
835  entry = &(queue[(queue_start + i) % FAT_COOP_QUEUE_SIZE]);
836 
837  sublength = 0;
838  if (entry->op == COOP_CFS_CLOSE || entry->op == COOP_CFS_READ || entry->op == COOP_CFS_WRITE) {
839  sublength = entry->parameters.generic.length;
840  }
841 
842  estimated_time += _get_time_of_operation(entry->op, sublength);
843  }
844  return estimated_time;
845 }
846 /*----------------------------------------------------------------------------*/
847 uint8_t
848 fat_buffer_available(uint16_t length)
849 {
850  uint16_t pos = (writeBuffer_start + writeBuffer_len) % FAT_COOP_BUFFER_SIZE;
851  uint16_t free = 0;
852 
853  if (pos == writeBuffer_start && writeBuffer_len != 0) {
854  return 0;
855  }
856 
857  if (pos < writeBuffer_start) {
858  free = writeBuffer_start - pos;
859  } else {
860  free = (FAT_COOP_BUFFER_SIZE - pos) + writeBuffer_start;
861  }
862 
863  if (length > free) {
864  return 0;
865  }
866 
867  return 1;
868 }
869 /*----------------------------------------------------------------------------*/