aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Bogart <bbogart@users.sourceforge.net>2009-03-19 20:33:40 +0000
committerB. Bogart <bbogart@users.sourceforge.net>2009-03-19 20:33:40 +0000
commita7b850566e6bf04e29e38698aa43f7d5b4acf60c (patch)
tree62c5f7a6089ff2b55a94d5f1cb56161b0aad9e53
parent8981c3e4bd8be9eee73692f81fcc76bb960f096b (diff)
First functional version of gphoto PD external.
svn path=/trunk/externals/bbogart/; revision=10878
-rw-r--r--gphoto/gphoto-help.pd31
-rw-r--r--gphoto/gphoto.c423
-rw-r--r--gphoto/makefile25
3 files changed, 479 insertions, 0 deletions
diff --git a/gphoto/gphoto-help.pd b/gphoto/gphoto-help.pd
new file mode 100644
index 0000000..79dff2c
--- /dev/null
+++ b/gphoto/gphoto-help.pd
@@ -0,0 +1,31 @@
+#N canvas 0 0 638 970 10;
+#X msg 83 48 getconfig model;
+#X msg 142 83 getconfig capture;
+#X msg 167 116 getconfig zoom;
+#X obj 79 221 print;
+#X msg 59 21 listconfig;
+#X msg 189 147 setconfig capture 0;
+#X msg 209 183 setconfig capture 1;
+#X msg 205 218 setconfig capture 2;
+#X text 336 182 cap on?;
+#X text 334 217 cap off?;
+#X msg 196 254 setconfig zoom 129;
+#X msg 177 277 setconfig zoom 0;
+#X msg 18 158 debug model;
+#X obj 133 231 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X msg 266 33 capture test2.jpg;
+#X obj 86 191 gphoto;
+#X connect 0 0 15 0;
+#X connect 1 0 15 0;
+#X connect 2 0 15 0;
+#X connect 4 0 15 0;
+#X connect 5 0 15 0;
+#X connect 6 0 15 0;
+#X connect 7 0 15 0;
+#X connect 10 0 15 0;
+#X connect 11 0 15 0;
+#X connect 12 0 15 0;
+#X connect 14 0 15 0;
+#X connect 15 0 3 0;
+#X connect 15 1 13 0;
diff --git a/gphoto/gphoto.c b/gphoto/gphoto.c
new file mode 100644
index 0000000..dab9f80
--- /dev/null
+++ b/gphoto/gphoto.c
@@ -0,0 +1,423 @@
+/* Gphoto PD External */
+/* Copyright Ben Bogart, 2009 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of the Gphoto PD External. */
+/* */
+/* Gphoto PD External 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. */
+/* */
+/* The Gphoto PD External is distributed in the hope that they 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 the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <m_pd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <gphoto2/gphoto2-camera.h>
+
+t_class *gphoto_class;
+
+typedef struct gphoto_struct {
+ t_object x_obj;
+ t_outlet *doneOutlet;
+ int busy;
+
+} gphoto_struct;
+
+// Struct to store A_GIMME data passed to thread.
+typedef struct gphoto_gimme_struct {
+ gphoto_struct *gphoto;
+ t_symbol *s;
+ int argc;
+ t_atom *argv;
+} gphoto_gimme_struct;
+
+// list configuration
+void *listConfig(void *threadArgs) {
+ int gp_ret, numsections, numchildren, i, j;
+ Camera *camera;
+ CameraWidget *config = NULL;
+ CameraWidget *child = NULL;
+ CameraWidget *child2 = NULL;
+ CameraWidgetType type;
+ char *childName;
+
+ gp_ret = gp_camera_new (&camera);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ // INIT camera (without context)
+ gp_ret = gp_camera_init (camera, NULL);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ if (gp_ret == -105) {post("gphoto: Are you sure the camera is supported, connected and powered on?"); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ numsections = gp_widget_count_children(config);
+ for (i=0; i<numsections; i++) {
+ gp_widget_get_child (config, i, &child);
+ gp_widget_get_type (child, &type);
+
+ if (type == GP_WIDGET_SECTION) {
+ //post("gphoto: Config Section: %s\n", childName);
+ numchildren = gp_widget_count_children(child);
+ for (j=0; j<numchildren; j++) {
+ gp_widget_get_child (child, j, &child2);
+ gp_widget_get_name (child2, &childName);
+ gp_widget_get_type (child2, &type);
+
+ sys_lock();
+ outlet_symbol(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, gensym(childName));
+ sys_unlock();
+
+ //post("gphoto: Config Child: %s\n", childName); // send through outlet?
+ }
+ }
+ }
+
+ // Free memory (not child?)
+ gp_widget_unref (config);
+ gp_camera_unref (camera);
+
+ // We are done and other messsages can now be sent.
+ ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0;
+
+ return(NULL);
+}
+
+// Wrap listConfig
+static void wrapListConfig(gphoto_struct *gphoto) {
+ int ret;
+ pthread_t thread1;
+
+ if (!gphoto->busy) {
+
+ // instance of structure
+ gphoto_gimme_struct *threadArgs = (gphoto_gimme_struct *)malloc(sizeof(gphoto_gimme_struct));
+
+ // packaging arguments into structure
+ threadArgs->gphoto = gphoto;
+
+ // We're busy
+ gphoto->busy = 1;
+
+ // Create thread
+ ret = pthread_create( &thread1, NULL, listConfig, threadArgs);
+ } else {
+ error("gphoto: ERROR: Already executing a command, try again later.");
+ }
+
+ return;
+}
+
+void *getConfig(void *threadArgs) {
+ int gp_ret;
+ const char *textVal;
+ const int *toggleVal;
+ const float rangeVal;
+ float value;
+
+ t_symbol *key;
+
+ Camera *camera;
+ CameraWidget *config = NULL;
+ CameraWidget *child = NULL;
+ CameraWidgetType type;
+
+ key = atom_getsymbol( ((gphoto_gimme_struct *)threadArgs)->argv ); // config key
+
+ gp_ret = gp_camera_new (&camera);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ // INIT camera (without context)
+ gp_ret = gp_camera_init (camera, NULL);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ if (gp_ret == -105) {post("gphoto: Are you sure the camera is supported, connected and powered on?"); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_widget_get_child_by_name (config, key->s_name, &child); // get item from config
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+
+/* post("types:");
+ post("GP_WIDGET_TOGGLE: %d", GP_WIDGET_TOGGLE);
+ post("GP_WIDGET_TEXT: %d", GP_WIDGET_TEXT);
+ post("GP_WIDGET_RANGE: %d", GP_WIDGET_RANGE);
+ post("GP_WIDGET_RADIO: %d", GP_WIDGET_RADIO);
+ post("GP_WIDGET_MENU: %d", GP_WIDGET_MENU);
+ post("GP_WIDGET_BUTTON: %d", GP_WIDGET_BUTTON);
+ post("GP_WIDGET_DATE: %d", GP_WIDGET_DATE);
+ post("GP_WIDGET_WINDOW: %d", GP_WIDGET_WINDOW);
+ post("GP_WIDGET_SECTION: %d", GP_WIDGET_SECTION);
+*/
+
+ gp_ret = gp_widget_get_type (child, &type);
+ if (gp_ret != 0) {
+ error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));
+ error("gphoto: Invalid config key.");
+ } else {
+ switch (type) {
+ case GP_WIDGET_TOGGLE:
+ gp_ret = gp_widget_get_value (child, &toggleVal); // get widget value
+ outlet_float(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, (int) toggleVal);
+ break;
+ case GP_WIDGET_TEXT:
+ gp_ret = gp_widget_get_value (child, &textVal);
+ outlet_symbol(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, gensym(textVal));
+ break;
+ case GP_WIDGET_RANGE:
+ gp_ret = gp_widget_get_value (child, &rangeVal);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ outlet_float(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, rangeVal);
+ break;
+ }
+ }
+
+ // Free memory (not child?)
+ gp_widget_unref (config);
+ gp_camera_unref (camera);
+
+ // We are done and other messsages can now be sent.
+ ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0;
+
+ // Send bang out 2nd outlet when operation is done.
+ sys_lock();
+ outlet_bang(((gphoto_gimme_struct *)threadArgs)->gphoto->doneOutlet);
+ sys_unlock();
+
+ return(NULL);
+}
+
+// Wrap getConfig
+static void wrapGetConfig(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom *argv) {
+ int ret;
+ pthread_t thread1;
+
+ if (!gphoto->busy) {
+
+ // instance of structure
+ gphoto_gimme_struct *threadArgs = (gphoto_gimme_struct *)malloc(sizeof(gphoto_gimme_struct));
+
+ // packaging arguments into structure
+ threadArgs->gphoto = gphoto;
+ threadArgs->s = s;
+ threadArgs->argc = argc;
+ threadArgs->argv = argv;
+
+ // We're busy
+ gphoto->busy = 1;
+
+ // Create thread
+ ret = pthread_create( &thread1, NULL, getConfig, threadArgs);
+ } else {
+ error("gphoto: ERROR: Already executing a command, try again later.");
+ }
+
+ return;
+}
+
+void *setConfig(void *threadArgs) {
+ int gp_ret, intValue;
+ float floatValue;
+ t_symbol *key;
+ Camera *camera;
+ CameraWidget *config = NULL;
+ CameraWidget *child = NULL;
+ CameraWidgetType type;
+
+ sys_lock();
+ key = atom_getsymbol( ((gphoto_gimme_struct *)threadArgs)->argv ); // config key
+ sys_unlock();
+
+ gp_ret = gp_camera_new (&camera);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+
+ // INIT camera (without context)
+ gp_ret = gp_camera_init (camera, NULL);
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ if (gp_ret == -105) {error("gphoto: Are you sure the camera is supported, connected and powered on?"); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_widget_get_child_by_name (config, key->s_name, &child); // get item from config
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_widget_get_type (child, &type);
+ if (gp_ret != 0) {
+ error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));
+ error("gphoto: Invalid config key.");
+ } else {
+ switch (type) {
+ case GP_WIDGET_TOGGLE:
+ intValue = atom_getint( ((gphoto_gimme_struct *)threadArgs)->argv+1 );
+
+ gp_ret = gp_widget_set_value (child, &intValue); // set widget value
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+
+ gp_ret = gp_camera_set_config (camera, config, NULL); // set new config
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ break;
+
+ case GP_WIDGET_RANGE:
+ floatValue = atom_getfloat( ((gphoto_gimme_struct *)threadArgs)->argv+1 );
+
+ gp_ret = gp_widget_set_value (child, &floatValue); // set widget value
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+
+ gp_ret = gp_camera_set_config (camera, config, NULL); // set new config
+ if (gp_ret != 0) {error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+
+ break;
+ }
+ }
+
+ // Free memory
+ gp_widget_unref (config);
+ gp_camera_unref(camera);
+
+ // We are done and other messsages can now be sent.
+ ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0;
+
+ // Send bang out 2nd outlet when operation is done.
+ sys_lock();
+ outlet_bang(((gphoto_gimme_struct *)threadArgs)->gphoto->doneOutlet);
+ sys_unlock();
+
+ return(NULL);
+}
+
+// Wrap setConfig
+// TODO is there a way to have one wrapper for all funcs?
+static void wrapSetConfig(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom *argv) {
+ int ret;
+ pthread_t thread1;
+
+ if (!gphoto->busy) {
+
+ // instance of structure
+ gphoto_gimme_struct *threadArgs = (gphoto_gimme_struct *)malloc(sizeof(gphoto_gimme_struct));
+
+ // packaging arguments into structure
+ threadArgs->gphoto = gphoto;
+ threadArgs->s = s;
+ threadArgs->argc = argc;
+ threadArgs->argv = argv;
+
+ // We're busy
+ gphoto->busy = 1;
+
+ // Create thread
+ ret = pthread_create( &thread1, NULL, setConfig, threadArgs);
+ } else {
+ error("gphoto: ERROR: Already executing a command, try again later.");
+ }
+
+ return;
+}
+
+void *captureImage(void *threadArgs) {
+ int gp_ret, fd;
+ Camera *camera;
+ CameraFile *camerafile;
+ CameraFilePath camera_file_path;
+ t_symbol *filename;
+
+ filename = atom_getsymbol( ((gphoto_gimme_struct *)threadArgs)->argv ); // destination filename
+
+ gp_ret = gp_camera_new (&camera);
+ if (gp_ret != 0) {error("1gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ // INIT camera (without context)
+ gp_ret = gp_camera_init (camera, NULL);
+ if (gp_ret != 0) {error("2gphoto: ERROR: %s\n", gp_result_as_string(gp_ret));}
+ if (gp_ret == -105) {post("gphoto: Are you sure the camera is supported, connected and powered on?"); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, NULL);
+ if (gp_ret != 0) {error("3gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ fd = open( filename->s_name, O_CREAT | O_WRONLY, 0644); // create file descriptor
+
+ gp_ret = gp_file_new_from_fd(&camerafile, fd); // create gphoto file from descriptor
+ if (gp_ret != 0) {error("4gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_file_get(camera, camera_file_path.folder, camera_file_path.name,
+ GP_FILE_TYPE_NORMAL, camerafile, NULL); // get file from camera
+ if (gp_ret != 0) {error("5gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ gp_ret = gp_camera_file_delete(camera, camera_file_path.folder, camera_file_path.name, NULL);
+ if (gp_ret != 0) {error("6gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); gp_camera_unref(camera); return(NULL);}
+
+ // Free memory
+ gp_camera_unref(camera);
+
+ // We are done and other messsages can now be sent.
+ ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0;
+
+ // Send bang out 2nd outlet when operation is done.
+ sys_lock();
+ outlet_bang(((gphoto_gimme_struct *)threadArgs)->gphoto->doneOutlet);
+ sys_unlock();
+
+ return(NULL);
+}
+
+// Wrap captureImage
+// TODO is there a way to have one wrapper for all funcs?
+static void wrapCaptureImage(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom *argv) {
+ int ret;
+ pthread_t thread1;
+
+ if (!gphoto->busy) {
+
+ // instance of structure
+ gphoto_gimme_struct *threadArgs = (gphoto_gimme_struct *)malloc(sizeof(gphoto_gimme_struct));
+
+ // packaging arguments into structure
+ threadArgs->gphoto = gphoto;
+ threadArgs->s = s;
+ threadArgs->argc = argc;
+ threadArgs->argv = argv;
+
+ // We're busy
+ gphoto->busy = 1;
+
+ // Create thread
+ ret = pthread_create( &thread1, NULL, captureImage, threadArgs);
+ } else {
+ error("gphoto: ERROR: Already executing a command, try again later.");
+ }
+}
+
+static void *gphoto_new(void) {
+ gphoto_struct *gphoto = (gphoto_struct *) pd_new(gphoto_class);
+ outlet_new(&gphoto->x_obj, NULL);
+ gphoto->doneOutlet = outlet_new(&gphoto->x_obj, &s_bang);
+
+ // Initially the external is not "busy"
+ gphoto->busy = 0;
+
+ return (void *)gphoto;
+}
+
+void gphoto_setup(void) {
+ gphoto_class = class_new(gensym("gphoto"), (t_newmethod) gphoto_new, 0, sizeof(gphoto_struct), 0, CLASS_DEFAULT, 0);
+ class_addmethod(gphoto_class, (t_method) wrapGetConfig, gensym("getconfig"), A_GIMME, 0);
+ class_addmethod(gphoto_class, (t_method) wrapCaptureImage, gensym("capture"), A_GIMME, 0);
+ class_addmethod(gphoto_class, (t_method) wrapSetConfig, gensym("setconfig"), A_GIMME, 0);
+ class_addmethod(gphoto_class, (t_method) wrapListConfig, gensym("listconfig"), 0);
+}
+
diff --git a/gphoto/makefile b/gphoto/makefile
new file mode 100644
index 0000000..f87381e
--- /dev/null
+++ b/gphoto/makefile
@@ -0,0 +1,25 @@
+current:
+ echo make pd_linux
+
+clean: ; rm -f *.pd_linux *.o
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: gphoto.pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch \
+ -lgphoto2 -lpthread
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c -ggdb
+ ld -shared -o $*.pd_linux $*.o -lc -lm -lgphoto2
+ strip --strip-unneeded $*.pd_linux
+ rm $*.o
+
+