Appiko
nvm_logger.c
1 
19 #include <math.h>
20 
21 #include "nvm_logger.h"
22 #include "hal_nvmc.h"
23 #include "stdbool.h"
24 #include "string.h"
25 #include "nrf_util.h"
26 #include "log.h"
27 #include "common_util.h"
28 
29 #define PAGE_METADATA_OFFSET 1
30 
31 #define MEM_RESET_VALUE 0xFFFFFFFF
32 
33 #define BYTE_RESET_VALUE 0xFF
34 
35 #define WORD_SIZE 4
36 
37 #define BYTES_PER_PAGE 4080
38 
39 #define PAGE_METADATA_LOC 0xFEF
40 
41 #define IN_PAGE_LOC(x) (x && 0xFFF)
42 
44 typedef struct
45 {
47  uint32_t entry_size;
49  uint32_t page_addrs[NVM_LOGGER_MAX_PAGES];
51  uint8_t no_pages;
53  uint8_t current_page;
55  uint32_t current_loc;
57  uint32_t last_entry_no;
59  uint32_t current_entry_no;
61  uint32_t total_entries;
63  uint32_t size_bytes;
65 
66 /*
67  * @brief Struct to store Page Metadata
68  */
69 typedef struct
70 {
72  uint8_t log_id;
74  uint8_t log_page_no;
76  uint16_t data_size;
77 }__attribute__ ((packed)) page_metadata_t;
78 
80 static uint32_t no_avail_pages = NVM_LOG_MAX_PAGES;
81 
82 static log_metadata_t LOGS[NVM_LOGGER_MAX_LOGS];
83 
84 static bool avail_pages[NVM_LOG_MAX_PAGES];
85 
86 static uint32_t p_empty_page[1024];
87 
88 const log_metadata_t EMPTY_LOG_METADATA =
89 {
90  .current_loc = 0,
91  .current_page = 0,
92  .entry_size = 0,
93  .last_entry_no = 0,
94  .no_pages = 0,
95  .total_entries = 0,
96  .current_entry_no =0,
97 };
98 
99 
100 const page_metadata_t EMPTY_PAGE_METADATA =
101 {
102  .log_id = 0xFF,
103  .log_page_no = 0xFF,
104  .data_size = 0xFFFF,
105 };
106 
107 void prepare_page_metadata (uint32_t log_id);
108 
109 void prepare_log_metadata (uint32_t * p_mem_loc, uint32_t page_no);
110 
111 void empty_page (uint32_t page_addr);
112 
113 void get_total_entries (uint32_t log_id)
114 {
115  for(uint32_t page_no = 0; page_no < LOGS[log_id].no_pages; page_no++)
116  {
117  for(uint32_t loc = 0; loc < LOGS[log_id].last_entry_no; loc++)
118  {
119  if(memcmp(
120  (uint32_t *)(LOGS[log_id].page_addrs[page_no]) + LOGS[log_id].entry_size*loc,
121  p_empty_page, sizeof(uint32_t) * LOGS[log_id].entry_size) != 0)
122  {
123 // log_printf();
124  LOGS[log_id].total_entries++;
125  }
126  }
127  log_printf("Total Entries LOGS[%d] : %d\n", log_id,LOGS[log_id].total_entries);
128  }
129 }
130 
131 uint32_t get_next_loc (uint32_t log_id)
132 {
133 
134  /* This is a dumb function which just asssumes that log exist and there is
135  * empty location available. So write log_write function to take care of
136  * erasing of next page */
137  log_printf("%s\n",__func__);
138  uint32_t page_no = 0;
139  uint32_t * p_mem_loc = (uint32_t *)LOGS[log_id].page_addrs[page_no];
140  bool next_loc_found = false;
141  uint32_t current_page_entry_no = 0;
142  while (next_loc_found == false)
143  {
144  if(memcmp(p_mem_loc, p_empty_page, sizeof(uint32_t) * LOGS[log_id].entry_size) == 0)
145  {
146  next_loc_found = true;
147  LOGS[log_id].current_loc = (uint32_t)(p_mem_loc );
148  LOGS[log_id].current_page = page_no;
149  LOGS[log_id].current_entry_no = current_page_entry_no;
150  }
151  else
152  {
153 // log_printf("nxt loc %x\n", p_mem_loc);
154  p_mem_loc += LOGS[log_id].entry_size;
155  current_page_entry_no++;
156  }
157  if(current_page_entry_no >= LOGS[log_id].last_entry_no)
158  {
159  page_no = (page_no + 1)%LOGS[log_id].no_pages;
160  p_mem_loc = (uint32_t *) LOGS[log_id].page_addrs[page_no];
161  current_page_entry_no = 0;
162  }
163  }
164  log_printf("Next loc : %x\n", p_mem_loc);
165  return (uint32_t)p_mem_loc;
166 }
167 
168 uint32_t update_log (log_config_t * log_config)
169 {
170  uint32_t cnt = 0; bool empty_log_found = false;
171  while(cnt < NVM_LOGGER_MAX_LOGS && empty_log_found == false)
172  {
173  if (memcmp (&LOGS[log_config->log_id], &EMPTY_LOG_METADATA, sizeof(log_metadata_t)) == 0)
174  {
175  empty_log_found = true;
176  LOGS[log_config->log_id].current_loc = log_config->start_page;
177  LOGS[log_config->log_id].current_page = 0;
178  LOGS[log_config->log_id].size_bytes = (log_config->entry_size );
179  LOGS[log_config->log_id].entry_size = CEIL_DIV(log_config->entry_size,4);
180  LOGS[log_config->log_id].no_pages = log_config->no_of_pages;
181  for(uint32_t page_no; page_no < log_config->no_of_pages; page_no++)
182  {
183  LOGS[log_config->log_id].page_addrs[page_no] = log_config->start_page
184  - page_no*NVM_LOGGER_PAGE_OFFSETS;
185  }
186  LOGS[log_config->log_id].last_entry_no = (BYTES_PER_PAGE/(LOGS[log_config->log_id].entry_size * WORD_SIZE));
187  }
188  else
189  {
190  log_config->log_id = (log_config->log_id + 1) % NVM_LOGGER_MAX_LOGS;
191  cnt++;
192  }
193  }
194  prepare_page_metadata (log_config->log_id);
195  return log_config->log_id;
196 
197 }
198 
199 void empty_page (uint32_t page_loc)
200 {
201  page_metadata_t page_metadata_buffer;
202  page_metadata_t * page_metadata_loc = (page_metadata_t *) (page_loc + NVM_LOGGER_PAGE_METADATA_ADDR);
203  memcpy(&page_metadata_buffer, page_metadata_loc, sizeof(page_metadata_t));
204  hal_nvmc_erase_page (page_loc);
205  hal_nvmc_write_data (page_metadata_loc, &page_metadata_buffer, sizeof(page_metadata_t));
206 
207 }
208 
209 void prepare_page_metadata (uint32_t log_id)
210 {
211  page_metadata_t local_page_metadata;
212  for(uint32_t page_no = 0; page_no < LOGS[log_id].no_pages; page_no++)
213  {
214  log_printf("%s : %x\n",__func__, LOGS[log_id].page_addrs[page_no]);
215  page_metadata_t * page_metadata_loc = (page_metadata_t *)
216  (LOGS[log_id].page_addrs[page_no] + NVM_LOGGER_PAGE_METADATA_ADDR);
217  local_page_metadata.log_id = log_id;
218  local_page_metadata.log_page_no = page_no;
219  local_page_metadata.data_size = (uint16_t)LOGS[log_id].size_bytes;
220  hal_nvmc_write_data (page_metadata_loc, &local_page_metadata, sizeof(page_metadata_t));
221  }
222 }
223 
224 void prepare_log_metadata (uint32_t * p_mem_loc, uint32_t page_no)
225 {
226 //Read page_metadata and generate the log_metadata
227  log_printf("%s\n",__func__);
228  page_metadata_t * local_ptr = (page_metadata_t *) p_mem_loc;
229  if(memcmp (local_ptr, &EMPTY_PAGE_METADATA, sizeof(page_metadata_t)) == 0 )
230  {
231  return;
232  }
233  LOGS[local_ptr->log_id].size_bytes = (uint32_t)local_ptr->data_size;
234  LOGS[local_ptr->log_id].entry_size = CEIL_DIV(local_ptr->data_size,4);
235  LOGS[local_ptr->log_id].page_addrs[local_ptr->log_page_no] =
236  ((uint32_t)p_mem_loc - NVM_LOGGER_PAGE_METADATA_ADDR);
237  LOGS[local_ptr->log_id].no_pages++;
238  LOGS[local_ptr->log_id].current_loc = 0;
239  LOGS[local_ptr->log_id].current_page = 0;
240  LOGS[local_ptr->log_id].last_entry_no = (BYTES_PER_PAGE/(LOGS[local_ptr->log_id].entry_size*4)) ;
241  avail_pages[page_no] = 0;
242  no_avail_pages--;
243 
244 }
245 
246 void nvm_logger_mod_init (void)
247 {
248  log_printf("%s\n", __func__);
249  memset (p_empty_page, BYTE_RESET_VALUE, sizeof(p_empty_page));
250  no_avail_pages = NVM_LOGGER_MAX_PAGES;
251  uint32_t * p_mem_loc = (uint32_t *)(NVM_LOG_PAGE0 + NVM_LOGGER_PAGE_METADATA_ADDR);
252  for (uint32_t page_no = 0; page_no < NVM_LOG_MAX_PAGES; page_no++)
253  {
254  avail_pages[page_no] = 1;
255  //go to every page_metadata location
256  prepare_log_metadata (p_mem_loc,page_no);
257  p_mem_loc -= NVM_LOGGER_PAGE_OFFSETS/WORD_SIZE;
258  }
259  for(uint32_t log_no = 0; log_no < NVM_LOGGER_MAX_LOGS; log_no++)
260  {
261  get_next_loc (log_no);
262  }
263 }
264 
265 
266 
267 //setup logic
268 uint32_t nvm_logger_log_init (log_config_t * log_config)
269 {
270  log_printf("%s\n", __func__);
271  if(no_avail_pages == 0)
272  {
273  log_printf("Memory Full..!!\n");
274  return NVM_LOGGER_MAX_LOGS;
275  }
276  else if((LOGS[log_config->log_id].size_bytes == log_config->entry_size) &&
277  (LOGS[log_config->log_id].no_pages == log_config->no_of_pages) &&
278  (LOGS[log_config->log_id].page_addrs[0] == log_config->start_page))
279 
280  {
281  log_printf("Log already present..!!\n");
282  get_total_entries (log_config->log_id);
283  return log_config->log_id;
284  }
285  else if(no_avail_pages >= log_config->no_of_pages)
286 
287  {
288  log_printf("New Log..!!\n");
289  no_avail_pages -= log_config->no_of_pages;
290  return update_log (log_config);
291  }
292  else
293  {
294  log_printf("Not enough Pages available..!!\n");
295  return NVM_LOGGER_MAX_LOGS;
296  }
297  return -1;
298 
299 }
300 
301 
302 //Writing logic
303 void nvm_logger_feed_data (uint32_t log_id, void * data)
304 {
305  uint32_t * p_buff = (uint32_t *)LOGS[log_id].current_loc;
306 
307  hal_nvmc_write_data (p_buff, (uint8_t *)data,
308  LOGS[log_id].size_bytes);
309 // log_printf("%x %d\n", p_buff, *p_buff);
310  {
311  LOGS[log_id].current_entry_no ++;
312  LOGS[log_id].current_loc += LOGS[log_id].entry_size * WORD_SIZE;
313  LOGS[log_id].total_entries++;
314  }
315  if(LOGS[log_id].current_entry_no < LOGS[log_id].last_entry_no )
316  {
317  return;
318  }
319  {
320  log_printf("page change..!!\n");
321  LOGS[log_id].current_page = ((LOGS[log_id].current_page + 1) % LOGS[log_id].no_pages);
322 
323  if(memcmp((uint32_t *)LOGS[log_id].page_addrs[LOGS[log_id].current_page],
324  (uint32_t *)p_empty_page, BYTES_PER_PAGE) != 0)
325  {
326  log_printf("Erase page %x\n",LOGS[log_id].page_addrs[LOGS[log_id].current_page]);
327  LOGS[log_id].total_entries -= LOGS[log_id].last_entry_no;
328  empty_page (LOGS[log_id].page_addrs[LOGS[log_id].current_page]);
329  }
330 
331 
332  LOGS[log_id].current_loc = LOGS[log_id].page_addrs[LOGS[log_id].current_page];
333  LOGS[log_id].current_entry_no = 0;
334  }
335 }
336 
337 void nvm_logger_fetch_tail_data (uint32_t log_id, void * dest_loc, uint32_t entry_no)
338 {
339  uint32_t * p_dest = (uint32_t *)dest_loc;
340  uint32_t * p_src = NULL;
341  if(entry_no >= LOGS[log_id].total_entries)
342  {
343  uint32_t loc = ((LOGS[log_id].current_page)
344  + 1*(LOGS[log_id].total_entries != LOGS[log_id].current_entry_no))
345  %LOGS[log_id].no_pages;
346  p_src = (uint32_t *)(LOGS[log_id].page_addrs[loc]);
347  while(memcmp(p_src, p_empty_page, LOGS[log_id].entry_size * WORD_SIZE) == 0)
348  {
349  loc = (loc + 1)%LOGS[log_id].no_pages;
350  p_src = (uint32_t *)(LOGS[log_id].page_addrs[loc]);
351  }
352  memcpy(p_dest, p_src, LOGS[log_id].size_bytes);
353  return;
354  }
355  if(entry_no > LOGS[log_id].current_entry_no)//Don't use >= condition
356  {
357  entry_no = (entry_no - LOGS[log_id].current_entry_no );
358 
359  uint32_t entry_page = ((LOGS[log_id].current_page) -
360  (1 + ((entry_no - 1)/(LOGS[log_id].last_entry_no))) +
361  LOGS[log_id].no_pages) % LOGS[log_id].no_pages;
362 
363  entry_no =
364  (((( LOGS[log_id].current_page - entry_page + LOGS[log_id].no_pages)
365  %LOGS[log_id].no_pages) * (LOGS[log_id].last_entry_no )) - entry_no *
366  1);
367  p_src = (uint32_t *)(LOGS[log_id].page_addrs[entry_page]) +
368  LOGS[log_id].entry_size*(entry_no);
369  memcpy(p_dest, p_src, LOGS[log_id].size_bytes);
370 
371  return;
372 
373  }
374  p_src = (uint32_t *)(LOGS[log_id].current_loc) -
375  LOGS[log_id].entry_size * (entry_no) ;
376  memcpy(p_dest, p_src, LOGS[log_id].size_bytes);
377 
378  return;
379 
380 }
381 
382 //set direction flag
383 //
384 
385 
386 void nvm_logger_empty_log (uint32_t log_id)
387 {
388  for(uint32_t page_no = 0; page_no < LOGS[log_id].no_pages; page_no++)
389  {
390  empty_page (LOGS[log_id].page_addrs[page_no]);
391  }
392  LOGS[log_id].current_entry_no = 0;
393  LOGS[log_id].current_page = 0;
394  LOGS[log_id].current_loc = LOGS[log_id].page_addrs[0];
395 }
396 
397 bool nvm_logger_is_log_empty (uint32_t log_id)
398 {
399  bool log_empty = true;
400  for(uint32_t page_no = 0; page_no < LOGS[log_id].no_pages; page_no++)
401  {
402  if(memcmp((uint8_t * )LOGS[log_id].page_addrs[page_no],
403  p_empty_page, NVM_LOGGER_PAGE_METADATA_ADDR) != 0)
404  {
405  log_empty = false;
406  }
407  }
408  return log_empty;
409 }
410 
411 void nvm_logger_release_log (uint32_t log_id)
412 {
413  for(uint32_t page_no; page_no < LOGS[log_id].no_pages; page_no++)
414  {
415  hal_nvmc_erase_page (LOGS[log_id].page_addrs[page_no]);
416  }
417 }
418 
419 
uint8_t current_page
Definition: nvm_logger.c:53
uint8_t log_id
Definition: nvm_logger.c:72
uint32_t entry_size
Definition: nvm_logger.c:47
Strcture for Operation time.
Definition: sensepi_ble.h:38
uint16_t data_size
Definition: nvm_logger.c:76
uint32_t last_entry_no
Definition: nvm_logger.c:57
uint32_t page_addrs[NVM_LOGGER_MAX_PAGES]
Definition: nvm_logger.c:49
uint32_t current_loc
Definition: nvm_logger.c:55
uint8_t no_pages
Definition: nvm_logger.c:51
#define CEIL_DIV(A, B)
When the result of a division is not an integer, the result is rounded up to the next integer.
Definition: common_util.h:90
uint32_t size_bytes
Definition: nvm_logger.c:63
uint32_t total_entries
Definition: nvm_logger.c:61
uint32_t current_entry_no
Definition: nvm_logger.c:59
uint8_t log_page_no
Definition: nvm_logger.c:74