KM3NeT CLB  2.0
KM3NeT CLB v2 Embedded Software
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
loghist.c
1 /*
2  * KM3NeT CLB v2 Firmware
3  * ----------------------
4  *
5  * Copyright 2012-2015 KM3NeT Collaboration
6  *
7  * All Rights Reserved.
8  *
9  *
10  * File : loghist.c
11  * Created : 28 sep. 2015
12  * Author : Vincent van Beveren
13  */
14 
15 #include "loghist.h"
16 #include <string.h>
17 #include <stdio.h>
18 #include "cfg_soc.h"
19 #include "util/log.h"
20 #include "dbg/show.h"
21 #include "drv/spi/sflash.h"
22 #include "lm32soc/lm32.h"
23 #include "err.h"
24 
25 
26 LOG_DEF(LogHist);
27 
28 static uint32_t _logLineID = 0;
29 
30 static char _lhLogBuf[LH_BUFFER_LENGTH][LH_BUFFER_WIDTH];
31 static int _lhLogBufIdx = 0;
32 
33 #define _UNINITIALIZED 0xFFFFFFFF
34 
35 static uint32_t _flashIdxCur;
36 static uint32_t _flashIdxOff;
37 static uint32_t _flashId;
38 static uint32_t _flashIdxIt = _UNINITIALIZED;
39 
40 #define LH_ENTRY_LEN 128
41 #define LH_ENTRY_HDR 16
42 #define LH_LINE_LEN ( LH_ENTRY_LEN - LH_ENTRY_HDR )
43 
44 #define MAGIC 0xCE11
45 
46 
47 // Addressing
48 #define SIZE_IN_ENTRIES ( LOGGING_SIZE / sizeof(LogEntry) )
49 // FIX 2019-04-23: Block size was wrong, explains problems with downloading full logs.
50 #define BLOCK_ENTRIES ( BLOCK_BYTES / sizeof(LogEntry))
51 
52 // log2 should be optimized out by the compiler.
53 #define MAX_ITERATIONS (int)(__builtin_log2(SIZE_IN_ENTRIES)+2)
54 
55 #define GET_ADDR(IDX) (IDX * sizeof(LogEntry) + LOGGING_OFFSET)
56 #define GET_NEXT(IDX) ((IDX + 1) % SIZE_IN_ENTRIES)
57 
58 bool lhEnableFlashWrite = true;
59 static bool _lhFlashInitialized = false;
60 
61 typedef struct {
62  uint16_t magic;
63  uint16_t _res0;
64  uint32_t id;
65  uint32_t _res1;
66  uint32_t _res2;
67  char line[LH_LINE_LEN];
68 } LogEntry;
69 
70 
71 
72 static bool loadEntry(LogEntry * entry, int idx, bool hdrOnly)
73 {
74  idx = idx % SIZE_IN_ENTRIES;
75  uint32_t addr = GET_ADDR(idx);
76  return errCondRebase(sfRead(addr, (uint8_t *) entry, hdrOnly ? LH_ENTRY_HDR : sizeof(LogEntry)), _logModInfo.name);
77 }
78 
79 static bool getId(int idx, int * id)
80 {
81  LogEntry entry;
82  if (!loadEntry(&entry, idx, true)) return false;
83 
84  if (entry.magic == MAGIC) *id = entry.id;
85  else *id = -1;
86 
87  return true;
88 }
89 
90 // cyclic less than function.
91 static inline bool less_than(uint32_t id1, uint32_t id2) {
92  return ( (id1 - id2) & 0x80000000);
93 }
94 
95 
96 bool lhFlashFormat() {
97 
98  bool allOk = true;
99  for (uint32_t addr = LOGGING_OFFSET; addr < LOGGING_OFFSET + LOGGING_SIZE; addr += BLOCK_BYTES)
100  {
101  allOk &= sfErase(addr);
102  }
103  if (!allOk) {
104  logError("Flash format failed!");
105  }
106  return allOk;
107 }
108 
109 // search for beginning of logging
111 {
112  _lhFlashInitialized = false;
113 #ifndef GOLDEN
114  int minIdx = 0;
115  int maxIdx = SIZE_IN_ENTRIES - 1;
116  int pivotId, pivotNextId;
117  int offId = -1;
118  int maxIts = MAX_ITERATIONS;
119 
120 
121  LogEntry le;
122 
123  if (!loadEntry(&le, 0, true)) return false;
124 
125  if (le.magic == MAGIC)
126  {
127  offId = le.id;
128 
129  } else if (le.magic != 0xFFFF) {
130  logWarn("Persistent logging memory invalid. Formatting...");
131  if (!lhFlashFormat()) {
132 
133  }
134  } else {
135  logInfo("Persistent logging did not find any information written yet");
136  }
137 
138  // nothing written yet
139  if (offId == -1)
140  {
141  _flashIdxCur = 0;
142  _flashIdxOff = 0;
143  _flashId = 0;
144  } else {
145  // binary search for the beginning of the flash
146  // TODO verify this algorithm always works
147  while (1)
148  {
149  maxIts--;
150 
151  int pivotIdx = ( minIdx + maxIdx ) >> 1;
152 
153  if (!getId(pivotIdx, &pivotId)) return false;
154  // So, the ID found is smaller than the first ID
155 
156  if (pivotId == -1 || less_than(pivotId, offId))
157  {
158  // so we must have passed the last entry
159  // so set max index to this position.
160  maxIdx = pivotIdx;
161  }
162  else
163  {
164  // pivotId is greater or equal to offId
165  // So, we be either on or before the most recent index
166 
167  // Load the next entry
168  if (!getId(pivotIdx + 1, &pivotNextId)) return false;
169 
170  // is the next entry less than the current
171  if (less_than(pivotNextId, pivotId))
172  {
173  // we have found the start
174  _flashIdxCur = GET_NEXT(pivotIdx);
175  _flashId = pivotId;
176  break;
177  }
178  else
179  {
180  // otherwise this is the minimal index
181  minIdx = pivotIdx;
182  }
183  }
184  // this could happen if the logging is not logically sorted
185  if (maxIts == 0)
186  {
187  logWarn("Persistent logging memory fragmented. Formatting...");
188  if (!lhFlashFormat()) return false;
189  offId = -1;
190  _flashIdxCur = 0;
191  _flashIdxOff = 0;
192  _flashId = 0;
193  break;
194  }
195  }
196  }
197 
198  _flashIdxOff = ((_flashIdxCur + BLOCK_ENTRIES - 1) / BLOCK_ENTRIES) * BLOCK_ENTRIES;
199 
200  if (!getId(_flashIdxOff,&offId)) return false;
201  if (offId == -1) _flashIdxOff = 0;
202 
203  logInfo("Persistent logging initiated: curIdx = %d, offIdx = %d, lastId = %d",
204  _flashIdxCur, _flashIdxOff, _flashId);
205 
206  // forward flash ID by one, since next log line may not reuse it!
207  _flashId = ( _flashId + 1 ) & 0x7FFFFFFF;
208  _lhFlashInitialized = true;
209 #endif
210  return true;
211 
212 }
213 
214 uint32_t lhGetLineById(uint32_t lastId, char ** logLinePtr)
215 {
216  uint32_t lines = _logLineID - lastId;
217  if (lines == 0) {
218  *logLinePtr = NULL;
219  return _logLineID;
220  }
221  if (lines > LH_BUFFER_LENGTH) {
222  lines = LH_BUFFER_LENGTH;
223  lastId = _logLineID - LH_BUFFER_LENGTH;
224  }
225  *logLinePtr = lhGetLine(lines - 1);
226  return lastId + 1;
227 }
228 
229 
230 bool lhFlashItStart(int count)
231 {
232 
233  if (!_lhFlashInitialized) return errSet(ERROR_CTX(E_INVSTATE));
234 
235  int avail = (_flashIdxCur - _flashIdxOff + SIZE_IN_ENTRIES) % SIZE_IN_ENTRIES;
236 
237  if (avail == 0) { // no entries is not an error, but should not return anything
238  _flashIdxIt = _UNINITIALIZED;
239  return true;
240  }
241 
242  if (count == 0 || count > avail) count = avail;
243 
244  _flashIdxIt = (_flashIdxCur - count + SIZE_IN_ENTRIES) % SIZE_IN_ENTRIES;
245 
246  return true;
247 }
248 
249 
250 bool lhFlashItNext(char * bufPtr, int bufSize)
251 {
252  if (_flashIdxIt == _UNINITIALIZED) return false;
253 
254  LogEntry le;
255  if (!loadEntry(&le, _flashIdxIt, false)) return false;
256 
257 
258  int len = strlen(le.line);
259  if (len + 1 > bufSize) len = bufSize - 1;
260 
261  memcpy(bufPtr, le.line, len);
262  bufPtr[len] = '\0';
263 
264  _flashIdxIt = GET_NEXT(_flashIdxIt);
265  if (_flashIdxIt == _flashIdxCur) _flashIdxIt = _UNINITIALIZED;
266  return true;
267 }
268 
269 
270 
271 static void lhStoreInFlash(LogLevel level, char * logOut)
272 {
273  // Filter stuff, everything lower than warn is not logger persistently.
274  if (level < logLevelInfo) return;
275 
276  // update flash offset for search.
277  if (_flashIdxCur == _flashIdxOff)
278  {
279 
280  // FIX 2019-04-24: when the offset needed to be moved the flashIdxOff always became 0
281  // causing the logging to always originate from offset 0, which is not true!
282  _flashIdxOff = (_flashIdxOff + BLOCK_ENTRIES ) % SIZE_IN_ENTRIES;
283  }
284 
285  uint32_t addr = GET_ADDR(_flashIdxCur);
286  if ((addr % BLOCK_BYTES) == 0)
287  {
288  if (!sfErase(addr)) {
289  _lhFlashInitialized = false;
290  logError("Failed to erase flash");
291  errPrint(true);
292  return;
293  }
294  }
295 
296  // Create log entry.
297  LogEntry entry;
298  entry.id = _flashId;
299  entry.magic = MAGIC;
300  // copy buffer
301  strncpy(entry.line, logOut, LH_LINE_LEN);
302  entry.line[LH_LINE_LEN - 1] = '\0';
303 
304  if (!sfProg(addr, (uint8_t *)&entry, sizeof(LogEntry)))
305  {
306  _lhFlashInitialized = false;
307  logError("Failed to store logging in flash");
308  errPrint(true);
309  }
310 
311 
312  _flashIdxCur = GET_NEXT(_flashIdxCur);
313  _flashId = ( _flashId + 1 ) & 0x7FFFFFFF;
314 }
315 
316 void lhStore(LogLevel level, char * logOut) {
317  strncpy(_lhLogBuf[_lhLogBufIdx], logOut, LH_BUFFER_WIDTH);
318  _lhLogBuf[_lhLogBufIdx][LH_BUFFER_WIDTH - 1] = '\0';
319  _lhLogBufIdx++;
320  if (_lhLogBufIdx >= LH_BUFFER_LENGTH) _lhLogBufIdx = 0;
321  _logLineID++;
322 #ifndef GOLDEN
323  if (_lhFlashInitialized && lhEnableFlashWrite) lhStoreInFlash(level, logOut);
324 #endif
325 }
326 
327 
328 char * lhGetLine(int idx)
329 {
330  if (idx >= LH_BUFFER_LENGTH) return NULL;
331 
332  int p = ( _lhLogBufIdx - idx ) - 1;
333  if (p < 0) p += LH_BUFFER_LENGTH;
334  return _lhLogBuf[p];
335 }
336 
337 void lhLogLast() {
338  int i;
339  for (i = LH_BUFFER_LENGTH - 1; i >= 0; --i) {
340  puts(lhGetLine(i));
341  }
342 }
343 
char * lhGetLine(int idx)
Returns a line from the in memory log, where index 0 is the last logged line.
Definition: loghist.c:328
Defines the configuration of the LM32 SOC for the CLBv2.
#define LH_BUFFER_WIDTH
Maximum width of the in memory log lines.
Definition: loghist.h:25
bool lhFlashInit()
Initializes the flash storage (may take a while).
Definition: loghist.c:110
Low level routines for LM32, including interrupt handling.
bool lhFlashItNext(char *bufPtr, int bufSize)
Get the next element.
Definition: loghist.c:250
#define LH_BUFFER_LENGTH
Maximum number of entries stored in memory.
Definition: loghist.h:24
void lhStore(LogLevel level, char *msg)
Stores a line in the buffer, and in flash if activated.
Definition: loghist.c:316
uint32_t lhGetLineById(uint32_t lastId, char **logLinePtr)
Returns the last log-line based on log-line ID.
Definition: loghist.c:214
LogLevel
Logging levels.
Definition: log.h:68
#define E_INVSTATE
Generic error: Module is in a state in which.
Definition: errorcode.h:103
bool lhEnableFlashWrite
Boolean to enable to disable the writing of logging to the flash.
Definition: loghist.c:58
#define logWarn(MSG,...)
Format a log message with warning level.
Definition: log.h:219
static bool errCondRebase(bool err, const char *name)
Transparent conditional error rebase.
Definition: err.h:117
Manages the global system error.
bool sfErase(uint32_t address)
Erase a sector in flash.
Definition: sflash.c:564
Info, general information.
Definition: log.h:72
void errPrint(bool clear)
Prints the last error.
Definition: err.c:79
Stores logging history.
bool lhFlashItStart(int count)
Start the iteration through the flash entries.
Definition: loghist.c:230
#define logError(MSG,...)
Format a log message with fatal level.
Definition: log.h:232
#define LOG_DEF(NAME,...)
Define a logger for a module.
Definition: log.h:129
bool sfRead(uint32_t address, uint8_t *data, uint32_t count)
Read from a specific address in flash.
Definition: sflash.c:491
bool errSet(uint32_t code, const char *error, const char *name)
Sets an error.
This driver implements access to the Serial Flash.
Implements a generic logger facility.
Definition: loghist.c:61
#define logInfo(MSG,...)
Write a log message with formatting on info level.
Definition: log.h:202
bool sfProg(uint32_t address, uint8_t *data, uint32_t count)
Program an page in flash.
Definition: sflash.c:519