193 lines
4.3 KiB
C
193 lines
4.3 KiB
C
// For F_SETPIPE_SZ
|
|
#define _GNU_SOURCE
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "logger.h"
|
|
|
|
#include "jsonlogger.h"
|
|
|
|
#define LOG_OR_RETURN(...) \
|
|
if(dprintf(m_fifo_fd, __VA_ARGS__) < 0) { \
|
|
return false; \
|
|
}
|
|
|
|
static int m_fifo_fd = -1;
|
|
static char m_fifo_path[1024];
|
|
|
|
static bool start_message(void)
|
|
{
|
|
if(m_fifo_fd < 0) {
|
|
// FIFO was not opened yet. Try to open it now.
|
|
m_fifo_fd = open(m_fifo_path, O_WRONLY | O_NONBLOCK);
|
|
if(m_fifo_fd < 0) {
|
|
if(errno != ENXIO) {
|
|
LOG(LVL_ERR, "open: %s", strerror(errno));
|
|
}
|
|
return false;
|
|
}
|
|
// Increase pipe buffer to prevent/reduce EAGAIN during a JSON
|
|
// message to prevent corrupted JSON messages. 1048576 is the
|
|
// current maximum as permitted by the Linux kernel.
|
|
if (fcntl(m_fifo_fd, F_SETPIPE_SZ, 1048576) < 0) {
|
|
LOG(LVL_ERR, "fcntl: %s", strerror(errno));
|
|
}
|
|
}
|
|
|
|
ssize_t ret = write(m_fifo_fd, "{", 1);
|
|
if(ret < 0) {
|
|
// FIFO is not writable or other error
|
|
switch(errno) {
|
|
case EAGAIN: // FIFO not ready for writing -> drop message
|
|
break;
|
|
|
|
case EPIPE: // FIFO was closed on the other side
|
|
close(m_fifo_fd);
|
|
m_fifo_fd = -1;
|
|
break;
|
|
|
|
default: // other errors are logged to stderr
|
|
LOG(LVL_ERR, "write: %s", strerror(errno));
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool end_message(void)
|
|
{
|
|
ssize_t ret = write(m_fifo_fd, "}\n", 2);
|
|
if(ret < 0) {
|
|
// FIFO is not writable or other error
|
|
if(errno != EAGAIN) {
|
|
LOG(LVL_ERR, "write: %s", strerror(errno));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool dump_var_array_cf(const var_array_cf_t *varray)
|
|
{
|
|
LOG_OR_RETURN("[");
|
|
|
|
if(varray->used > 0) {
|
|
LOG_OR_RETURN("[%g, %g]", crealf(varray->symbols[0]), cimagf(varray->symbols[0]));
|
|
|
|
for(size_t i = 1; i < varray->used; i++) {
|
|
LOG_OR_RETURN(", [%g, %g]", crealf(varray->symbols[i]), cimagf(varray->symbols[i]));
|
|
}
|
|
}
|
|
|
|
LOG_OR_RETURN("]");
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool jsonlogger_init(const char *fifoname)
|
|
{
|
|
// try to create the named FIFO
|
|
int ret = mkfifo(fifoname, 0666);
|
|
if(ret < 0) {
|
|
if(errno != EEXIST) {
|
|
LOG(LVL_ERR, "mkfifo: %s", strerror(errno));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
strncpy(m_fifo_path, fifoname, sizeof(m_fifo_path));
|
|
m_fifo_path[sizeof(m_fifo_path)-1] = '\0';
|
|
|
|
m_fifo_fd = -1; // open on demand
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void jsonlogger_shutdown(void)
|
|
{
|
|
close(m_fifo_fd);
|
|
}
|
|
|
|
|
|
bool jsonlogger_log_simple_integer(const char *msg_type, int64_t value)
|
|
{
|
|
if(!start_message()) {
|
|
return false;
|
|
}
|
|
|
|
LOG_OR_RETURN("\"%s\": %ld", msg_type, value);
|
|
|
|
return end_message();
|
|
}
|
|
|
|
|
|
bool jsonlogger_log_simple_double(const char *msg_type, double value)
|
|
{
|
|
if(!start_message()) {
|
|
return false;
|
|
}
|
|
|
|
LOG_OR_RETURN("\"%s\": %g", msg_type, value);
|
|
|
|
return end_message();
|
|
}
|
|
|
|
|
|
bool jsonlogger_log_rx_stats(const rx_stats_t *rx_stats)
|
|
{
|
|
if(!start_message()) {
|
|
return false;
|
|
}
|
|
|
|
LOG_OR_RETURN("\"preambles_found\": %zd, ", rx_stats->preambles_found);
|
|
LOG_OR_RETURN("\"successful_decodes\": %zd, ", rx_stats->successful_decodes);
|
|
LOG_OR_RETURN("\"failed_decodes\": %zd, ", rx_stats->failed_decodes);
|
|
LOG_OR_RETURN("\"header_errors\": %zd", rx_stats->header_errors);
|
|
|
|
return end_message();
|
|
}
|
|
|
|
|
|
bool jsonlogger_log_rx_packet_info(const rx_packet_dbg_t *rx_packet_dbg)
|
|
{
|
|
if(!start_message()) {
|
|
return false;
|
|
}
|
|
|
|
LOG_OR_RETURN("\"preamble_symbols\": ");
|
|
dump_var_array_cf(&rx_packet_dbg->preamble_symbols);
|
|
LOG_OR_RETURN(", \"header_symbols\": ");
|
|
dump_var_array_cf(&rx_packet_dbg->header_symbols);
|
|
LOG_OR_RETURN(", \"data_symbols\": ");
|
|
dump_var_array_cf(&rx_packet_dbg->data_symbols);
|
|
LOG_OR_RETURN(", ");
|
|
|
|
LOG_OR_RETURN("\"preamble_correlation_peak\": %g, ", rx_packet_dbg->preamble_correlation_peak);
|
|
LOG_OR_RETURN("\"header_rssi_dB\": %g, ", rx_packet_dbg->header_rssi);
|
|
LOG_OR_RETURN("\"data_rssi_dB\": %g, ", rx_packet_dbg->data_rssi);
|
|
LOG_OR_RETURN("\"noise_floor_level_dB\": %g, ", rx_packet_dbg->noise_floor_level);
|
|
|
|
LOG_OR_RETURN("\"carrier_tracked_freq_Hz\": %g, ", rx_packet_dbg->carrier_tracked_freq);
|
|
LOG_OR_RETURN("\"initial_freq_offset_Hz\": %g, ", rx_packet_dbg->initial_freq_offset);
|
|
LOG_OR_RETURN("\"final_freq_offset_Hz\": %g, ", rx_packet_dbg->final_freq_offset);
|
|
|
|
LOG_OR_RETURN("\"header_evm\": %g, ", rx_packet_dbg->header_evm);
|
|
LOG_OR_RETURN("\"data_evm\": %g", rx_packet_dbg->data_evm);
|
|
|
|
return end_message();
|
|
}
|