#include #include #include #include #include #include #include #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) { perror("open"); } return false; } } 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 perror("write"); 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) { perror("write"); } 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("]"); } bool jsonlogger_init(const char *fifoname) { // try to create the named FIFO int ret = mkfifo(fifoname, 0666); if(ret < 0) { if(errno != EEXIST) { perror("mkfifo"); return false; } } strncpy(m_fifo_path, fifoname, sizeof(m_fifo_path)); 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(); }