302 *buffer = debug_buffer; |
302 *buffer = debug_buffer; |
303 } |
303 } |
304 return wait_error; |
304 return wait_error; |
305 } |
305 } |
306 |
306 |
307 |
|
308 /* LOGGING |
|
309 */ |
|
310 |
|
311 #define LOG_LEVELS 4 |
|
312 #define LOG_CRITICAL 0 |
|
313 #define LOG_WARNING 1 |
|
314 #define LOG_INFO 2 |
|
315 #define LOG_DEBUG 3 |
|
316 |
|
317 #ifndef LOG_BUFFER_SIZE |
|
318 #define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ |
|
319 #endif |
|
320 #define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) |
|
321 static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE]; |
|
322 void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ |
|
323 if(buffpos + size < LOG_BUFFER_SIZE){ |
|
324 memcpy(&LogBuff[level][buffpos], buf, size); |
|
325 }else{ |
|
326 uint32_t remaining = LOG_BUFFER_SIZE - buffpos - 1; |
|
327 memcpy(&LogBuff[level][buffpos], buf, remaining); |
|
328 memcpy(LogBuff[level], buf + remaining, size - remaining); |
|
329 } |
|
330 } |
|
331 void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ |
|
332 if(buffpos + size < LOG_BUFFER_SIZE){ |
|
333 memcpy(buf, &LogBuff[level][buffpos], size); |
|
334 }else{ |
|
335 uint32_t remaining = LOG_BUFFER_SIZE - buffpos; |
|
336 memcpy(buf, &LogBuff[level][buffpos], remaining); |
|
337 memcpy(buf + remaining, LogBuff[level], size - remaining); |
|
338 } |
|
339 } |
|
340 |
|
341 /* Log buffer structure |
|
342 |
|
343 |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... |
|
344 | Message1 Body | Tail1 | Message2 Body | Tail2 | |
|
345 |
|
346 */ |
|
347 typedef struct { |
|
348 uint32_t msgidx; |
|
349 uint32_t msgsize; |
|
350 unsigned long tick; |
|
351 IEC_TIME time; |
|
352 } mTail; |
|
353 |
|
354 /* Log cursor : 64b |
|
355 |63 ... 32|31 ... 0| |
|
356 | Message | Buffer | |
|
357 | counter | Index | */ |
|
358 static uint64_t LogCursor[LOG_LEVELS] = {0x0,0x0,0x0,0x0}; |
|
359 |
|
360 /* Store one log message of give size */ |
|
361 int LogMessage(uint8_t level, uint8_t* buf, uint32_t size){ |
|
362 if(size < LOG_BUFFER_SIZE - sizeof(mTail)){ |
|
363 uint32_t buffpos; |
|
364 uint64_t new_cursor, old_cursor; |
|
365 |
|
366 mTail tail; |
|
367 tail.msgsize = size; |
|
368 tail.tick = __tick; |
|
369 PLC_GetTime(&tail.time); |
|
370 |
|
371 /* We cannot increment both msg index and string pointer |
|
372 in a single atomic operation but we can detect having been interrupted. |
|
373 So we can try with atomic compare and swap in a loop until operation |
|
374 succeeds non interrupted */ |
|
375 do{ |
|
376 old_cursor = LogCursor[level]; |
|
377 buffpos = (uint32_t)old_cursor; |
|
378 tail.msgidx = (old_cursor >> 32); |
|
379 new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) |
|
380 | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); |
|
381 }while(AtomicCompareExchange64( |
|
382 (long long*)&LogCursor[level], |
|
383 (long long)old_cursor, |
|
384 (long long)new_cursor)!=old_cursor); |
|
385 |
|
386 copy_to_log(level, buffpos, buf, size); |
|
387 copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); |
|
388 |
|
389 return 1; /* Success */ |
|
390 }else{ |
|
391 uint8_t mstr[] = "Logging error : message too big"; |
|
392 LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); |
|
393 } |
|
394 return 0; |
|
395 } |
|
396 |
|
397 uint32_t GetLogCount(uint8_t level){ |
|
398 return (uint64_t)LogCursor[level] >> 32; |
|
399 } |
|
400 |
|
401 /* Return message size and content */ |
|
402 uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ |
|
403 uint64_t cursor = LogCursor[level]; |
|
404 if(cursor){ |
|
405 /* seach cursor */ |
|
406 uint32_t stailpos = (uint32_t)cursor; |
|
407 uint32_t smsgidx; |
|
408 mTail tail; |
|
409 tail.msgidx = cursor >> 32; |
|
410 tail.msgsize = 0; |
|
411 |
|
412 /* Message search loop */ |
|
413 do { |
|
414 smsgidx = tail.msgidx; |
|
415 stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; |
|
416 copy_from_log(level, stailpos, &tail, sizeof(mTail)); |
|
417 }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); |
|
418 |
|
419 if(tail.msgidx == msgidx){ |
|
420 uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; |
|
421 uint32_t totalsize = tail.msgsize; |
|
422 *tick = tail.tick; |
|
423 *tv_sec = tail.time.tv_sec; |
|
424 *tv_nsec = tail.time.tv_nsec; |
|
425 copy_from_log(level, sbuffpos, buf, |
|
426 totalsize > max_size ? max_size : totalsize); |
|
427 return totalsize; |
|
428 } |
|
429 } |
|
430 return 0; |
|
431 } |
|