From b6d7291115368ab2381f75abaf3b73d4cc109084 Mon Sep 17 00:00:00 2001 From: "B. Bogart" Date: Fri, 27 Mar 2009 16:50:49 +0000 Subject: Fixed one of the multiple-iteration crashes when capturing images by setting the threads "detatched" attribute. Now it seems that gphoto is causing a similar issue when after 338 iterations the camera is no longer recognized. Will add a method for capturing multiple images in a loop without disconnecting from camera. Fixed the issue with setting ISO (WIDGET_RADIO) values. svn path=/trunk/externals/bbogart/; revision=10911 --- gphoto/README.txt | 1 - gphoto/gphoto-help.pd | 43 ++++---- gphoto/gphoto.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 286 insertions(+), 35 deletions(-) (limited to 'gphoto') diff --git a/gphoto/README.txt b/gphoto/README.txt index 1b8062b..f3628d3 100644 --- a/gphoto/README.txt +++ b/gphoto/README.txt @@ -27,6 +27,5 @@ Put the binary in your extra folder. Put the helpfile in your 5.reference folder. TODO: -* Change listConfig to output a list of configuration names. * Add a getConfigDetail function to get the range, step, etc info on each config name. * Add getFile and getFiles functions for PTP file transfer functionality. diff --git a/gphoto/gphoto-help.pd b/gphoto/gphoto-help.pd index a259d9d..2eacadc 100644 --- a/gphoto/gphoto-help.pd +++ b/gphoto/gphoto-help.pd @@ -1,4 +1,4 @@ -#N canvas 479 0 638 776 10; +#N canvas 479 0 638 746 10; #X msg 83 48 getconfig model; #X msg 142 83 getconfig capture; #X msg 167 116 getconfig zoom; @@ -10,23 +10,32 @@ #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 msg 174 327 configdetail iso; +#X msg 150 354 configdetail zoom; +#X msg 150 384 configdetail capture; #X obj 86 191 gphoto; -#X msg 189 147 getconfig iso; -#X text 281 147 <- does not work.; -#X connect 0 0 14 0; -#X connect 1 0 14 0; -#X connect 2 0 14 0; -#X connect 4 0 14 0; -#X connect 5 0 14 0; -#X connect 6 0 14 0; -#X connect 9 0 14 0; -#X connect 10 0 14 0; -#X connect 11 0 14 0; -#X connect 13 0 14 0; -#X connect 14 0 3 0; -#X connect 14 1 12 0; -#X connect 15 0 14 0; +#X msg 280 113 getconfig iso; +#X msg 18 158 reset; +#X msg 208 154 setconfig iso \$1; +#X symbolatom 320 153 10 0 0 0 - - -; +#X connect 0 0 16 0; +#X connect 1 0 16 0; +#X connect 2 0 16 0; +#X connect 4 0 16 0; +#X connect 5 0 16 0; +#X connect 6 0 16 0; +#X connect 9 0 16 0; +#X connect 10 0 16 0; +#X connect 12 0 16 0; +#X connect 13 0 16 0; +#X connect 14 0 16 0; +#X connect 15 0 16 0; +#X connect 16 0 3 0; +#X connect 16 1 11 0; +#X connect 17 0 16 0; +#X connect 18 0 16 0; +#X connect 19 0 16 0; +#X connect 20 0 19 0; diff --git a/gphoto/gphoto.c b/gphoto/gphoto.c index 73ae822..5eb982a 100644 --- a/gphoto/gphoto.c +++ b/gphoto/gphoto.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,7 @@ typedef struct gphoto_struct { t_object x_obj; t_outlet *doneOutlet; int busy; + pthread_attr_t threadAttr; //thread attributes } gphoto_struct; @@ -44,6 +46,154 @@ typedef struct gphoto_gimme_struct { t_atom *argv; } gphoto_gimme_struct; +void *getConfigDetail(void *threadArgs) { + int gp_ret; + const char *textVal; + const int *toggleVal; + const float rangeVal; + const char *label, *info; + float rangeMax, rangeMin, rangeIncr; + float floatVal; + int intVal, i; + + 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) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} + + // INIT camera (without context) + gp_ret = gp_camera_init (camera, NULL); + if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock();} + if (gp_ret == -105) { + sys_lock(); + error("gphoto: Are you sure the camera is supported, connected and powered on?"); + sys_unlock(); + gp_camera_unref(camera); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + return(NULL); + } + + gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera + if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); 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) { + sys_lock(); + error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); + sys_unlock(); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + gp_camera_unref(camera); + return(NULL); + } + + gp_ret = gp_widget_get_type (child, &type); + if (gp_ret != 0) { + sys_lock; error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); + error("gphoto: Invalid config key."); sys_unlock(); + } else { + switch (type) { + case GP_WIDGET_RADIO: + gp_ret = gp_widget_get_label (child, &label); + sys_lock(); + post("gphoto: Label: %s", label); + post("gphoto: Type: Radio"); + sys_unlock(); + for (i=0; igphoto->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 getConfigDetail +static void wrapGetConfigDetail(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, &gphoto->threadAttr, getConfigDetail, threadArgs); + } else { + error("gphoto: ERROR: Already executing a command, try again later."); + } + + return; +} + // list configuration void *listConfig(void *threadArgs) { int gp_ret, numsections, numchildren, i, j; @@ -60,7 +210,14 @@ void *listConfig(void *threadArgs) { // 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) {sys_lock(); post("gphoto: Are you sure the camera is supported, connected and powered on?"); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret == -105) { + sys_lock(); + error("gphoto: Are you sure the camera is supported, connected and powered on?"); + sys_unlock(); + gp_camera_unref(camera); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + return(NULL); + } gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} @@ -117,7 +274,7 @@ static void wrapListConfig(gphoto_struct *gphoto) { gphoto->busy = 1; // Create thread - ret = pthread_create( &thread1, NULL, listConfig, threadArgs); + ret = pthread_create( &thread1, &gphoto->threadAttr, listConfig, threadArgs); } else { error("gphoto: ERROR: Already executing a command, try again later."); } @@ -147,13 +304,27 @@ void *getConfig(void *threadArgs) { // INIT camera (without context) gp_ret = gp_camera_init (camera, NULL); if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock();} - if (gp_ret == -105) {sys_lock(); post("gphoto: Are you sure the camera is supported, connected and powered on?"); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret == -105) { + sys_lock(); + error("gphoto: Are you sure the camera is supported, connected and powered on?"); + sys_unlock(); + gp_camera_unref(camera); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + return(NULL); + } gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); 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) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret != 0) { + sys_lock(); + error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); + sys_unlock(); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + gp_camera_unref(camera); + return(NULL); + } gp_ret = gp_widget_get_type (child, &type); if (gp_ret != 0) { @@ -161,18 +332,30 @@ void *getConfig(void *threadArgs) { error("gphoto: Invalid config key."); sys_unlock(); } else { switch (type) { + case GP_WIDGET_RADIO: + gp_ret = gp_widget_get_value(child, &textVal); + sys_lock(); + outlet_symbol(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, gensym(textVal)); + sys_unlock(); + break; case GP_WIDGET_TOGGLE: gp_ret = gp_widget_get_value (child, &toggleVal); // get widget value + sys_lock(); outlet_float(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, (int) toggleVal); + sys_unlock(); break; case GP_WIDGET_TEXT: gp_ret = gp_widget_get_value (child, &textVal); + sys_lock(); outlet_symbol(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, gensym(textVal)); + sys_lock(); 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));} + sys_lock(); outlet_float(((gphoto_gimme_struct *)threadArgs)->gphoto->x_obj.ob_outlet, rangeVal); + sys_lock(); break; } } @@ -212,7 +395,7 @@ static void wrapGetConfig(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom * gphoto->busy = 1; // Create thread - ret = pthread_create( &thread1, NULL, getConfig, threadArgs); + ret = pthread_create( &thread1, &gphoto->threadAttr, getConfig, threadArgs); } else { error("gphoto: ERROR: Already executing a command, try again later."); } @@ -223,7 +406,8 @@ static void wrapGetConfig(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom * void *setConfig(void *threadArgs) { int gp_ret, intValue; float floatValue; - t_symbol *key; + t_symbol *key, *textValue; + char charkey[MAXPDSTRING]; Camera *camera; CameraWidget *config = NULL; CameraWidget *child = NULL; @@ -239,13 +423,27 @@ void *setConfig(void *threadArgs) { // INIT camera (without context) gp_ret = gp_camera_init (camera, NULL); if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock();} - if (gp_ret == -105) {sys_lock(); error("gphoto: Are you sure the camera is supported, connected and powered on?"); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret == -105) { + sys_lock(); + error("gphoto: Are you sure the camera is supported, connected and powered on?"); + sys_unlock(); + gp_camera_unref(camera); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + return(NULL); + } gp_ret = gp_camera_get_config (camera, &config, NULL); // get config from camera if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); 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) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret != 0) { + sys_lock(); + error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); + sys_unlock(); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + gp_camera_unref(camera); + return(NULL); + } gp_ret = gp_widget_get_type (child, &type); if (gp_ret != 0) { @@ -253,6 +451,21 @@ void *setConfig(void *threadArgs) { error("gphoto: Invalid config key."); sys_unlock(); } else { switch (type) { + // same method as TOGGLE type + case GP_WIDGET_RADIO: + sys_lock(); + textValue = atom_getsymbol( ((gphoto_gimme_struct *)threadArgs)->argv+1 ); + post("argument: %s", textValue->s_name); + strcpy(charkey,(char *)textValue->s_name); + post("charkey: %s", charkey); + sys_unlock(); + + gp_ret = gp_widget_set_value (child, &charkey); // set widget value + if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); } + + gp_ret = gp_camera_set_config (camera, config, NULL); // set new config + if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); } + break; case GP_WIDGET_TOGGLE: sys_lock(); intValue = atom_getint( ((gphoto_gimme_struct *)threadArgs)->argv+1 ); @@ -316,7 +529,7 @@ static void wrapSetConfig(gphoto_struct *gphoto, t_symbol *s, int argc, t_atom * gphoto->busy = 1; // Create thread - ret = pthread_create( &thread1, NULL, setConfig, threadArgs); + ret = pthread_create( &thread1, &gphoto->threadAttr, setConfig, threadArgs); } else { error("gphoto: ERROR: Already executing a command, try again later."); } @@ -341,7 +554,14 @@ void *captureImage(void *threadArgs) { // INIT camera (without context) gp_ret = gp_camera_init (camera, NULL); if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); } - if (gp_ret == -105) {sys_lock(); post("gphoto: Are you sure the camera is supported, connected and powered on?"); sys_unlock(); gp_camera_unref(camera); return(NULL);} + if (gp_ret == -105) { + sys_lock(); + error("gphoto: Are you sure the camera is supported, connected and powered on?"); + sys_unlock(); + gp_camera_unref(camera); + ((gphoto_gimme_struct *)threadArgs)->gphoto->busy = 0; // no longer busy if we got an error. + return(NULL); + } gp_ret = gp_camera_capture(camera, GP_CAPTURE_IMAGE, &camera_file_path, NULL); if (gp_ret != 0) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} @@ -354,22 +574,23 @@ void *captureImage(void *threadArgs) { 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) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); 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) {sys_lock(); error("gphoto: ERROR: %s\n", gp_result_as_string(gp_ret)); sys_unlock(); gp_camera_unref(camera); return(NULL);} // Free memory - gp_camera_unref(camera); + gp_camera_free(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); + pthread_exit(NULL); + //return(NULL); // needed? } // Wrap captureImage @@ -378,6 +599,8 @@ static void wrapCaptureImage(gphoto_struct *gphoto, t_symbol *s, int argc, t_ato int ret; pthread_t thread1; +post("busy state: %d", gphoto->busy); + if (!gphoto->busy) { // instance of structure @@ -393,12 +616,20 @@ static void wrapCaptureImage(gphoto_struct *gphoto, t_symbol *s, int argc, t_ato gphoto->busy = 1; // Create thread - ret = pthread_create( &thread1, NULL, captureImage, threadArgs); + ret = pthread_create( &thread1, &gphoto->threadAttr, captureImage, threadArgs); + post("pthread return: %d", ret); } else { error("gphoto: ERROR: Already executing a command, try again later."); } } +// Reset internal state to accept new commands. +static void reset(gphoto_struct *gphoto) { + gphoto->busy = 0; + + return; +} + static void *gphoto_new(void) { gphoto_struct *gphoto = (gphoto_struct *) pd_new(gphoto_class); outlet_new(&gphoto->x_obj, NULL); @@ -406,15 +637,27 @@ static void *gphoto_new(void) { // Initially the external is not "busy" gphoto->busy = 0; + + // When we create a thread, make sure it is deatched. + pthread_attr_init(&gphoto->threadAttr); + pthread_attr_setdetachstate(&gphoto->threadAttr, PTHREAD_CREATE_DETACHED); return (void *)gphoto; } +static void *gphoto_destroy(gphoto_struct *gphoto) { + pthread_attr_destroy(&gphoto->threadAttr); + + return(NULL); +} + void gphoto_setup(void) { - gphoto_class = class_new(gensym("gphoto"), (t_newmethod) gphoto_new, 0, sizeof(gphoto_struct), 0, CLASS_DEFAULT, 0); + gphoto_class = class_new(gensym("gphoto"), (t_newmethod) gphoto_new, (t_method) gphoto_destroy, 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) wrapGetConfigDetail, gensym("configdetail"), A_GIMME, 0); + class_addmethod(gphoto_class, (t_method) wrapCaptureImage, gensym("captureimage"), 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); + class_addmethod(gphoto_class, (t_method) reset, gensym("reset"), 0); } -- cgit v1.2.1