summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2019-11-13 22:35:11 +0100
committerNicolas Schodet2019-11-14 00:41:59 +0100
commitea90facf4674046e0a58969a6e0eb23054c550de (patch)
tree2ad747ab3f376b0102bedb21d996555fa1416343
parentaea9101e6b3da183adcd99f5377c799d194efd11 (diff)
Use GLib for command line too
-rw-r--r--Makefile4
-rw-r--r--cli.c93
-rw-r--r--cli.h (renamed from gui.h)10
-rw-r--r--gui.c37
-rw-r--r--gui_app.c3
-rw-r--r--gui_app_window.c10
-rw-r--r--main.c87
-rw-r--r--options.c157
-rw-r--r--options.h16
9 files changed, 189 insertions, 228 deletions
diff --git a/Makefile b/Makefile
index e80a611..83675d2 100644
--- a/Makefile
+++ b/Makefile
@@ -6,9 +6,9 @@ GLIB_COMPILE_RESOURCES = \
$(shell pkg-config --variable=glib_compile_resources gio-2.0)
SOURCES := \
+ cli.c \
device.c \
image.c \
- gui.c \
gui_app.c \
gui_app_window.c \
gui_resources.c \
@@ -27,6 +27,6 @@ camicro: $(SOURCES:%.c=%.o)
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
clean:
- rm -f camicro $(SOURCES:%.c=%.o) gui_resources.c
+ rm -f camicro $(SOURCES:%.c=%.o) $(SOURCES:%.c=%.d) gui_resources.c
-include $(SOURCES:%.c=%.d)
diff --git a/cli.c b/cli.c
new file mode 100644
index 0000000..33edcee
--- /dev/null
+++ b/cli.c
@@ -0,0 +1,93 @@
+/* Camicro - Microscope camera viewer.
+ *
+ * Copyright (C) 2019 Nicolas Schodet
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ * Email: <nico at ni.fr.eu.org>
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <png.h>
+
+#include "device.h"
+#include "utils.h"
+#include "cli.h"
+
+void
+cli_read_images(libusb_context *usb, struct device *device, int count,
+ const char *out)
+{
+ device_start(device);
+ for (int i = 0; i < count;) {
+ const struct device_image *device_image = device_read(device);
+ if (device_image) {
+ char *name = NULL;
+ if (asprintf(&name, out, i) < 0)
+ utils_fatal("can not prepare file name");
+ utils_info("write %s", name);
+ png_image image;
+ memset(&image, 0, sizeof(image));
+ image.version = PNG_IMAGE_VERSION;
+ image.width = device_image->width;
+ image.height = device_image->height;
+ image.format = PNG_FORMAT_BGRA;
+ int r = png_image_write_to_file(&image, name, 0,
+ device_image->pixels, device_image->stride, NULL);
+ if (r == 0)
+ utils_fatal("can not write image: %s", image.message);
+ free(name);
+ i++;
+ } else {
+ libusb_handle_events(usb);
+ }
+ }
+ device_stop(device);
+}
+
+int
+cli_run(struct options *options)
+{
+ libusb_context *usb;
+ int r = libusb_init(&usb);
+ if (r)
+ utils_fatal("unable to initialize libusb: %s", libusb_strerror(r));
+ struct device *device = device_open(usb);
+ if (!device)
+ utils_fatal("unable to find device");
+ const struct device_info *info = device_get_info(device);
+ if (options->exposure_ms > 0.0)
+ device_set_exposure(device, options->exposure_ms);
+ if (options->gain > 0.0)
+ device_set_gain(device, options->gain);
+ int width = -1, height = -1;
+ for (int i = 0; width == -1 && i < info->resolutions; i++) {
+ const struct device_info_resolution *ir = &info->resolution[i];
+ if ((options->width == -1 || options->width == ir->width)
+ && (options->height == -1 || options->height == ir->height)) {
+ width = ir->width;
+ height = ir->height;
+ }
+ }
+ if (width == -1)
+ utils_fatal("no matching resolution");
+ device_set_resolution(device, width, height, 0);
+ cli_read_images(usb, device, options->count, options->out);
+ device_close(device);
+ libusb_exit(usb);
+ return EXIT_SUCCESS;
+}
diff --git a/gui.h b/cli.h
index b244717..01f2d8a 100644
--- a/gui.h
+++ b/cli.h
@@ -1,5 +1,5 @@
-#ifndef gui_h
-#define gui_h
+#ifndef cli_h
+#define cli_h
/* Camicro - Microscope camera viewer.
*
* Copyright (C) 2019 Nicolas Schodet
@@ -22,8 +22,10 @@
* Web: http://ni.fr.eu.org/
* Email: <nico at ni.fr.eu.org>
*/
+#include "options.h"
+/* Run command line application, return status code. */
int
-gui_run(int argc, char **argv);
+cli_run(struct options *options);
-#endif /* gui_h */
+#endif /* cli_h */
diff --git a/gui.c b/gui.c
deleted file mode 100644
index bce344a..0000000
--- a/gui.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Camicro - Microscope camera viewer.
- *
- * Copyright (C) 2019 Nicolas Schodet
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Contact :
- * Web: http://ni.fr.eu.org/
- * Email: <nico at ni.fr.eu.org>
- */
-#include <gtk/gtk.h>
-
-#include "gui.h"
-#include "gui_app.h"
-
-int
-gui_run(int argc, char **argv)
-{
- int status;
- GuiApp *app;
- app = gui_app_new();
- status = g_application_run(G_APPLICATION(app), argc, argv);
- g_object_unref(app);
- return status;
-}
diff --git a/gui_app.c b/gui_app.c
index d29ba2a..5df8d15 100644
--- a/gui_app.c
+++ b/gui_app.c
@@ -24,6 +24,7 @@
#include "gui_app.h"
#include "gui_app_window.h"
+#include "options.h"
#include "usb_source.h"
#include "utils.h"
@@ -59,6 +60,7 @@ gui_app_init(GuiApp *app)
GuiAppPrivate *priv = gui_app_get_instance_private(app);
priv->usb = NULL;
priv->usb_source = NULL;
+ options_add(G_APPLICATION(app));
}
static void
@@ -107,6 +109,7 @@ gui_app_class_init(GuiAppClass *class)
G_APPLICATION_CLASS(class)->startup = gui_app_startup;
G_APPLICATION_CLASS(class)->activate = gui_app_activate;
G_APPLICATION_CLASS(class)->shutdown = gui_app_shutdown;
+ G_APPLICATION_CLASS(class)->handle_local_options = options_handle;
g_signal_new("video-ready", GUI_APP_TYPE, G_SIGNAL_RUN_FIRST, 0, NULL,
NULL, NULL, G_TYPE_NONE, 0);
}
diff --git a/gui_app_window.c b/gui_app_window.c
index 0acdaaa..8403d8e 100644
--- a/gui_app_window.c
+++ b/gui_app_window.c
@@ -124,6 +124,7 @@ video_start(GuiAppWindowPrivate *priv)
device_start(priv->device);
priv->video_ready_handler_id = g_signal_connect(priv->app, "video-ready",
G_CALLBACK(video_ready_cb), priv);
+ gtk_button_set_label(priv->start_stop_button, "Stop");
}
/* Stop video. */
@@ -139,6 +140,7 @@ video_stop(GuiAppWindowPrivate *priv)
device_stop(priv->device);
priv->started = false;
gtk_widget_queue_draw(GTK_WIDGET(priv->video));
+ gtk_button_set_label(priv->start_stop_button, "Start");
}
static gboolean
@@ -188,13 +190,10 @@ start_stop_button_clicked_cb(GtkButton *button, gpointer user_data)
GuiAppWindow *win =
GUI_APP_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button)));
GuiAppWindowPrivate *priv = gui_app_window_get_instance_private(win);
- if (!priv->started) {
- gtk_button_set_label(button, "Stop");
+ if (!priv->started)
video_start(priv);
- } else {
- gtk_button_set_label(button, "Start");
+ else
video_stop(priv);
- }
}
static void
@@ -327,4 +326,5 @@ gui_app_window_open(GuiAppWindow *win, struct device *device)
gtk_combo_box_text_append_text(priv->resolution_combo_box, buf);
}
gtk_combo_box_set_active(GTK_COMBO_BOX(priv->resolution_combo_box), 0);
+ video_start(priv);
}
diff --git a/main.c b/main.c
index 9ffd6f2..2abeeda 100644
--- a/main.c
+++ b/main.c
@@ -20,88 +20,17 @@
* Web: http://ni.fr.eu.org/
* Email: <nico at ni.fr.eu.org>
*/
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <png.h>
+#include <gtk/gtk.h>
-#include "device.h"
-#include "gui.h"
-#include "options.h"
-#include "utils.h"
-
-void
-cli_read_images(libusb_context *usb, struct device *device, int count,
- const char *out)
-{
- device_start(device);
- for (int i = 0; i < count;) {
- const struct device_image *device_image = device_read(device);
- if (device_image) {
- char *name = NULL;
- if (asprintf(&name, out, i) < 0)
- utils_fatal("can not prepare file name");
- utils_info("write %s", name);
- png_image image;
- memset(&image, 0, sizeof(image));
- image.version = PNG_IMAGE_VERSION;
- image.width = device_image->width;
- image.height = device_image->height;
- image.format = PNG_FORMAT_BGRA;
- int r = png_image_write_to_file(&image, name, 0,
- device_image->pixels, device_image->stride, NULL);
- if (r == 0)
- utils_fatal("can not write image: %s", image.message);
- free(name);
- i++;
- } else {
- libusb_handle_events(usb);
- }
- }
- device_stop(device);
-}
-
-int
-cli_run(struct options *options)
-{
- libusb_context *usb;
- int r = libusb_init(&usb);
- if (r)
- utils_fatal("unable to initialize libusb: %s", libusb_strerror(r));
- struct device *device = device_open(usb);
- if (!device)
- utils_fatal("unable to find device");
- const struct device_info *info = device_get_info(device);
- if (options->exposure_ms > 0.0)
- device_set_exposure(device, options->exposure_ms);
- if (options->gain > 0.0)
- device_set_gain(device, options->gain);
- int width = -1, height = -1;
- for (int i = 0; width == -1 && i < info->resolutions; i++) {
- const struct device_info_resolution *ir = &info->resolution[i];
- if ((options->width == -1 || options->width == ir->width)
- && (options->height == -1 || options->height == ir->height)) {
- width = ir->width;
- height = ir->height;
- }
- }
- if (width == -1)
- utils_fatal("no matching resolution");
- device_set_resolution(device, width, height, 0);
- cli_read_images(usb, device, options->count, options->out);
- device_close(device);
- libusb_exit(usb);
- return EXIT_SUCCESS;
-}
+#include "gui_app.h"
int
main(int argc, char **argv)
{
- struct options options;
- options_parse(argc, argv, &options);
- if (!options.count)
- return gui_run(argc, argv);
- else
- return cli_run(&options);
+ int status;
+ GuiApp *app;
+ app = gui_app_new();
+ status = g_application_run(G_APPLICATION(app), argc, argv);
+ g_object_unref(app);
+ return status;
}
diff --git a/options.c b/options.c
index 388402a..bd9f82b 100644
--- a/options.c
+++ b/options.c
@@ -21,108 +21,75 @@
* Email: <nico at ni.fr.eu.org>
*/
#define _GNU_SOURCE
-#include <errno.h>
-#include <getopt.h>
#include <printf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "cli.h"
#include "options.h"
+#include "utils.h"
-/* Report command line usage, optionally prefixed with an error message. */
-static void
-usage(int status, const char *msg)
+void
+options_add(GApplication *app)
{
- if (msg)
- fprintf(stderr, "%s: %s\n", program_invocation_short_name, msg);
- fprintf(status == EXIT_SUCCESS ? stdout : stderr,
- "usage: %s [options]\n"
- "\n"
- "Microscope camera viewer.\n"
- "\n"
- "optional arguments:\n"
- " -h, --help show this help message and exit\n"
- " -w, --width VALUE image width\n"
- " -e, --exposure MS exposure value\n"
- " -g, --gain VALUE gain value\n"
- " -o, --output FILE output file pattern (default:"
- " out%%02d.png)\n"
- " -n, --count N number of image to take"
- " (default: gui)\n"
- , program_invocation_name);
- exit(status);
+ g_application_set_option_context_summary(app, "Microscope camera viewer");
+ g_application_set_option_context_description(app,
+ "Without options, run the GUI, else switch to batch mode to dump"
+ " image from the camera.");
+ g_application_add_main_option(app, "width", 'w', 0,
+ G_OPTION_ARG_INT, "image width", "VALUE");
+ g_application_add_main_option(app, "exposure", 'e', 0,
+ G_OPTION_ARG_DOUBLE, "exposure value", "MS");
+ g_application_add_main_option(app, "gain", 'g', 0,
+ G_OPTION_ARG_DOUBLE, "gain value", "VALUE");
+ g_application_add_main_option(app, "output", 'o', 0,
+ G_OPTION_ARG_FILENAME,
+ "output file pattern (default: out%02d.png)", "PATTERN");
+ g_application_add_main_option(app, "count", 'n', 0,
+ G_OPTION_ARG_INT, "number of image to take", "N");
}
-void
-options_parse(int argc, char **argv, struct options *options)
+gint
+options_handle(GApplication *app, GVariantDict *options_dict)
{
- options->width = -1;
- options->height = -1;
- options->exposure_ms = -1.0;
- options->gain = -1.0;
- options->count = 0;
- options->out = NULL;
- char *tail;
- while (1) {
- static struct option long_options[] = {
- { "help", no_argument, 0, 'h' },
- { "width", required_argument, 0, 'w' },
- { "exposure", required_argument, 0, 'e' },
- { "gain", required_argument, 0, 'g' },
- { "output", required_argument, 0, 'o' },
- { "count", required_argument, 0, 'n' },
- { NULL },
- };
- int option_index = 0;
- int c = getopt_long(argc, argv, "hw:e:g:o:n:", long_options,
- &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 'h':
- usage(EXIT_SUCCESS, NULL);
- break;
- case 'w':
- errno = 0;
- options->width = strtol(optarg, &tail, 10);
- if (*tail != '\0' || errno || options->width < 1)
- usage(EXIT_FAILURE, "bad width value");
- break;
- case 'e':
- errno = 0;
- options->exposure_ms = strtod(optarg, &tail);
- if (*tail != '\0' || errno || options->exposure_ms < 1)
- usage(EXIT_FAILURE, "bad exposure value");
- break;
- case 'g':
- errno = 0;
- options->gain = strtod(optarg, &tail);
- if (*tail != '\0' || errno || options->gain <= 0.0)
- usage(EXIT_FAILURE, "bad gain value");
- break;
- case 'o':
- options->out = optarg;
- break;
- case 'n':
- errno = 0;
- options->count = strtoul(optarg, &tail, 10);
- if (*tail != '\0' || errno)
- usage(EXIT_FAILURE, "bad count value");
- break;
- case '?':
- usage(EXIT_FAILURE, NULL);
- break;
- default:
- abort();
- }
+ struct options options;
+ options.width = -1;
+ options.height = -1;
+ options.exposure_ms = -1.0;
+ options.gain = -1.0;
+ options.count = 1;
+ options.out = NULL;
+ bool option_set = false;
+ if (g_variant_dict_lookup(options_dict, "width", "i", &options.width)) {
+ option_set = true;
+ if (options.width <= 0)
+ utils_fatal("invalid width");
+ }
+ if (g_variant_dict_lookup(options_dict, "exposure", "d",
+ &options.exposure_ms)) {
+ option_set = true;
+ if (options.exposure_ms < 1.0)
+ utils_fatal("invalid exposure");
+ }
+ if (g_variant_dict_lookup(options_dict, "gain", "d", &options.gain)) {
+ option_set = true;
+ if (options.gain <= 0.0)
+ utils_fatal("invalid gain");
+ }
+ if (g_variant_dict_lookup(options_dict, "count", "i", &options.count)) {
+ option_set = true;
+ if (options.count <= 0)
+ utils_fatal("invalid count");
+ }
+ if (g_variant_dict_lookup(options_dict, "out", "^&ay", &options.out)) {
+ option_set = true;
+ int argtypes[1];
+ int formats = parse_printf_format(options.out, 1, argtypes);
+ if (formats != 1 || argtypes[0] != PA_INT)
+ utils_fatal("bad file pattern, use one %%d");
+ } else {
+ options.out = "out%02d.png";
}
- if (optind < argc)
- usage(EXIT_FAILURE, "too many arguments");
- if (!options->out)
- options->out = "out%02d.png";
- int argtypes[1];
- int formats = parse_printf_format(options->out, 1, argtypes);
- if (formats != 1 || argtypes[0] != PA_INT)
- usage(EXIT_FAILURE, "bad file pattern, use one %d");
+ if (option_set)
+ return cli_run(&options);
+ else
+ return -1;
}
diff --git a/options.h b/options.h
index 3cc0681..86741cf 100644
--- a/options.h
+++ b/options.h
@@ -23,6 +23,7 @@
* Email: <nico at ni.fr.eu.org>
*/
#include <stdbool.h>
+#include <gtk/gtk.h>
/* Runtime options. */
struct options {
@@ -34,16 +35,19 @@ struct options {
double exposure_ms;
/* Digital gain after image acquisition, -1.0 for default. */
double gain;
- /* When zero, run interactive mode, else number of frame to dump. */
+ /* Number of frame to dump. */
int count;
- /* Output file name or pattern, only used in dump mode. This should
- * include a printf like pattern (%d) used to name the files. Only used in
- * dump mode. */
+ /* Output file name or pattern. This should include a printf like pattern
+ * (%d) used to name the files. */
const char *out;
};
-/* Parse command line options and fill provided options structure. */
+/* Add options to application. */
void
-options_parse(int argc, char **argv, struct options *options);
+options_add(GApplication *app);
+
+/* Handle options. */
+gint
+options_handle(GApplication *app, GVariantDict *options_dict);
#endif /* options_h */