int main(int argc, char *argv[]) { #ifndef WIN32 setlinebuf (stdout); #endif char logpath[PATH_MAX]; memset (logpath, 0, sizeof (logpath)); logger_t logger; memset (&logger, 0, sizeof (logger)); // set some defaults logger.force_overwrite = 0; logger.auto_increment = 0; logger.use_strftime = 0; char *chan_regex = strdup(".*"); double max_write_queue_size_mb = DEFAULT_MAX_WRITE_QUEUE_SIZE_MB; logger.invert_channels = 0; logger.fflush_interval_ms = 100; char *lcmurl = NULL; char *optstring = "a:fic:shm:vu:"; int c; struct option long_opts[] = { { "auto-split-hours", required_argument, 0, 'a' }, { "auto-split-mb", required_argument, 0, 'b' }, { "channel", required_argument, 0, 'c' }, { "force", no_argument, 0, 'f' }, { "increment", required_argument, 0, 'i' }, { "lcm-url", required_argument, 0, 'l' }, { "max-unwritten-mb", required_argument, 0, 'm' }, { "strftime", required_argument, 0, 's' }, { "invert-channels", no_argument, 0, 'v' }, { "flush-interval", required_argument, 0,'u'}, { 0, 0, 0, 0 } }; while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) { switch (c) { case 'a': logger.auto_split_hours = strtod(optarg, NULL); logger.auto_increment = 1; if(logger.auto_split_hours <= 0) { usage(); return 1; } break; case 'b': logger.auto_split_mb = strtod(optarg, NULL); logger.auto_increment = 1; if(logger.auto_split_mb <= 0) { usage(); return 1; } break; case 'f': logger.force_overwrite = 1; break; case 'c': free(chan_regex); chan_regex = strdup(optarg); break; case 'i': logger.auto_increment = 1; break; case 's': logger.use_strftime = 1; break; case 'l': free(lcmurl); lcmurl = strdup(optarg); break; case 'v': logger.invert_channels = 1; break; case 'm': max_write_queue_size_mb = strtod(optarg, NULL); if(max_write_queue_size_mb <= 0) { usage(); return 1; } break; case 'u': logger.fflush_interval_ms = atol(optarg); if(logger.fflush_interval_ms <= 0) { usage(); return 1; } break; case 'h': default: usage(); return 1; }; } if (optind == argc) { strcpy (logger.input_fname, "lcmlog-%Y-%m-%d"); logger.auto_increment = 1; logger.use_strftime = 1; } else if (optind == argc - 1) { strncpy (logger.input_fname, argv[optind], sizeof (logger.input_fname)); } else if (optind < argc-1) { usage (); return 1; } // initialize GLib threading g_thread_init(NULL); logger.time0 = timestamp_now(); logger.max_write_queue_size = (int64_t)(max_write_queue_size_mb * (1 << 20)); if(0 != open_logfile(&logger)) return 1; // create write thread logger.write_thread_exit_flag = 0; logger.mutex = g_mutex_new(); logger.write_queue_size = 0; logger.write_queue = g_async_queue_new(); logger.write_thread = g_thread_create(write_thread, &logger, TRUE, NULL); // begin logging logger.lcm = lcm_create (lcmurl); free(lcmurl); if (!logger.lcm) { fprintf (stderr, "Couldn't initialize LCM!"); return 1; } if(logger.invert_channels) { // if inverting the channels, subscribe to everything and invert on the // callback lcm_subscribe(logger.lcm, ".*", message_handler, &logger); char *regexbuf = g_strdup_printf("^%s$", chan_regex); #ifdef USE_GREGEX GError *rerr = NULL; logger.regex = g_regex_new(regexbuf, (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, &rerr); if(rerr) { fprintf(stderr, "%s\n", rerr->message); g_free(regexbuf); return 1; } #else if (0 != regcomp (&logger.preg, regexbuf, REG_NOSUB | REG_EXTENDED)) { fprintf(stderr, "bad regex!\n"); g_free(regexbuf); return 1; } #endif g_free(regexbuf); } else { // otherwise, let LCM handle the regex lcm_subscribe(logger.lcm, chan_regex, message_handler, &logger); } free(chan_regex); _mainloop = g_main_loop_new (NULL, FALSE); signal_pipe_glib_quit_on_kill (); glib_mainloop_attach_lcm (logger.lcm); #ifdef USE_SIGHUP signal(SIGHUP, sighup_handler); #endif // main loop g_main_loop_run (_mainloop); fprintf(stderr, "Logger exiting\n"); // stop the write thread g_mutex_lock(logger.mutex); logger.write_thread_exit_flag = 1; g_mutex_unlock(logger.mutex); g_async_queue_push(logger.write_queue, &logger.write_thread_exit_flag); g_thread_join(logger.write_thread); g_mutex_free(logger.mutex); // cleanup. This isn't strictly necessary, do it to be pedantic and so that // leak checkers don't complain glib_mainloop_detach_lcm (logger.lcm); lcm_destroy (logger.lcm); lcm_eventlog_destroy (logger.log); for(void *msg = g_async_queue_try_pop(logger.write_queue); msg; msg=g_async_queue_try_pop(logger.write_queue)) { if(msg == &logger.write_thread_exit_flag) continue; free(msg); } g_async_queue_unref(logger.write_queue); if(logger.invert_channels) { #ifdef USE_GREGEX g_regex_unref(logger.regex); #else regfree(&logger.preg); #endif } return 0; }
int main(int argc, char *argv[]) { g_type_init (); dbg_init (); // initialize application state and zero out memory g_self = (state_t*) calloc( 1, sizeof(state_t) ); state_t *self = g_self; // run the main loop self->loop = g_main_loop_new(NULL, FALSE); getopt_t *gopt = getopt_create(); getopt_add_bool (gopt, 'h', "help", 0, "Show this help"); getopt_add_bool (gopt, 'v', "verbose", 0, "Be verbose"); if (!getopt_parse(gopt, argc, argv, 1) || getopt_get_bool(gopt,"help")) { printf("Usage: %s [options]\n\n", argv[0]); getopt_do_usage(gopt); return 0; } self->verbose = getopt_get_bool(gopt, "verbose"); self->lcm = lcm_create(NULL); if (!self->lcm) return 1; // read config file if (!(self->config = read_config_file ())) { dbg (DBG_ERROR, "[viewer] failed to read config file."); return -1; } // attach lcm to main loop glib_mainloop_attach_lcm (self->lcm); // publish cam settings every now and then // g_timeout_add_seconds (2, &publish_log_info_data, self); // g_timeout_add_seconds (2, &dump_to_index_file, self); // listen to tablet event navlcm_log_info_t_subscribe (self->lcm, "LOG_INFO", on_log_info_set_event, self); list_files (self); publish_log_info_data (self); // connect to kill signal signal_pipe_glib_quit_on_kill (self->loop); // run main loop g_main_loop_run (self->loop); // cleanup g_main_loop_unref (self->loop); return 0; }