MHEG5  18.9.0
MHEG5 Documentation
mh5fsnvm.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*---includes for this file--------------------------------------------------*/
26 #include <stdio.h>
27 #include <assert.h>
28 #include <string.h>
29 
30 #include <glue_memory.h>
31 #include <glue_queue.h>
32 
33 #include "mh5date.h"
34 
35 #include "mh5fsnvm.h"
36 
37 #include "mherrors.h"
38 #include "techtype.h"
39 #include "dvb_service.h"
40 
41 #include "stb_nvm.h"
42 
43 #ifdef INCLUDE_FREESAT
44 
45 /*---constant definitions for this file--------------------------------------*/
46 #ifndef NVM_STORAGE_MAX
47 #define NVM_STORAGE_MAX (256 * 1024)
48 #endif
49 #define HEADER_SIZE 7
50 
51 #ifndef NVM_STORAGE_DIRECTORY
52 #define NVM_STORAGE_DIRECTORY "nvm/"
53 #endif
54 #define NVM_STORAGE_DIRECTORY_LEN strlen(NVM_STORAGE_DIRECTORY)
55 
56 #define MAX_PATH_LEN 64
57 
58 
59 /*---local typedef structs for this file-------------------------------------*/
60 
61 typedef struct s_nvm_file
62 {
63  MHEG5String fn;
64  void *data;
65  MHEG5Bool stored;
66  MHEG5Int data_len;
67  MHEG5Int expires;
68  MHEG5Int priority;
69  MHEG5Int last_accessed;
70  MHEG5Int score;
71  struct s_nvm_allocation *allocation;
72  struct s_nvm_file *next;
73  struct s_nvm_file *previous;
74 } S_NVM_FILE;
75 
76 typedef struct s_nvm_allocation
77 {
78  U16BIT id;
79  MHEG5Int size;
80  MHEG5Int used;
81  S_NVM_FILE *first_file;
82  struct s_nvm_allocation *next;
83  struct s_nvm_allocation *previous;
84 } S_NVM_ALLOCATION;
85 
86 /*---local (static) variable declarations for this file----------------------*/
87 static MHEG5Bool init = MHEG5FALSE;
88 static MHEG5Bool store_open = MHEG5FALSE;
89 static S_NVM_ALLOCATION *allocation_list = NULL;
90 static S_NVM_ALLOCATION scratchpad;
91 static MHEG5Int total_stored = 0;
92 
93 /*---local function prototypes for this file---------------------------------*/
94 static MHEG5String* CreateStorageFilename(MHEG5String fn, U16BIT allocation_id);
95 static MHEG5Bool WriteToFile(S_NVM_FILE *file);
96 static MHEG5Bool CheckFreeSpace(S_NVM_FILE *file);
97 static MHEG5Bool CheckAllocationSize(S_NVM_FILE *file);
98 static U16BIT ConvertPathToId(MHEG5String fn);
99 static void InitStore(void);
100 static void OpenNvmStore(void);
101 static S_NVM_FILE* FindFile(MHEG5String filename, U16BIT allocation_id);
102 static MHEG5Bool RemoveFileFromCache(S_NVM_FILE *file_entry);
103 static MHEG5Bool DeleteFile(S_NVM_FILE *file_entry);
104 static MHEG5Bool MoveFileToScratch(S_NVM_FILE *file);
105 static S_NVM_FILE* CreateFile(void *data, MHEG5Int len, MHEG5String *filename,
106  U16BIT allocation_id, U32BIT priority);
107 static MHEG5Bool ReadFromFile(void **data, MHEG5Int *len, S_NVM_FILE *file);
108 static void CalculateFileScore(S_NVM_FILE *file);
109 static S_NVM_ALLOCATION* GetAllocationFromId(U16BIT allocation_id);
110 static void CheckUpdatedAllocation(S_NVM_ALLOCATION *allocation);
111 static void CacheFile(char *file_name);
112 static void UpdateHeader( S_NVM_FILE *file);
113 static void ParseFileHeader(U8BIT *header_data, S_NVM_FILE *file);
114 static U32BIT FilenameToId(MHEG5String string);
115 static void ClearFileDataCache(void);
116 /*---global function definitions---------------------------------------------*/
117 
129  MHEG5Int *expires, MHEG5Int *priority)
130 {
131  MHEG5Bool success = MHEG5FALSE;
132  MHEG5String *new_filename = NULL;
133  U16BIT allocation_id;
134  S_NVM_FILE *file;
135  //int i;
136 
137  if (!init)
138  {
139  return MHEG5FALSE;
140  }
141 
142  OpenNvmStore();
143  if (fn.len)
144  {
145  allocation_id = ConvertPathToId(fn);
146 
147  new_filename = CreateStorageFilename(fn, allocation_id);
148  if (new_filename)
149  {
150  file = FindFile(*new_filename, allocation_id);
151  if (file)
152  {
153  *priority = file->priority;
154  *expires = file->expires;
155  success = ReadFromFile(data, len, file);
156  }
157  }
158  }
159 
160  return success;
161 }
162 
173 MHEG5Bool MHEG5FSnvmWrite(MHEG5String fn, void *data, MHEG5Int len,
174  MHEG5Int expires, MHEG5Int priority)
175 {
176  MHEG5Bool success = MHEG5FALSE;
177  MHEG5String *new_filename = NULL;
178  U16BIT allocation_id;
179  MHEG5Int file_priority = priority;
180  S32BIT today, throwaway;
181  S_NVM_FILE *file;
182  //int i;
183 
184  if (!init)
185  {
186  return MHEG5FALSE;
187  }
188 
189  OpenNvmStore();
190 
191  MHEG5getDate(&today, &throwaway);
192  allocation_id = ConvertPathToId(fn);
193  if (allocation_id == 0xffff)
194  {
195  /*if the allocation_id was invalid or the current service isn't assigned to it
196  FAIL*/
197  return MHEG5FALSE;
198  }
199  new_filename = CreateStorageFilename(fn, allocation_id);
200  if (new_filename)
201  {
202  if (expires)
203  {
204  file = CreateFile(data, len, new_filename, allocation_id, file_priority);
205  if (file)
206  {
207  file->expires = expires;
208  file->last_accessed = today;
209  if (CheckAllocationSize(file))
210  {
211  if (CheckFreeSpace(file))
212  {
213  success = WriteToFile(file);
214  }
215  }
216  if (!success)
217  {
218  RemoveFileFromCache(file);
219  }
220  }
221  }
222  else
223  {
224  file = FindFile(*new_filename, allocation_id);
225  if (file)
226  {
227  success = DeleteFile(file);
228  }
229  }
230  }
231 
232  ClearFileDataCache();
233  return success;
234 }
235 
242 static MHEG5Bool WriteToFile(S_NVM_FILE *file)
243 {
244  void *nvm_file;
245  U32BIT bytes_written = 0;
246  MHEG5Bool success;
247 
248  assert(file);
249 
250  /* create header from metadata */
251  UpdateHeader(file);
252 
253 
254  nvm_file = STB_NVMOpenFile(file->fn.data, FILE_MODE_OVERWRITE );
255  if (nvm_file)
256  {
257  bytes_written = STB_NVMWriteFile(nvm_file, file->data, HEADER_SIZE + file->data_len);
258 
259  STB_NVMCloseFile(nvm_file);
260  }
261 
262  if (bytes_written == HEADER_SIZE + file->data_len)
263  {
264  success = MHEG5TRUE;
265  }
266  else
267  {
268  success = MHEG5FALSE;
269  }
270  return success;
271 }
272 
279 static U16BIT ConvertPathToId(MHEG5String fn)
280 {
281  U16BIT current_identifier;
282  int i, shift;
283  BOOLEAN ok;
284  if (!MHEG5strncmp(fn.data, "svc/", 4))
285  {
286  if (DVB_MhegGetCurrentFSI(&current_identifier) == MHERR_OK)
287  {
288  return current_identifier;
289  }
290  }
291  else
292  {
293  current_identifier = 0;
294  shift = 12;
295  for (i = 0; i < 4; i++)
296  {
297  if (fn.data[i] >= 'a' && fn.data[i] <= 'f')
298  {
299  current_identifier += (fn.data[i] + 0xa - 'a') << shift;
300  }
301  else if (fn.data[i] >= '0' && fn.data[i] <= '9')
302  {
303  current_identifier += (fn.data[i] - '0') << shift;
304  }
305  else
306  {
307  return 0xFFFF;
308  }
309  shift -= 4;
310  }
311 
312  if (current_identifier > 0x8000)
313  {
314  return 0xFFFF;
315  }
316  else
317  {
318  DVB_MhegCurrentServiceIsInGroup(current_identifier, &ok);
319 
320  if (ok)
321  {
322  current_identifier |= 0x8000; /*using top bit to indicate a group*/
323  }
324  else
325  {
326  current_identifier = 0xffff;
327  }
328  }
329  }
330  return current_identifier;
331 }
332 
338 static MHEG5Bool CheckFreeSpace(S_NVM_FILE *file)
339 {
340  S_NVM_FILE *file_cursor;
341  S_NVM_FILE *lowest_scored_file = NULL;
342 
343  assert(file);
344  while (total_stored > NVM_STORAGE_MAX && scratchpad.first_file)
345  {
346  file_cursor = scratchpad.first_file;
347  while (file_cursor)
348  {
349  if (file_cursor == file)
350  {
351  file_cursor = file_cursor->next;
352  continue;
353  }
354 
355  CalculateFileScore(file_cursor);
356  if (!lowest_scored_file)
357  {
358  lowest_scored_file = file_cursor;
359  }
360  else if (lowest_scored_file->score > file_cursor->score)
361  {
362  lowest_scored_file = file_cursor;
363  }
364 
365  file_cursor = file_cursor->next;
366  }
367 
368  if (lowest_scored_file)
369  {
370  DeleteFile(lowest_scored_file);
371  }
372  }
373  if (total_stored <= NVM_STORAGE_MAX)
374  {
375  return MHEG5TRUE;
376  }
377  else
378  {
379  return MHEG5FALSE;
380  }
381 }
382 
388 static MHEG5Bool CheckAllocationSize(S_NVM_FILE *file)
389 {
390  S_NVM_ALLOCATION *allocation;
391  S_NVM_FILE *file_cursor;
392  S_NVM_FILE *next_file;
393 
394  assert(file);
395 
396  /*check if the file has an allocation region set*/
397  allocation = file->allocation;
398  if (allocation)
399  {
400  CalculateFileScore(file);
401  if (file->allocation == &scratchpad)
402  {
403  return MoveFileToScratch(file);
404  }
405 
406  /*if the file will fit into the allocation without moving anything*/
407  if (allocation->size >= allocation->used)
408  {
409  return MHEG5TRUE;
410  }
411  /*if it is within the total allocation size*/
412  else if (file->data_len <= allocation->size)
413  {
414  /*remove expired files*/
415  file_cursor = allocation->first_file;
416  while (file_cursor && allocation->size < allocation->used)
417  {
418  CalculateFileScore(file_cursor);
419  next_file = file_cursor->next;
420  if (file_cursor != file && !file_cursor->score)
421  {
422  DeleteFile(file_cursor);
423  }
424  file_cursor = next_file;
425  }
426  /*if it still doesn't fit try moving files to scratch*/
427  file_cursor = allocation->first_file;
428  while (file_cursor && allocation->size < allocation->used)
429  {
430  next_file = file_cursor->next;
431  if (file_cursor != file && file_cursor->score < file->score)
432  {
433  MoveFileToScratch(file_cursor);
434  }
435  file_cursor = next_file;
436  }
437  /*if it still doesn't fit*/
438  if (allocation->size < allocation->used)
439  {
440  file->priority = 0;
441  CalculateFileScore(file);
442  return MoveFileToScratch(file);
443  }
444  }
445  /*if it is too big for the allocation it must not save at all*/
446  else
447  {
448  RemoveFileFromCache(file);
449  return MHEG5FALSE;
450  }
451  }
452 
453 
454  return MHEG5TRUE;
455 }
456 
462 static MHEG5String* CreateStorageFilename(MHEG5String fn, U16BIT allocation_id)
463 {
464  MHEG5String *new_fn = NULL;
465  int i, shift;
466  int name_start;
467 
468  for (name_start = 0; name_start < fn.len; name_start++)
469  {
470  if (fn.data[name_start] == '/')
471  {
472  name_start++;
473  break;
474  }
475  }
476  /*check that the filename is within the 1-8 characters length limit*/
477  if (fn.len > name_start && fn.len <= name_start + 7)
478  {
479  new_fn = MHEG5getMem(sizeof(MHEG5String));
480  }
481  if (new_fn)
482  {
483  new_fn->len = fn.len + 5 - name_start;
484  new_fn->len += NVM_STORAGE_DIRECTORY_LEN;
485  new_fn->data = MHEG5getMem(new_fn->len + NVM_STORAGE_DIRECTORY_LEN + 1);
486 
487  if (!new_fn->data)
488  {
489  MHEG5freeMem(new_fn);
490  new_fn = NULL;
491  }
492  else
493  {
494  memcpy(new_fn->data, NVM_STORAGE_DIRECTORY, NVM_STORAGE_DIRECTORY_LEN);
495  shift = 12;
496  for (i = NVM_STORAGE_DIRECTORY_LEN; i != NVM_STORAGE_DIRECTORY_LEN + 4; i++)
497  {
498  new_fn->data[i] = (allocation_id >> shift) & 0xf;
499  if (new_fn->data[i] > 9)
500  {
501  new_fn->data[i] += 'a' - 0xa;
502  }
503  else
504  {
505  new_fn->data[i] += '0';
506  }
507  shift -= 4;
508  }
509  new_fn->data[i++] = '_';
510  memcpy( &new_fn->data[i], &fn.data[name_start], fn.len - name_start);
511  new_fn->data[new_fn->len] = '\0';
512  }
513  }
514 
515 
516  return new_fn;
517 }
518 
523 static void InitStore(void)
524 {
525  if (!init)
526  {
527  assert(!allocation_list);
528 
529  scratchpad.id = 0xffff;
530  scratchpad.size = NVM_STORAGE_MAX;
531  scratchpad.used = 0;
532  scratchpad.first_file = NULL;
533  scratchpad.next = NULL;
534  scratchpad.previous = NULL;
535  total_stored = 0;
536  init = MHEG5TRUE;
537  }
538 }
539 
544 static void OpenNvmStore(void)
545 {
546  char *file_name;
547  void *directory_handle;
548  E_STB_DIR_ENTRY_TYPE file_type;
549  if (!init)
550  {
551  return;
552  }
553 
554  if (!store_open)
555  {
556  directory_handle = STB_NVMOpenDirectory((U8BIT *)NVM_STORAGE_DIRECTORY);
557  if (directory_handle)
558  {
559  file_name = MHEG5getMem(MAX_PATH_LEN);
560  memcpy(file_name, NVM_STORAGE_DIRECTORY, NVM_STORAGE_DIRECTORY_LEN);
561  while (STB_NVMReadDirectory(directory_handle,
562  (U8BIT *)file_name + NVM_STORAGE_DIRECTORY_LEN, MAX_PATH_LEN - NVM_STORAGE_DIRECTORY_LEN, &file_type))
563  {
564  if (file_type == DIR_ENTRY_FILE)
565  {
566  CacheFile(file_name);
567  }
568  memcpy(file_name, NVM_STORAGE_DIRECTORY, NVM_STORAGE_DIRECTORY_LEN);
569  }
570  MHEG5freeMem(file_name);
571  }
572  store_open = MHEG5TRUE;
573  }
574 }
575 
576 void MHEG5FSnvmStoreOpen(void)
577 {
578  InitStore();
579 }
580 
581 void MHEG5FSnvmStoreClose(void)
582 {
583  S_NVM_ALLOCATION *allocation;
584  S_NVM_ALLOCATION *next_allocation;
585  S_NVM_FILE *file;
586  S_NVM_FILE *next_file;
587 
588 
589  init = MHEG5FALSE;
590  store_open = MHEG5FALSE;
591  allocation = allocation_list;
592  while (allocation)
593  {
594  next_allocation = allocation->next;
595  file = allocation->first_file;
596  while (file)
597  {
598  next_file = file->next;
599 
600  RemoveFileFromCache(file);
601 
602  file = next_file;
603  }
604  MHEG5freeMem(allocation);
605  allocation = next_allocation;
606  }
607  file = scratchpad.first_file;
608  while (file)
609  {
610  next_file = file->next;
611 
612  RemoveFileFromCache(file);
613 
614  file = next_file;
615  }
616  scratchpad.first_file = NULL;
617  allocation_list = NULL;
618  total_stored = 0;
619 }
620 
626 static S_NVM_FILE* FindFile(MHEG5String filename, U16BIT allocation_id)
627 {
628  S_NVM_ALLOCATION *allocation;
629  S_NVM_FILE *file_cursor = NULL;
630 
631 
632  /*try to find the storage allocation*/
633  allocation = GetAllocationFromId(allocation_id);
634 
635  /*if it was found search for the file in it*/
636  if (allocation)
637  {
638  file_cursor = allocation->first_file;
639  while (file_cursor && !MHEG5stringEqual(&file_cursor->fn, &filename))
640  {
641  file_cursor = file_cursor->next;
642  }
643  }
644  /*if the file hasn't been found yet, it could be in scratch*/
645  if (!file_cursor)
646  {
647  allocation = &scratchpad;
648  file_cursor = scratchpad.first_file;
649  while (file_cursor && !MHEG5stringEqual(&file_cursor->fn, &filename))
650  {
651  file_cursor = file_cursor->next;
652  }
653  }
654  return file_cursor;
655 }
656 
664 static MHEG5Bool RemoveFileFromCache(S_NVM_FILE *file_entry)
665 {
666  file_entry->allocation->used -= file_entry->data_len;
667  total_stored -= file_entry->data_len;
668  if (file_entry->data)
669  {
670  MHEG5freeMem(file_entry->data);
671  }
672  MHEG5freeMem(file_entry->fn.data);
673 
674  if (!file_entry->previous)
675  {
676  file_entry->allocation->first_file = file_entry->next;
677  }
678  else
679  {
680  file_entry->previous->next = file_entry->next;
681  }
682  if (file_entry->next)
683  {
684  file_entry->next->previous = file_entry->previous;
685  }
686  MHEG5freeMem(file_entry);
687  return MHEG5TRUE;
688 }
689 
696 static MHEG5Bool DeleteFile(S_NVM_FILE *file_entry)
697 {
698  MHEG5Bool success = MHEG5FALSE;
699 
700  assert(file_entry);
701 
702  if (STB_NVMDeleteFile(file_entry->fn.data))
703  {
704  success = RemoveFileFromCache(file_entry);
705  }
706 
707  return success;
708 }
709 
719 static MHEG5Bool MoveFileToScratch(S_NVM_FILE *file)
720 {
721  S_NVM_ALLOCATION *allocation;
722  S_NVM_FILE *file_cursor;
723  S_NVM_FILE *lowest_file;
724  MHEG5Int lowest_score = 0x7fffffff;
725  void *temp_file = NULL;
726  U32BIT bytes_read = 0;
727 
728  assert(file);
729 
730  allocation = file->allocation; /*shorthand*/
731  file->priority = 0;
732 
733  /*if the file isn't allocated to the scratchpad yet, move it in*/
734  /*(it is possible that it is already on scratchpad, but needs reallocating)*/
735  if (allocation != &scratchpad)
736  {
737  /*if the file being moved is already stored in NVM
738  it needs to be updated*/
739  if (file->stored)
740  {
741  /*if only the metadata is cached, re-read the file data*/
742  if (!file->data)
743  {
744  file->data = MHEG5getMem(file->data_len + HEADER_SIZE);
745  if (file->data)
746  {
747  temp_file = STB_NVMOpenFile(file->fn.data, FILE_MODE_READ );
748  }
749  if (temp_file)
750  {
751  bytes_read = STB_NVMReadFile( temp_file, file->data, file->data_len + HEADER_SIZE);
752  STB_NVMCloseFile(temp_file);
753  }
754  if (file->data && bytes_read != file->data_len + HEADER_SIZE)
755  {
756  MHEG5freeMem(file->data);
757  file->data = NULL;
758  }
759  }
760  /*if the file data is cached, rewrite the file with the new metadata*/
761  if (file->data)
762  {
763  WriteToFile(file);
764  }
765  }
766 
767 
768  if (file->previous)
769  {
770  file->previous->next = file->next;
771  }
772  else
773  {
774  allocation->first_file = file->next;
775  }
776  if (file->next)
777  {
778  file->next->previous = file->previous;
779  }
780  allocation->used -= file->data_len;
781  total_stored -= file->data_len;
782  file->allocation = &scratchpad;
783  file->previous = NULL;
784  file->next = scratchpad.first_file;
785  if (scratchpad.first_file)
786  {
787  scratchpad.first_file->previous = file;
788  }
789  scratchpad.first_file = file;
790  scratchpad.used += file->data_len;
791  total_stored += file->data_len;
792  }
793 
794  /*if there is a scratchpad overflow*/
795  while (scratchpad.size < scratchpad.used)
796  {
797  /*find the lowest scored file*/
798  file_cursor = scratchpad.first_file;
799  lowest_score = -1;
800  lowest_file = NULL;
801  while (file_cursor)
802  {
803  if (file_cursor->stored && file_cursor->score < lowest_score)
804  {
805  lowest_score = file_cursor->score;
806  lowest_file = file_cursor;
807  }
808  file_cursor = file_cursor->next;
809  }
810  if (lowest_file)
811  {
812  DeleteFile(lowest_file);
813  }
814  else
815  {
816  RemoveFileFromCache(file);
817  return MHEG5FALSE;
818  }
819  }
820 
821  return MHEG5TRUE;
822 }
823 
836 static S_NVM_FILE* CreateFile(void *data, MHEG5Int len, MHEG5String *filename,
837  U16BIT allocation_id, U32BIT priority)
838 {
839  S_NVM_FILE *file_entry = NULL;
840  S_NVM_ALLOCATION *allocation;
841  S_NVM_ALLOCATION *old_allocation;
842 
843  allocation = GetAllocationFromId(allocation_id);
844  if (!allocation || allocation->size < len + HEADER_SIZE)
845  {
846  return NULL;
847  }
848 
849  file_entry = FindFile(*filename, allocation_id);
850  if (!file_entry)
851  { /* new file */
852  if (!priority)
853  {
854  allocation = &scratchpad;
855  }
856 
857  if (allocation)
858  {
859  file_entry = MHEG5getMem(sizeof(S_NVM_FILE));
860  if (file_entry)
861  {
862  file_entry->data = MHEG5getMem(len + HEADER_SIZE);
863  if (file_entry->data)
864  {
865  memcpy((U8BIT *)file_entry->data + HEADER_SIZE, data, len);
866  }
867  file_entry->fn.data = filename->data;
868  file_entry->fn.len = filename->len;
869  file_entry->allocation = allocation;
870  file_entry->data_len = len;
871  file_entry->priority = priority;
872  file_entry->previous = NULL;
873  file_entry->stored = MHEG5FALSE;
874  if (allocation->first_file)
875  {
876  allocation->first_file->previous = file_entry;
877  }
878  file_entry->next = allocation->first_file;
879 
880  allocation->first_file = file_entry;
881  allocation->used += len;
882  total_stored += len;
883  }
884  }
885  }
886  else
887  {
888  if (!file_entry->priority)
889  {
890  old_allocation = &scratchpad;
891  }
892  else
893  {
894  old_allocation = allocation;
895  }
896  old_allocation->used -= file_entry->data_len;
897  total_stored -= file_entry->data_len;
898  file_entry->data_len = len;
899  file_entry->priority = priority;
900  file_entry->data = MHEG5getMem(len + HEADER_SIZE);
901 
902  if (!priority)
903  {
904  allocation = &scratchpad;
905  }
906  /*move the file to a different allocation*/
907  if (old_allocation != allocation)
908  {
909  if (file_entry->next)
910  {
911  file_entry->next->previous = file_entry->previous;
912  }
913 
914  if (file_entry->previous)
915  {
916  file_entry->previous->next = file_entry->next;
917  }
918  if (old_allocation->first_file == file_entry)
919  {
920  old_allocation->first_file = file_entry->next;
921  }
922 
923  file_entry->previous = NULL;
924  file_entry->next = allocation->first_file;
925  allocation->first_file = file_entry;
926  file_entry->allocation = allocation;
927  }
928  allocation->used += len;
929  total_stored += len;
930 
931  if (file_entry->data)
932  {
933  memcpy((U8BIT *)file_entry->data + HEADER_SIZE, data, len);
934  }
935  }
936  return file_entry;
937 }
938 
943 static MHEG5Bool ReadFromFile(void **data, MHEG5Int *len, S_NVM_FILE *file)
944 {
945  void *nvm_file;
946  MHEG5Bool success = MHEG5FALSE;
947  assert(file);
948 
949  if (file->data)
950  {
951  *len = file->data_len;
952  *data = (U8BIT *)file->data + HEADER_SIZE;
953  success = MHEG5TRUE;
954  }
955  else
956  {
957  file->data = MHEG5getMem(file->data_len + HEADER_SIZE);
958  nvm_file = STB_NVMOpenFile(file->fn.data, FILE_MODE_READ );
959  if (nvm_file)
960  {
961  STB_NVMReadFile(nvm_file, file->data, file->data_len + HEADER_SIZE);
962  *len = file->data_len;
963  *data = (U8BIT *)file->data + HEADER_SIZE;
964  success = MHEG5TRUE;
965  STB_NVMCloseFile(nvm_file);
966  }
967  }
968  return success;
969 }
970 
976 static void CalculateFileScore(S_NVM_FILE *file)
977 {
978  S32BIT today, second;
979 
980  MHEG5getDate(&today, &second);
981  if (file->expires <= today)
982  {
983  file->score = 0;
984  }
985  else
986  {
987  file->score = file->priority * 30;
988  file->score += file->last_accessed;
989  }
990 }
991 
996 static void NotifyUpdateServiceAllocation( U16BIT identifier, BOOLEAN groupNotService,
997  U8BIT blockSize, U8BIT blocks )
998 {
999  S_NVM_ALLOCATION *allocation;
1000  U16BIT allocation_id;
1001  MHEG5Int size;
1002  int i;
1003 
1004  if (!init)
1005  {
1006  return;
1007  }
1008 
1009  /*simple 2^blockSize*/
1010  size = 1;
1011  for (i = 0; i < blockSize; i++)
1012  {
1013  size *= 2;
1014  }
1015  size *= blocks;
1016 
1017  allocation_id = identifier;
1018  if (groupNotService)
1019  {
1020  allocation_id |= 0x8000;
1021  }
1022  allocation = GetAllocationFromId(allocation_id);
1023  if (allocation)
1024  {
1025  allocation->size = size;
1026  }
1027  else
1028  {
1029  if (size <= NVM_STORAGE_MAX)
1030  {
1031  allocation = MHEG5getMem(sizeof(S_NVM_ALLOCATION));
1032  }
1033 
1034  if (allocation)
1035  {
1036  allocation->size = size;
1037  allocation->used = 0;
1038  allocation->id = allocation_id;
1039  allocation->first_file = NULL;
1040  allocation->next = allocation_list;
1041  allocation->previous = NULL;
1042  allocation_list = allocation;
1043  }
1044  else
1045  {
1046  return;
1047  }
1048  }
1049 
1050  if (store_open)
1051  {
1052  CheckUpdatedAllocation(allocation);
1053  }
1054 }
1055 
1056 static void UpdateStorageAllocation( MHEG5FsStorageParams_t *params )
1057 {
1058  NotifyUpdateServiceAllocation( params->identifier, params->group,
1059  params->blockSize, params->blocks );
1060 }
1061 
1076 E_MhegErr MHEG5_NotifyStorageChanged( U16BIT identifier, BOOLEAN groupNotService,
1077  U8BIT blockSize, U8BIT blocks )
1078 {
1079  S_MhegMessage event_msg;
1080  event_msg.proc_msg_func = (F_MSG_PROCESS)UpdateStorageAllocation;
1081  event_msg.data_type = DT_VALUE;
1082  event_msg.data.fsStorage.blockSize = blockSize;
1083  event_msg.data.fsStorage.blocks = blocks;
1084  event_msg.data.fsStorage.group = groupNotService;
1085  event_msg.data.fsStorage.identifier = identifier;
1086  return VQ_PutMsg(&event_msg, PRTY_NORMAL);
1087 }
1088 
1095 static void CheckUpdatedAllocation(S_NVM_ALLOCATION *allocation)
1096 {
1097  S_NVM_FILE *file_cursor;
1098  S_NVM_FILE *lowest_file;
1099 
1100 
1101  file_cursor = allocation->first_file;
1102  while (file_cursor)
1103  {
1104  if (file_cursor->data_len > allocation->size)
1105  {
1106  S_NVM_FILE *temp_next = file_cursor->next;
1107  DeleteFile(file_cursor);
1108  file_cursor = temp_next;
1109  }
1110  else
1111  {
1112  file_cursor = file_cursor->next;
1113  }
1114  }
1115 
1116  /*while the allocation is now too small to hold the files stored*/
1117  while (allocation->used > allocation->size)
1118  {
1119  /*move the lowest scored file to scratch*/
1120  file_cursor = allocation->first_file;
1121  lowest_file = NULL;
1122  while (file_cursor)
1123  {
1124  if (!lowest_file || file_cursor->score < lowest_file->score)
1125  {
1126  lowest_file = file_cursor;
1127  }
1128  file_cursor = file_cursor->next;
1129  }
1130  if (lowest_file)
1131  {
1132  MoveFileToScratch(lowest_file);
1133  }
1134  else
1135  {
1136  /*somehow there are no files stored, but used space > total allocated*/
1137  assert(0);
1138  }
1139  }
1140 
1141 
1142 
1143  if (scratchpad.used > scratchpad.size)
1144  {
1145  /*slight hack, but this function does what is necessary.*/
1146  MoveFileToScratch(scratchpad.first_file);
1147  }
1148 }
1149 
1156 static S_NVM_ALLOCATION* GetAllocationFromId(U16BIT allocation_id)
1157 {
1158  S_NVM_ALLOCATION *allocation;
1159 
1160  allocation = allocation_list;
1161  while (allocation && allocation->id != allocation_id)
1162  {
1163  allocation = allocation->next;
1164  }
1165  return allocation;
1166 }
1167 
1173 static void CacheFile(char *file_name)
1174 {
1175  void *nvm_file = NULL;
1176  U32BIT bytes_read = 0;
1177  U8BIT *header_data = NULL;
1178  S_NVM_ALLOCATION *allocation;
1179  S_NVM_FILE *new_file = NULL;
1180 
1181  U32BIT allocation_id;
1182 
1183  /*open the file for reading and take a copy of the filename*/
1184  nvm_file = STB_NVMOpenFile( (U8BIT *)file_name, FILE_MODE_READ );
1185  if (nvm_file)
1186  {
1187  new_file = MHEG5getMem(sizeof(S_NVM_FILE));
1188  if (new_file)
1189  {
1190  new_file->fn.data = MHEG5getMem(strlen(file_name) + 1);
1191  if (new_file->fn.data)
1192  {
1193  new_file->fn.len = strlen(file_name);
1194  memcpy(new_file->fn.data, file_name, new_file->fn.len + 1);
1195 
1196  header_data = MHEG5getMem(HEADER_SIZE);
1197  }
1198  else
1199  {
1200  MHEG5freeMem(new_file);
1201  }
1202  }
1203  /*read the file*/
1204  if (header_data)
1205  {
1206  bytes_read = STB_NVMReadFile( nvm_file, header_data, HEADER_SIZE);
1207  }
1208  if (bytes_read == HEADER_SIZE)
1209  {
1210  /*parse the header from the file data into the cache fields*/
1211  ParseFileHeader(header_data, new_file);
1212 
1213  new_file->data = NULL;
1214  new_file->stored = MHEG5TRUE;
1215  new_file->previous = NULL;
1216  allocation_id = FilenameToId(new_file->fn);
1217  if (allocation_id)
1218  {
1219  allocation = GetAllocationFromId(allocation_id);
1220  if (!allocation)
1221  {
1222  allocation = &scratchpad;
1223  new_file->priority = 0;
1224  }
1225 
1226  new_file->next = allocation->first_file;
1227  allocation->first_file = new_file;
1228  if (new_file->next)
1229  {
1230  new_file->next->previous = new_file;
1231  }
1232  new_file->allocation = allocation;
1233  allocation->used += new_file->data_len;
1234  total_stored += new_file->data_len;
1235  }
1236  CalculateFileScore(new_file);
1237  }
1238  if (header_data)
1239  MHEG5freeMem(header_data);
1240 
1241  STB_NVMCloseFile( nvm_file );
1242  }
1243 }
1244 
1250 static void UpdateHeader( S_NVM_FILE *file)
1251 {
1252  U8BIT *header_data;
1253 
1254  header_data = file->data;
1255  if (header_data)
1256  {
1257  header_data[0] = (file->expires) & 0xff;
1258  header_data[1] = (file->expires >> 8) & 0xff;
1259  header_data[2] = (file->expires >> 16) & 0x01;
1260  header_data[2] |= (file->last_accessed << 1) & 0xfe;
1261  header_data[3] = (file->last_accessed >> 7) & 0xff;
1262  header_data[4] = (file->last_accessed >> 15) & 0x3;
1263  header_data[4] |= (file->priority << 2) & 0xc;
1264  header_data[5] = (file->data_len) & 0xff;
1265  header_data[6] = (file->data_len >> 8) & 0xff;
1266  }
1267 }
1268 
1275 static void ParseFileHeader(U8BIT *header_data, S_NVM_FILE *file)
1276 {
1277  U32BIT buffer;
1278 
1279  assert(file);
1280  buffer = header_data[0];
1281  buffer |= header_data[1] << 8;
1282  buffer |= (header_data[2] << 16) & 0x10000;
1283  file->expires = buffer;
1284 
1285  buffer = header_data[2] >> 1;
1286  buffer |= (header_data[3] << 7) & 0x7f00;
1287  buffer |= (header_data[4] << 15) & 0x18000;
1288  file->last_accessed = buffer;
1289 
1290  buffer = (header_data[4] >> 2) & 0x3;
1291  file->priority = buffer;
1292 
1293  buffer = header_data[5];
1294  buffer |= (header_data[6] << 8) & 0xff00;
1295  file->data_len = buffer;
1296 }
1297 
1303 static U32BIT FilenameToId(MHEG5String string)
1304 {
1305  U32BIT rc = 0;
1306  int i;
1307 
1308  if (!string.len)
1309  return 0;
1310  else /* HEX INT */
1311  {
1312  for (i = 0; i < 4; i++)
1313  if ((string.data[i] >= '0') && (string.data[i] <= '9'))
1314  rc = rc * 16 + ((int) string.data[i] - (int) '0');
1315  else if ((string.data[i] >= 'a') && (string.data[i] <= 'z'))
1316  rc = rc * 16 + ((int) string.data[i] - (int) 'a') + 10;
1317  else if ((string.data[i] >= 'A') && (string.data[i] <= 'Z'))
1318  rc = rc * 16 + ((int) string.data[i] - (int) 'A') + 10;
1319  else
1320  break;
1321  return rc;
1322  }
1323 }
1324 
1329 static void ClearFileDataCache(void)
1330 {
1331  S_NVM_ALLOCATION *allocation_cursor;
1332  S_NVM_FILE *file_cursor;
1333 
1334  allocation_cursor = allocation_list;
1335 
1336  while (allocation_cursor)
1337  {
1338  file_cursor = allocation_cursor->first_file;
1339  while (file_cursor)
1340  {
1341  if (file_cursor->data && file_cursor->stored)
1342  {
1343  MHEG5freeMem(file_cursor->data);
1344  file_cursor->data = NULL;
1345  }
1346  file_cursor = file_cursor->next;
1347  }
1348  allocation_cursor = allocation_cursor->next;
1349  }
1350 
1351  if (scratchpad.first_file)
1352  {
1353  file_cursor = scratchpad.first_file;
1354  while (file_cursor)
1355  {
1356  if (file_cursor->data && file_cursor->stored)
1357  {
1358  MHEG5freeMem(file_cursor->data);
1359  file_cursor->data = NULL;
1360  }
1361  file_cursor = file_cursor->next;
1362  }
1363  }
1364 }
1365 
1366 #endif /*INCLUDE_FREESAT*/
Date functions.
void * STB_NVMOpenFile(U8BIT *name, E_STB_DSK_FILE_MODE mode)
Opens an existing file or creates a new one.
E_MhegErr VQ_PutMsg(S_MhegMessage *pMsg, E_PRIORITY priority)
Post event or section message on queue. Copies data into queue.
Definition: glue_queue.c:248
F_MSG_PROCESS proc_msg_func
Definition: glue_queue.h:198
MHEG5Bool MHEG5stringEqual(MHEG5String *s1, MHEG5String *s2)
Compare two Strings (case sensitive!)
Definition: mh5base.c:710
const char * data
Definition: mh5gate.c:56
MHEG5 queue.
E_STB_DIR_ENTRY_TYPE
Definition: stb_nvm.h:48
#define MHEG5getMem
Definition: glue_memory.h:93
void MHEG5getDate(S32BIT *day, S32BIT *sec)
Modified Julian Date - see Davic 9.2.12.1.
Definition: mh5date.c:111
MHEG5Bool MHEG5FSnvmWrite(MHEG5String fn, void *data, MHEG5Int len, MHEG5Int expires, MHEG5Int priority)
void STB_NVMCloseFile(void *file)
Flushes and closes an open file.
E_MhegErr
Definition: mherrors.h:28
#define MAX_PATH_LEN
Definition: mh5tps.c:48
MHEG5 engine interface error codes.
void(* F_MSG_PROCESS)(void *data)
Function to Process voyager message.
Definition: glue_queue.h:70
Freesat NVM.
uint8_t U8BIT
Definition: techtype.h:82
void * STB_NVMOpenDirectory(U8BIT *dir_name)
Opens a directory in order to read the entries.
long MHEG5Int
Definition: mh5base.h:73
Memory functions.
DVB Service information functions are required by MHEG5 engine. All required functions should be non-...
#define MHEG5freeMem
Definition: glue_memory.h:94
void MHEG5FSnvmStoreClose(void)
void MHEG5FSnvmStoreOpen(void)
short MHEG5Bool
Definition: mh5base.h:71
U32BIT STB_NVMReadFile(void *file, U8BIT *data, U32BIT size)
Reads data from an open file.
MHEG5Byte * data
Definition: mh5base.h:85
int len
Definition: mh5gate.c:57
int32_t S32BIT
Definition: techtype.h:87
#define MHEG5TRUE
Definition: mh5base.h:49
E_DATA_TYPE data_type
Definition: glue_queue.h:199
#define MHEG5strncmp(a, b, n)
Definition: mh5base.h:52
uint16_t U16BIT
Definition: techtype.h:84
File System types.
System Wide Global Technical Data Type Definitions.
BOOLEAN STB_NVMReadDirectory(void *dir, U8BIT *filename, U16BIT filename_len, E_STB_DIR_ENTRY_TYPE *entry_type)
Reads the next entry from the directory, returning the name of the entry and the type of the entry...
Definition: mg_png.c:52
U32BIT STB_NVMWriteFile(void *file, U8BIT *data, U32BIT size)
Writes data to an open file.
MHEG5Int len
Definition: mh5base.h:84
MHEG5Bool MHEG5FSnvmRead(MHEG5String fn, void **data, MHEG5Int *len, MHEG5Int *expires, MHEG5Int *priority)
U8BIT BOOLEAN
Definition: techtype.h:99
union s_mhg_message::@13 data
#define MHEG5FALSE
Definition: mh5base.h:48
uint32_t U32BIT
Definition: techtype.h:86
BOOLEAN STB_NVMDeleteFile(U8BIT *filename)
Deletes the file.