|
|
|
@ -89,6 +89,7 @@
@@ -89,6 +89,7 @@
|
|
|
|
|
|
|
|
|
|
#include <systemlib/systemlib.h> |
|
|
|
|
#include <systemlib/param/param.h> |
|
|
|
|
#include <systemlib/perf_counter.h> |
|
|
|
|
#include <version/version.h> |
|
|
|
|
|
|
|
|
|
#include <mavlink/mavlink_log.h> |
|
|
|
@ -112,12 +113,14 @@ static bool main_thread_should_exit = false; /**< Deamon exit flag */
@@ -112,12 +113,14 @@ static bool main_thread_should_exit = false; /**< Deamon exit flag */
|
|
|
|
|
static bool thread_running = false; /**< Deamon status flag */ |
|
|
|
|
static int deamon_task; /**< Handle of deamon task / thread */ |
|
|
|
|
static bool logwriter_should_exit = false; /**< Logwriter thread exit flag */ |
|
|
|
|
static const int MAX_NO_LOGFOLDER = 999; /**< Maximum number of log dirs */ |
|
|
|
|
static const int MAX_NO_LOGFILE = 999; /**< Maximum number of log files */ |
|
|
|
|
static const unsigned MAX_NO_LOGFOLDER = 999; /**< Maximum number of log dirs */ |
|
|
|
|
static const unsigned MAX_NO_LOGFILE = 999; /**< Maximum number of log files */ |
|
|
|
|
static const int LOG_BUFFER_SIZE_DEFAULT = 8192; |
|
|
|
|
static const int MAX_WRITE_CHUNK = 512; |
|
|
|
|
static const int MIN_BYTES_TO_WRITE = 512; |
|
|
|
|
|
|
|
|
|
static bool _extended_logging = false; |
|
|
|
|
|
|
|
|
|
static const char *log_root = "/fs/microsd/log"; |
|
|
|
|
static int mavlink_fd = -1; |
|
|
|
|
struct logbuffer_s lb; |
|
|
|
@ -218,6 +221,8 @@ static int create_log_dir(void);
@@ -218,6 +221,8 @@ static int create_log_dir(void);
|
|
|
|
|
*/ |
|
|
|
|
static int open_log_file(void); |
|
|
|
|
|
|
|
|
|
static int open_perf_file(const char* str); |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
sdlog2_usage(const char *reason) |
|
|
|
|
{ |
|
|
|
@ -225,12 +230,13 @@ sdlog2_usage(const char *reason)
@@ -225,12 +230,13 @@ sdlog2_usage(const char *reason)
|
|
|
|
|
fprintf(stderr, "%s\n", reason); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
errx(1, "usage: sdlog2 {start|stop|status} [-r <log rate>] [-b <buffer size>] -e -a -t\n" |
|
|
|
|
errx(1, "usage: sdlog2 {start|stop|status} [-r <log rate>] [-b <buffer size>] -e -a -t -x\n" |
|
|
|
|
"\t-r\tLog rate in Hz, 0 means unlimited rate\n" |
|
|
|
|
"\t-b\tLog buffer size in KiB, default is 8\n" |
|
|
|
|
"\t-e\tEnable logging by default (if not, can be started by command)\n" |
|
|
|
|
"\t-a\tLog only when armed (can be still overriden by command)\n" |
|
|
|
|
"\t-t\tUse date/time for naming log directories and files\n"); |
|
|
|
|
"\t-t\tUse date/time for naming log directories and files\n" |
|
|
|
|
"\t-x\tExtended logging"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -349,8 +355,8 @@ int create_log_dir()
@@ -349,8 +355,8 @@ int create_log_dir()
|
|
|
|
|
int open_log_file() |
|
|
|
|
{ |
|
|
|
|
/* string to hold the path to the log */ |
|
|
|
|
char log_file_name[16] = ""; |
|
|
|
|
char log_file_path[48] = ""; |
|
|
|
|
char log_file_name[32] = ""; |
|
|
|
|
char log_file_path[64] = ""; |
|
|
|
|
|
|
|
|
|
if (log_name_timestamp && gps_time != 0) { |
|
|
|
|
/* use GPS time for log file naming, e.g. /fs/microsd/2014-01-19/19_37_52.bin */ |
|
|
|
@ -378,7 +384,7 @@ int open_log_file()
@@ -378,7 +384,7 @@ int open_log_file()
|
|
|
|
|
|
|
|
|
|
if (file_number > MAX_NO_LOGFILE) { |
|
|
|
|
/* we should not end up here, either we have more than MAX_NO_LOGFILE on the SD card, or another problem */ |
|
|
|
|
warnx("all %d possible files exist already", MAX_NO_LOGFILE); |
|
|
|
|
mavlink_log_critical(mavlink_fd, "[sdlog2] ERR: max files %d", MAX_NO_LOGFILE); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -387,7 +393,58 @@ int open_log_file()
@@ -387,7 +393,58 @@ int open_log_file()
|
|
|
|
|
|
|
|
|
|
if (fd < 0) { |
|
|
|
|
warn("failed opening log: %s", log_file_name); |
|
|
|
|
mavlink_log_info(mavlink_fd, "[sdlog2] failed opening log: %s", log_file_name); |
|
|
|
|
mavlink_log_critical(mavlink_fd, "[sdlog2] failed opening log: %s", log_file_name); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
warnx("log file: %s", log_file_name); |
|
|
|
|
mavlink_log_info(mavlink_fd, "[sdlog2] log file: %s", log_file_name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return fd; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int open_perf_file(const char* str) |
|
|
|
|
{ |
|
|
|
|
/* string to hold the path to the log */ |
|
|
|
|
char log_file_name[32] = ""; |
|
|
|
|
char log_file_path[64] = ""; |
|
|
|
|
|
|
|
|
|
if (log_name_timestamp && gps_time != 0) { |
|
|
|
|
/* use GPS time for log file naming, e.g. /fs/microsd/2014-01-19/19_37_52.bin */ |
|
|
|
|
time_t gps_time_sec = gps_time / 1000000; |
|
|
|
|
struct tm t; |
|
|
|
|
gmtime_r(&gps_time_sec, &t); |
|
|
|
|
strftime(log_file_name, sizeof(log_file_name), "perf%H_%M_%S.txt", &t); |
|
|
|
|
snprintf(log_file_path, sizeof(log_file_path), "%s/%s_%s", log_dir, str, log_file_name); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
unsigned file_number = 1; // start with file log001
|
|
|
|
|
|
|
|
|
|
/* look for the next file that does not exist */ |
|
|
|
|
while (file_number <= MAX_NO_LOGFILE) { |
|
|
|
|
/* format log file path: e.g. /fs/microsd/sess001/log001.bin */ |
|
|
|
|
snprintf(log_file_name, sizeof(log_file_name), "perf%03u.txt", file_number); |
|
|
|
|
snprintf(log_file_path, sizeof(log_file_path), "%s/%s_%s", log_dir, str, log_file_name); |
|
|
|
|
|
|
|
|
|
if (!file_exist(log_file_path)) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
file_number++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (file_number > MAX_NO_LOGFILE) { |
|
|
|
|
/* we should not end up here, either we have more than MAX_NO_LOGFILE on the SD card, or another problem */ |
|
|
|
|
mavlink_log_critical(mavlink_fd, "[sdlog2] ERR: max files %d", MAX_NO_LOGFILE); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int fd = open(log_file_path, O_CREAT | O_WRONLY | O_DSYNC); |
|
|
|
|
|
|
|
|
|
if (fd < 0) { |
|
|
|
|
warn("failed opening log: %s", log_file_name); |
|
|
|
|
mavlink_log_critical(mavlink_fd, "[sdlog2] failed opening log: %s", log_file_name); |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
warnx("log file: %s", log_file_name); |
|
|
|
@ -529,6 +586,12 @@ void sdlog2_start_log()
@@ -529,6 +586,12 @@ void sdlog2_start_log()
|
|
|
|
|
errx(1, "error creating logwriter thread"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* write all performance counters */ |
|
|
|
|
int perf_fd = open_perf_file("preflight"); |
|
|
|
|
dprintf(perf_fd, "PERFORMANCE COUNTERS PRE-FLIGHT\n\n"); |
|
|
|
|
perf_print_all(perf_fd); |
|
|
|
|
close(perf_fd); |
|
|
|
|
|
|
|
|
|
logging_enabled = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -556,6 +619,12 @@ void sdlog2_stop_log()
@@ -556,6 +619,12 @@ void sdlog2_stop_log()
|
|
|
|
|
logwriter_pthread = 0; |
|
|
|
|
pthread_attr_destroy(&logwriter_attr); |
|
|
|
|
|
|
|
|
|
/* write all performance counters */ |
|
|
|
|
int perf_fd = open_perf_file("postflight"); |
|
|
|
|
dprintf(perf_fd, "PERFORMANCE COUNTERS POST-FLIGHT\n\n"); |
|
|
|
|
perf_print_all(perf_fd); |
|
|
|
|
close(perf_fd); |
|
|
|
|
|
|
|
|
|
sdlog2_status(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -572,7 +641,7 @@ int write_formats(int fd)
@@ -572,7 +641,7 @@ int write_formats(int fd)
|
|
|
|
|
int written = 0; |
|
|
|
|
|
|
|
|
|
/* fill message format packet for each format and write it */ |
|
|
|
|
for (int i = 0; i < log_formats_num; i++) { |
|
|
|
|
for (unsigned i = 0; i < log_formats_num; i++) { |
|
|
|
|
log_msg_format.body = log_formats[i]; |
|
|
|
|
written += write(fd, &log_msg_format, sizeof(log_msg_format)); |
|
|
|
|
} |
|
|
|
@ -679,7 +748,7 @@ int sdlog2_thread_main(int argc, char *argv[])
@@ -679,7 +748,7 @@ int sdlog2_thread_main(int argc, char *argv[])
|
|
|
|
|
* set error flag instead */ |
|
|
|
|
bool err_flag = false; |
|
|
|
|
|
|
|
|
|
while ((ch = getopt(argc, argv, "r:b:eat")) != EOF) { |
|
|
|
|
while ((ch = getopt(argc, argv, "r:b:eatx")) != EOF) { |
|
|
|
|
switch (ch) { |
|
|
|
|
case 'r': { |
|
|
|
|
unsigned long r = strtoul(optarg, NULL, 10); |
|
|
|
@ -715,6 +784,10 @@ int sdlog2_thread_main(int argc, char *argv[])
@@ -715,6 +784,10 @@ int sdlog2_thread_main(int argc, char *argv[])
|
|
|
|
|
log_name_timestamp = true; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'x': |
|
|
|
|
_extended_logging = true; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case '?': |
|
|
|
|
if (optopt == 'c') { |
|
|
|
|
warnx("option -%c requires an argument", optopt); |
|
|
|
@ -834,8 +907,10 @@ int sdlog2_thread_main(int argc, char *argv[])
@@ -834,8 +907,10 @@ int sdlog2_thread_main(int argc, char *argv[])
|
|
|
|
|
struct log_ESTM_s log_ESTM; |
|
|
|
|
struct log_PWR_s log_PWR; |
|
|
|
|
struct log_VICN_s log_VICN; |
|
|
|
|
struct log_GSN0_s log_GSN0; |
|
|
|
|
struct log_GSN1_s log_GSN1; |
|
|
|
|
struct log_GS0A_s log_GS0A; |
|
|
|
|
struct log_GS0B_s log_GS0B; |
|
|
|
|
struct log_GS1A_s log_GS1A; |
|
|
|
|
struct log_GS1B_s log_GS1B; |
|
|
|
|
} body; |
|
|
|
|
} log_msg = { |
|
|
|
|
LOG_PACKET_HEADER_INIT(0) |
|
|
|
@ -969,8 +1044,17 @@ int sdlog2_thread_main(int argc, char *argv[])
@@ -969,8 +1044,17 @@ int sdlog2_thread_main(int argc, char *argv[])
|
|
|
|
|
LOGBUFFER_WRITE_AND_COUNT(STAT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* --- GPS POSITION --- */ |
|
|
|
|
/* --- GPS POSITION - UNIT #1 --- */ |
|
|
|
|
if (gps_pos_updated) { |
|
|
|
|
|
|
|
|
|
float snr_mean = 0.0f; |
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < buf_gps_pos.satellites_visible; i++) { |
|
|
|
|
snr_mean += buf_gps_pos.satellite_snr[i]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
snr_mean /= buf_gps_pos.satellites_visible; |
|
|
|
|
|
|
|
|
|
log_msg.msg_type = LOG_GPS_MSG; |
|
|
|
|
log_msg.body.log_GPS.gps_time = buf_gps_pos.time_gps_usec; |
|
|
|
|
log_msg.body.log_GPS.fix_type = buf_gps_pos.fix_type; |
|
|
|
@ -983,19 +1067,48 @@ int sdlog2_thread_main(int argc, char *argv[])
@@ -983,19 +1067,48 @@ int sdlog2_thread_main(int argc, char *argv[])
|
|
|
|
|
log_msg.body.log_GPS.vel_e = buf_gps_pos.vel_e_m_s; |
|
|
|
|
log_msg.body.log_GPS.vel_d = buf_gps_pos.vel_d_m_s; |
|
|
|
|
log_msg.body.log_GPS.cog = buf_gps_pos.cog_rad; |
|
|
|
|
log_msg.body.log_GPS.sats = buf_gps_pos.satellites_visible; |
|
|
|
|
log_msg.body.log_GPS.snr_mean = snr_mean; |
|
|
|
|
log_msg.body.log_GPS.noise_per_ms = buf_gps_pos.noise_per_ms; |
|
|
|
|
log_msg.body.log_GPS.jamming_indicator = buf_gps_pos.jamming_indicator; |
|
|
|
|
LOGBUFFER_WRITE_AND_COUNT(GPS); |
|
|
|
|
|
|
|
|
|
/* log the SNR of each satellite for a detailed view of signal quality */ |
|
|
|
|
log_msg.msg_type = LOG_GSN0_MSG; |
|
|
|
|
/* pick the smaller number so we do not overflow any of the arrays */ |
|
|
|
|
unsigned gps_msg_max_snr = sizeof(buf_gps_pos.satellite_snr) / sizeof(buf_gps_pos.satellite_snr[0]); |
|
|
|
|
unsigned log_max_snr = sizeof(log_msg.body.log_GSN0.satellite_snr) / sizeof(log_msg.body.log_GSN0.satellite_snr[0]); |
|
|
|
|
unsigned sat_max_snr = (gps_msg_max_snr < log_max_snr) ? gps_msg_max_snr : log_max_snr; |
|
|
|
|
if (_extended_logging) { |
|
|
|
|
/* log the SNR of each satellite for a detailed view of signal quality */ |
|
|
|
|
unsigned gps_msg_max_snr = sizeof(buf_gps_pos.satellite_snr) / sizeof(buf_gps_pos.satellite_snr[0]); |
|
|
|
|
unsigned log_max_snr = sizeof(log_msg.body.log_GS0A.satellite_snr) / sizeof(log_msg.body.log_GS0A.satellite_snr[0]); |
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < sat_max_snr; i++) { |
|
|
|
|
log_msg.body.log_GSN0.satellite_snr[i] = buf_gps_pos.satellite_snr[i]; |
|
|
|
|
log_msg.msg_type = LOG_GS0A_MSG; |
|
|
|
|
memset(&log_msg.body.log_GS0A, 0, sizeof(log_msg.body.log_GS0A)); |
|
|
|
|
/* fill set A */ |
|
|
|
|
for (unsigned i = 0; i < gps_msg_max_snr; i++) { |
|
|
|
|
|
|
|
|
|
int satindex = buf_gps_pos.satellite_prn[i] - 1; |
|
|
|
|
|
|
|
|
|
/* handles index exceeding and wraps to to arithmetic errors */ |
|
|
|
|
if ((satindex >= 0) && (satindex < (int)log_max_snr)) { |
|
|
|
|
/* map satellites by their ID so that logs from two receivers can be compared */ |
|
|
|
|
log_msg.body.log_GS0A.satellite_snr[satindex] = buf_gps_pos.satellite_snr[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
LOGBUFFER_WRITE_AND_COUNT(GS0A); |
|
|
|
|
|
|
|
|
|
log_msg.msg_type = LOG_GS0B_MSG; |
|
|
|
|
memset(&log_msg.body.log_GS0B, 0, sizeof(log_msg.body.log_GS0B)); |
|
|
|
|
/* fill set B */ |
|
|
|
|
for (unsigned i = 0; i < gps_msg_max_snr; i++) { |
|
|
|
|
|
|
|
|
|
/* get second bank of satellites, thus deduct bank size from index */ |
|
|
|
|
int satindex = buf_gps_pos.satellite_prn[i] - 1 - log_max_snr; |
|
|
|
|
|
|
|
|
|
/* handles index exceeding and wraps to to arithmetic errors */ |
|
|
|
|
if ((satindex >= 0) && (satindex < (int)log_max_snr)) { |
|
|
|
|
/* map satellites by their ID so that logs from two receivers can be compared */ |
|
|
|
|
log_msg.body.log_GS0B.satellite_snr[satindex] = buf_gps_pos.satellite_snr[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
LOGBUFFER_WRITE_AND_COUNT(GS0B); |
|
|
|
|
} |
|
|
|
|
LOGBUFFER_WRITE_AND_COUNT(GSN0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* --- SENSOR COMBINED --- */ |
|
|
|
@ -1340,6 +1453,7 @@ void sdlog2_status()
@@ -1340,6 +1453,7 @@ void sdlog2_status()
|
|
|
|
|
float seconds = ((float)(hrt_absolute_time() - start_time)) / 1000000.0f; |
|
|
|
|
|
|
|
|
|
warnx("wrote %lu msgs, %4.2f MiB (average %5.3f KiB/s), skipped %lu msgs", log_msgs_written, (double)mebibytes, (double)(kibibytes / seconds), log_msgs_skipped); |
|
|
|
|
warnx("extended logging: %s", (_extended_logging) ? "ON" : "OFF"); |
|
|
|
|
mavlink_log_info(mavlink_fd, "[sdlog2] wrote %lu msgs, skipped %lu msgs", log_msgs_written, log_msgs_skipped); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|