meta data for this page
  •  

This is an old revision of the document!


log

Flow

Application:

  • every call to NRF_LOG_sth puts a log entry into ringbuffer.
  • NOT DEFERRED: NRF_LOG_FLUSH() is enforced: calls nrf_log_frontend_dequeue() in loop until ringbuffer empty.

Frontend:

  • DEFERRED: Application calls nrf_log_frontend_dequeue() and:
  • nrf_log_frontend_dequeue():
    • one entry is pop-ed from ringbuffer
    • new memobj is allocated from log_mempool to fit log entry.
    • all registered backends are iterated:
      • check if backend is enabled nrf_log_backend_is_enabled(p_backend)
      • filters: check if module log level and log entry severity level matches
      • if log entry should be send to backend - call nrf_log_backend_put
      • BACKEND: process log entry and do really printf-like processing and sending / TX-ing / storing
  • nrf_log_frontend_dequeue() return false if ringbuffer is empty

<uml> participant Application as APP queue “Circular Buffer\nNRF_LOG_BUFSIZE” as CB queue “log_mempool\ndynamic memory pool” as MEM control “nrf_log_frontend_dequeue()” as DE note over MEM NRF_LOG_MSGPOOL_ELEMENT_SIZE

  • *x NRF_LOG_MSGPOOL_ELEMENT_COUNT endnote control “backend RTT” as B1 control “backend UART” as B2 control “backend x” as B3 APP → CB: NRF_LOG_INFO() activate CB APP → CB: NRF_LOG_DEBUG() activate CB APP → CB: NRF_LOG_HEXDUMP() activate CB … APP → DE: NRF_LOG_PROCESS() activate DE DE ←- MEM: nrf_memobj_alloc() activate MEM activate DE CB –> DE: pop one entry deactivate CB DE –> DE: copy entry to allocated\nmempool object DE ←- DE: backend1:\ncheck filters and status DE –> B1: mempool object DE ←- DE: backend2:\ncheck filters and status DE –> B2: mempool object DE ←- DE: backend3:\ncheck filters and status DE –> B3: mempool object MEM ←- DE: nrf_memobj_put() deactivate MEM DE –> APP: return “circular buffer is empty” deactivate DE deactivate DE </uml> ===== buffer sizes ===== * Circular buffer of NRF_LOG_BUFSIZE (1024)**:
  • Its aim is to store log entry from app as fast as poosible without further processing.
  • DEFERRED: should be big enough to store all log entries until apps calls log to be processed.
  • Dynamic memory pool:
  • size is NRF_LOG_MSGPOOL_ELEMENT_SIZE (20) x NRF_LOG_MSGPOOL_ELEMENT_COUNT (8)
  • provides dynamic memory access, even to fragmented memory.
  • provides storage for log entry qualified to be passed to backends.
  • provides get/put counting semaphore locking mechanism, so one log entry can be passed to multiple log backends at time.
  • It looks like to be designed for background backends. Counting semaphore will keep object locked until all backends finish.
  • Background backends:
  • ???
  • Backends are using temporary string buffers - this is the real place where printf-like function writes generated strings.
  • NRF_LOG_BACKEND_UART_TEMP_BUFFER_SIZE 64

Backends api

typedef struct
{
    void (*put)(nrf_log_backend_t const * p_backend, nrf_log_entry_t * p_entry);
    void (*panic_set)(nrf_log_backend_t const * p_backend);
    void (*flush)(nrf_log_backend_t const * p_backend);
} nrf_log_backend_api_t;
  • put
    • printf-like processing
    • memobj with log entry is released (put() - counting semaphore decremented)
    • CLI:
      • memobj is not released. get() is called to lock it. And entry is pushed to own queue.
      • nrf_cli_process() –> cli_log_entry_process() gets one entry from queue. After processing it free memobj by put()
  • panic_set:
    • RTT: empty
    • UART: uninit uart driver
  • flush - empty function in most backends
    • CLI: (void)cli_log_entry_process(p_cli, true);