DVBCore  20.3.0
DVBCore Documentation
stbnvm.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2004 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 // compiler library header files
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 // third party header files
32 
33 // Ocean Blue Software header files
34 
35 #include <techtype.h>
36 #include <dbgfuncs.h>
37 
38 #include "stbnvm.h"
39 #include "stbcsum.h"
40 #include "stbheap.h"
41 #include "stbhwmem.h"
42 
43 //---macro definitions for this file-------------------------------------------
44 #ifdef STB_NV_PRINT_REQUIRED
45 #define STB_NV_PRINT(x) DEBUG_PRINTX_CONDITIONAL(DEBUG_STB_NV) x
46 #else
47 #define STB_NV_PRINT(x)
48 #endif
49 
50 //---constant definitions for this file----------------------------------------
51 
52 #define FORMAT_VERSION_NUM 1
53 #define FORMAT_ID_STRING "DTVKit NV"
54 #define FORMAT_ID_STRING_SIZE 10
55 
56 //---local typedef structs for this file---------------------------------------
57 
58 // if this format structure is changed, the version number MUST be incremented!
59 typedef struct
60 {
61  U8BIT id_str[FORMAT_ID_STRING_SIZE];
62  U8BIT version;
63  U8BIT num_data_blocks;
65 
66 typedef struct
67 {
68  U32BIT data_block_id;
69  U32BIT data_block_size;
71 
72 typedef struct s_data_block_list
73 {
74  S_DATA_BLOCK_REC block;
75  U32BIT nvm_addr;
76  struct s_data_block_list *next;
77  struct s_data_block_list *prev;
79 
80 //---local (static) variable declarations for this file------------------------
81 // (internal variables declared static to make them local)
82 static NVM_FORMAT_REC nvm_format;
83 static S_DATA_BLOCK_LIST *data_block_list;
84 static U32BIT stb_area_offset;
85 
86 //---local function prototypes for this file-----------------------------------
87 // (internal functions declared static to make them local)
88 
89 static U32BIT CalcNvmOffset(U32BIT offset);
90 static void MoveBlock(U32BIT src_addr, U32BIT dst_addr, U32BIT size);
91 static BOOLEAN LoadFormat(void);
92 static void SaveFormat(void);
93 
94 //---local function definitions------------------------------------------------
95 
96 static U32BIT CalcNvmOffset(U32BIT offset)
97 {
98  return(offset + (offset % STB_MEMGetNVMAlign()));
99 }
100 
114 static void MoveBlock(U32BIT src_addr, U32BIT dst_addr, U32BIT bytes)
115 {
116  U8BIT *temp_array;
117 
118  FUNCTION_START(MoveBlock);
119 
120  if ((dst_addr + bytes) > STB_MEMGetNVMSize())
121  {
122  bytes = (STB_MEMGetNVMSize() - dst_addr);
123  }
124 
125  temp_array = (U8BIT *)STB_GetMemory(bytes);
126  if (temp_array != NULL)
127  {
128  if (STB_MEMReadNVM(src_addr, bytes, temp_array))
129  {
130  STB_MEMWriteNVM(dst_addr, bytes, temp_array);
131  }
132  STB_FreeMemory(temp_array);
133  }
134 
135  FUNCTION_FINISH(MoveBlock);
136 }
137 
149 static BOOLEAN LoadFormat(void)
150 {
151  BOOLEAN ret_val = FALSE;
152  U32BIT offset;
153  S_DATA_BLOCK_LIST *rec_ptr;
154  S_DATA_BLOCK_LIST *last_rec;
155  U8BIT i;
156 
157  FUNCTION_START(LoadFormat);
158 
159  // read format info into RAM
160  if (STB_MEMReadNVM(STB_MEMGetNVMOffset(), (U32BIT)sizeof(NVM_FORMAT_REC), (U8BIT *)&nvm_format))
161  {
162  // validate format string
163  if (strcmp((char *)nvm_format.id_str, (char *)FORMAT_ID_STRING) == 0)
164  {
165  // check version number
166  if (nvm_format.version == FORMAT_VERSION_NUM)
167  {
168  ret_val = TRUE;
169 
170  /* Read any data blocks */
171  offset = CalcNvmOffset(STB_MEMGetNVMOffset() + sizeof(NVM_FORMAT_REC));
172 
173  for (i = 0, last_rec = NULL; (i < nvm_format.num_data_blocks) && ret_val; i++)
174  {
175  rec_ptr = (S_DATA_BLOCK_LIST *)STB_GetMemory(sizeof(S_DATA_BLOCK_LIST));
176  if (rec_ptr != NULL)
177  {
178  if (STB_MEMReadNVM(offset, sizeof(S_DATA_BLOCK_REC), (U8BIT *)&rec_ptr->block))
179  {
180  rec_ptr->nvm_addr = CalcNvmOffset(offset + sizeof(S_DATA_BLOCK_REC));
181  rec_ptr->next = NULL;
182 
183  if (data_block_list == NULL)
184  {
185  data_block_list = rec_ptr;
186  }
187  else if (last_rec)
188  {
189  last_rec->next = rec_ptr;
190  }
191 
192  rec_ptr->prev = last_rec;
193  last_rec = rec_ptr;
194 
195  /* Offset to the next data block is size of header + size of this data block */
196  offset = CalcNvmOffset(offset + sizeof(S_DATA_BLOCK_REC) + rec_ptr->block.data_block_size);
197  }
198  else
199  {
200  ret_val = FALSE;
201  }
202  }
203  }
204 
205  /* Offset should now be pointing at the start of the service database, so save this value */
206  stb_area_offset = offset;
207  }
208  }
209  }
210 
211  FUNCTION_FINISH(LoadFormat);
212 
213  return(ret_val);
214 }
215 
225 static void SaveFormat(void)
226 {
227  S_DATA_BLOCK_LIST *rec_ptr;
228  U32BIT offset;
229 
230  FUNCTION_START(SaveFormat);
231 
232  /* Setup new format info and checksum */
233  strncpy((char *)nvm_format.id_str, (char *)FORMAT_ID_STRING, FORMAT_ID_STRING_SIZE);
234  nvm_format.version = FORMAT_VERSION_NUM;
235 #if 0
236  /* Calculate the offset of each area in NVM, adjusting it according to the alignment
237  * required by the physical storage media */
238  nvm_format.app_area_offset = (U32BIT)sizeof(NVM_FORMAT_REC);
239  nvm_format.app_area_offset += (nvm_format.app_area_offset % STB_MEMGetNVMAlign());
240 
241  nvm_format.dvb_area_offset = nvm_format.app_area_offset + nvm_format.app_area_size;
242  nvm_format.dvb_area_offset += (nvm_format.dvb_area_offset % STB_MEMGetNVMAlign());
243 
244  nvm_format.stb_area_offset = (nvm_format.dvb_area_offset + nvm_format.dvb_area_size);
245  nvm_format.stb_area_offset += (nvm_format.stb_area_offset % STB_MEMGetNVMAlign());
246 
247  nvm_format.checksum = STB_CalcChecksum((U8BIT *)&nvm_format, (U32BIT)sizeof(NVM_FORMAT_REC));
248 #endif
249  /* Write header format info into NVM */
250  offset = STB_MEMGetNVMOffset();
251 
252  if (STB_MEMWriteNVM(offset, (U32BIT)sizeof(NVM_FORMAT_REC), (U8BIT *)&nvm_format))
253  {
254  /* Write the header for each data block */
255  offset = CalcNvmOffset(offset + sizeof(NVM_FORMAT_REC));
256 
257  for (rec_ptr = data_block_list; rec_ptr != NULL; rec_ptr = rec_ptr->next)
258  {
259  STB_MEMWriteNVM(offset, (U32BIT)sizeof(S_DATA_BLOCK_REC), (U8BIT *)&rec_ptr->block);
260 
261  /* Offset to the next data block is size of header + size of this data block */
262  offset = CalcNvmOffset(offset + sizeof(S_DATA_BLOCK_REC) + rec_ptr->block.data_block_size);
263  }
264 
265  stb_area_offset = offset;
266  }
267 
268  FUNCTION_FINISH(SaveFormat);
269 }
270 
271 //---global function definitions-----------------------------------------------
272 
285 {
286  FUNCTION_START(STB_NVMInitialise);
287 
288  if (!LoadFormat())
289  {
290  memset(&nvm_format, 0, sizeof(nvm_format));
291  SaveFormat();
292  }
293 
294  FUNCTION_FINISH(STB_NVMInitialise);
295 }
296 
302 U32BIT STB_NVMGetDataBlockSize(U32BIT data_block_id)
303 {
304  U32BIT size;
305  S_DATA_BLOCK_LIST *rec_ptr;
306 
307  FUNCTION_START(STB_NVMGetDataBlockSize);
308 
309  size = 0;
310 
311  for (rec_ptr = data_block_list; rec_ptr != NULL; rec_ptr = rec_ptr->next)
312  {
313  if (rec_ptr->block.data_block_id == data_block_id)
314  {
315  size = rec_ptr->block.data_block_size;
316  break;
317  }
318  }
319 
320  FUNCTION_FINISH(STB_NVMGetDataBlockSize);
321 
322  return(size);
323 }
324 
332 BOOLEAN STB_NVMDataBlockRead(U32BIT data_block_id, U32BIT num_bytes, U8BIT *dest_addr)
333 {
334  BOOLEAN ret_val;
335  S_DATA_BLOCK_LIST *rec_ptr;
336 
337  FUNCTION_START(STB_NVMDataBlockRead);
338 
339  ret_val = FALSE;
340 
341  /* Find the info for the data block to be read */
342  for (rec_ptr = data_block_list; rec_ptr != NULL; rec_ptr = rec_ptr->next)
343  {
344  if (rec_ptr->block.data_block_id == data_block_id)
345  {
346  ret_val = STB_MEMReadNVM(rec_ptr->nvm_addr, num_bytes, dest_addr);
347  break;
348  }
349  }
350 
351  FUNCTION_FINISH(STB_NVMDataBlockRead);
352 
353  return(ret_val);
354 }
355 
363 BOOLEAN STB_NVMDataBlockWrite(U32BIT data_block_id, U32BIT num_bytes, U8BIT *src_addr)
364 {
365  BOOLEAN ret_val;
366  S_DATA_BLOCK_LIST *rec_ptr;
367  S_DATA_BLOCK_LIST *last_rec;
368  S_DATA_BLOCK_LIST *bptr;
369  U32BIT offset;
370  BOOLEAN block_changed;
371 
372  FUNCTION_START(STB_NVMDataBlockWrite);
373 
374  ret_val = FALSE;
375 
376  /* Find the info for the data block to be read */
377  for (rec_ptr = data_block_list, last_rec = NULL; rec_ptr != NULL; rec_ptr = rec_ptr->next)
378  {
379  if (rec_ptr->block.data_block_id == data_block_id)
380  {
381  break;
382  }
383 
384  last_rec = rec_ptr;
385  }
386 
387  block_changed = FALSE;
388 
389  if (rec_ptr == NULL)
390  {
391  /* This is a new data block so create a record for it */
392  rec_ptr = (S_DATA_BLOCK_LIST *)STB_GetMemory(sizeof(S_DATA_BLOCK_LIST));
393  if (rec_ptr != NULL)
394  {
395  memset(rec_ptr, 0, sizeof(*rec_ptr));
396 
397  rec_ptr->block.data_block_id = data_block_id;
398  rec_ptr->block.data_block_size = num_bytes;
399 
400  /* Add it to the end of the list */
401  if (data_block_list == NULL)
402  {
403  data_block_list = rec_ptr;
404  }
405  else
406  {
407  last_rec->next = rec_ptr;
408  }
409 
410  rec_ptr->prev = last_rec;
411 
412  nvm_format.num_data_blocks++;
413  block_changed = TRUE;
414  }
415  }
416 
417  if (rec_ptr != NULL)
418  {
419  /* The data block is new or has increased in size so all following blocks need to be
420  * moved, in reverse order */
421  if (rec_ptr->block.data_block_size != num_bytes)
422  {
423  block_changed = TRUE;
424  rec_ptr->block.data_block_size = num_bytes;
425  }
426 
427  /* Calculate the new offset */
428  offset = STB_MEMGetNVMOffset() + sizeof(NVM_FORMAT_REC);;
429  for (bptr = data_block_list, last_rec = NULL; bptr != NULL; bptr = bptr->next)
430  {
431  offset = CalcNvmOffset(offset + sizeof(S_DATA_BLOCK_REC) + bptr->block.data_block_size);
432  last_rec = bptr;
433  }
434 
435  /* Now have the new offset for the service database, check it needs to be moved */
436  if (offset != stb_area_offset)
437  {
438  /* Move the service database */
439  MoveBlock(stb_area_offset, offset, STB_NVMGetSTBSize());
440  stb_area_offset = offset;
441 
442  /* Move all data blocks in reverse order until the one that's changed or been added */
443  for (bptr = last_rec; (bptr != NULL) && (bptr != rec_ptr); bptr = bptr->prev)
444  {
445  /* Calc the new offset for this block */
446  offset = CalcNvmOffset(offset - sizeof(S_DATA_BLOCK_REC) - bptr->block.data_block_size);
447  MoveBlock(bptr->nvm_addr, offset, sizeof(S_DATA_BLOCK_REC) + bptr->block.data_block_size);
448  bptr->nvm_addr = CalcNvmOffset(offset + sizeof(S_DATA_BLOCK_REC));
449  }
450  }
451 
452  if (block_changed)
453  {
454  rec_ptr->nvm_addr = CalcNvmOffset(offset - rec_ptr->block.data_block_size);
455  SaveFormat();
456  }
457 
458  /* Save the data */
459  ret_val = STB_MEMWriteNVM(rec_ptr->nvm_addr, num_bytes, src_addr);
460  }
461 
462  FUNCTION_FINISH(STB_NVMDataBlockWrite);
463 
464  return(ret_val);
465 }
466 
478 U32BIT STB_NVMGetSTBSize(void)
479 {
480  U32BIT ret_val;
481 
482  FUNCTION_START(STB_NVMGetSTBSize);
483 
484  ASSERT(STB_MEMGetNVMSize() > (STB_MEMGetNVMOffset()+stb_area_offset));
485 
486  ret_val = (STB_MEMGetNVMSize() - STB_MEMGetNVMOffset() - stb_area_offset);
487 
488  FUNCTION_FINISH(STB_NVMGetSTBSize);
489 
490  return(ret_val);
491 }
492 
506 BOOLEAN STB_NVMSTBRead(U32BIT offset, U32BIT bytes, U8BIT *dest_addr)
507 {
508  BOOLEAN ret_val;
509  U32BIT nvm_addr;
510 
511  FUNCTION_START(STB_NVMSTBRead);
512 
513  ASSERT(bytes > 0);
514  ASSERT(dest_addr != NULL);
515 
516  nvm_addr = STB_MEMGetNVMOffset();
517  nvm_addr += stb_area_offset;
518  nvm_addr += offset;
519  ret_val = STB_MEMReadNVM(nvm_addr, bytes, dest_addr);
520 
521  FUNCTION_FINISH(STB_NVMSTBRead);
522 
523  return(ret_val);
524 }
525 
539 BOOLEAN STB_NVMSTBWrite(U32BIT offset, U32BIT bytes, U8BIT *src_addr)
540 {
541  BOOLEAN ret_val;
542  U32BIT nvm_addr;
543 
544  FUNCTION_START(STB_NVMSTBWrite);
545 
546  ASSERT(bytes > 0);
547  ASSERT(src_addr != NULL);
548 
549  nvm_addr = STB_MEMGetNVMOffset();
550  nvm_addr += stb_area_offset;
551  nvm_addr += offset;
552  ret_val = STB_MEMWriteNVM(nvm_addr, bytes, src_addr);
553 
554  FUNCTION_FINISH(STB_NVMSTBWrite);
555 
556  return(ret_val);
557 }
558 
559 //*****************************************************************************
560 // End of file
561 //*****************************************************************************
562 
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
void STB_NVMInitialise(void)
Initialises NVM control.
Definition: stbnvm.c:284
BOOLEAN STB_MEMWriteNVM(U32BIT addr, U32BIT bytes, U8BIT *src_addr)
Writes data to the NVM.
BOOLEAN STB_NVMSTBRead(U32BIT offset, U32BIT bytes, U8BIT *dest_addr)
Reads bytes from the given position of the STB area of NVM.
Definition: stbnvm.c:506
Header file - Function prototypes for NVM control.
U8BIT STB_CalcChecksum(U8BIT *data_ptr, U32BIT data_size)
Calculates the checksum to zero for the data block provided.
Definition: stbcsum.c:62
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
BOOLEAN STB_NVMDataBlockRead(U32BIT data_block_id, U32BIT num_bytes, U8BIT *dest_addr)
Reads data bytes for the given data block from NVM.
Definition: stbnvm.c:332
U32BIT STB_NVMGetDataBlockSize(U32BIT data_block_id)
Returns the number of bytes of data stored for the given data block.
Definition: stbnvm.c:302
Debug functions header file.
U32BIT STB_MEMGetNVMOffset(void)
Returns any offset required in NVM to avoid private data.
U8BIT STB_MEMGetNVMAlign(void)
Returns the word alignment size of the NVM device.
U32BIT STB_MEMGetNVMSize(void)
Returns the size (capacity) of the NVM.
Header file - Function prototypes for NVM and Heap.
System Wide Global Technical Data Type Definitions.
Header file - Function prototypes for check sum calcs.
BOOLEAN STB_NVMSTBWrite(U32BIT offset, U32BIT bytes, U8BIT *src_addr)
Writes bytes into the given position of the STB area of NVM.
Definition: stbnvm.c:539
Header file - Function prototypes for heap memory.
BOOLEAN STB_NVMDataBlockWrite(U32BIT data_block_id, U32BIT num_bytes, U8BIT *src_addr)
Writes data bytes for the given data block to NVM.
Definition: stbnvm.c:363
BOOLEAN STB_MEMReadNVM(U32BIT addr, U32BIT bytes, U8BIT *dst_addr)
Read data from the NVM.
U32BIT STB_NVMGetSTBSize(void)
Returns size of STB database storage are (in bytes).
Definition: stbnvm.c:478