Hey all,

I'm working on a gphoto2 external.

I've gotten quite far, except now when I set a config option in the
camera PD gets a SIGHUP and the watchdog starts. I think this is due to
libgphoto doing some stuff in the background and messing with PD's
scheduler.

Once this call is made:

gp_ret = gp_camera_set_config (gphoto2->camera, config, NULL);

then no further lines are read, so I'm guessing PD bails before the
function returns.

This is simply a control object, it need not provide any sync with
audio/gem, just needs to send the messages (via libusb) in a reasonable
amount of time.

Anyone have a very simply pthreads example in a PD external?

I've attached the current state of my code for reference, in case
someone has a better idea.

Thanks,
B. Bogart
/* Gphoto2 PD External */
/* Copyright Ben Bogart, 2009 */
/* This program is distributed under the params of the GNU Public License */

///////////////////////////////////////////////////////////////////////////////////
/* This file is part of the Gphoto2 PD External.                                 */
/*                                                                               */
/* Gphoto2 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 Gphoto2 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 <gphoto2/gphoto2-camera.h>

t_class *gphoto2_class;

typedef struct gphoto2_struct {
	t_object x_obj;
	t_outlet *outlet;

	Camera *camera;

	int connected;


} gphoto2_struct;

static void getConfig(gphoto2_struct *gphoto2, t_symbol *s) {
	if (gphoto2->connected) {
		int gp_ret;
		const char *textVal;
		const int *toggleVal;
		CameraWidget *config = NULL;
		CameraWidget *child = NULL;
		CameraWidgetType type;

		gp_ret = gp_camera_get_config (gphoto2->camera, &config, NULL); // get config from camera
		if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}

		gp_ret = gp_widget_get_child_by_name (config, s->s_name, &child); // get item from config
		if (gp_ret != 0) {error("gphoto2: 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("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));
			error("gphoto2: Invalid config key.");
		} else {
			switch (type) {
				case GP_WIDGET_TOGGLE:
					gp_ret = gp_widget_get_value (child, &toggleVal); //  get widget value
					outlet_float(gphoto2->x_obj.ob_outlet, (int) toggleVal);
					break;
				case GP_WIDGET_TEXT:
					gp_ret = gp_widget_get_value (child, &textVal);
					outlet_symbol(gphoto2->x_obj.ob_outlet, gensym(textVal));
					break;
			}
		}

		/* Free memory
		gp_widget_unref (config);
		gp_widget_unref (child);*/
	} else {
		error("Not connected to camera.");
	}
}

static void setConfig(gphoto2_struct *gphoto2, t_symbol *s, int argc, t_atom *argv) {
	if (gphoto2->connected) {
		int gp_ret, value;
		t_symbol *key;
		CameraWidget *config = NULL;
		CameraWidget *child = NULL;
		CameraWidgetType type;

		key = atom_getsymbol( argv ); // config key

		gp_ret = gp_camera_get_config (gphoto2->camera, &config, NULL); // get config from camera
		if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}

		gp_ret = gp_widget_get_child_by_name (config, key->s_name, &child); // get item from config
		if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}

		gp_ret = gp_widget_get_type (child, &type);
		if (gp_ret != 0) {
			error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));
			error("gphoto2: Invalid config key.");
		} else {
			switch (type) {
				case GP_WIDGET_TOGGLE:
					value = atom_getint( argv+1 );

					gp_ret = gp_widget_set_value (child, &value); //  set widget value
					if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}

					gp_ret = gp_camera_set_config (gphoto2->camera, config, NULL); // set new config
					if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}

					post("value set");
					//outlet_float(gphoto2->x_obj.ob_outlet, (int) toggleVal);
					break;
				case GP_WIDGET_TEXT:
					//gp_ret = gp_widget_get_value (child, &textVal);
					//outlet_symbol(gphoto2->x_obj.ob_outlet, gensym(textVal));
					break;
			}
		}	

		/* Free memory
		gp_widget_unref (config);
		gp_widget_unref (child);*/
	} else {
		error("Not connected to camera.");
	}

}

static void openCam(gphoto2_struct *gphoto2) {
	int gp_ret;

	gphoto2->connected = 0;

	// new camera instance
	gp_ret = gp_camera_new (&(gphoto2->camera));		
	if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}


	// INIT camera (without context)	
	gp_ret = gp_camera_init (gphoto2->camera, NULL); 
	if (gp_ret != 0) {error("gphoto2: ERROR: %s\n", gp_result_as_string(gp_ret));}
	if (gp_ret == 0) {
		post("gphoto2: Connected to camera.");
		gphoto2->connected = 1;
	}
	if (gp_ret == -105) {post("gphoto2: Are you sure the camera is supported, connected and powered on?");}

	
}

static void closeCam(gphoto2_struct *gphoto2) {
	int gp_ret;

	if (gphoto2->connected) {
		gp_ret = gp_camera_unref (gphoto2->camera);		// or gp_camera_exit() ?
		if (gp_ret == 0) {
			post("gphoto2: Disconnected from camera.");
			gphoto2->connected = 0;
		} else {
			error("gphoto2: ERROR %s\n", gp_result_as_string(gp_ret));
		}
	} else {
		error("gphoto2: Not connected to camera.");
	}
}

static void *gphoto2_new(void) {
	gphoto2_struct *gphoto2 = (gphoto2_struct *) pd_new(gphoto2_class);
	outlet_new(&gphoto2->x_obj, NULL);
	
	return (void *)gphoto2;
}

static void gphoto2_release(gphoto2_struct *gphoto2) {
	if (gphoto2->connected) {
		gp_camera_unref(gphoto2->camera);
	} else {	
		error("gphoto2: Not connected to camera.");
	}
}

void gphoto2_setup(void) {
	gphoto2_class = class_new(gensym("gphoto2"), (t_newmethod) gphoto2_new,  (t_method) gphoto2_release, sizeof(gphoto2_struct), 0, CLASS_DEFAULT, 0);
	class_addmethod(gphoto2_class, (t_method) openCam, gensym("open"), 0);
	class_addmethod(gphoto2_class, (t_method) closeCam, gensym("close"), 0);
	class_addmethod(gphoto2_class, (t_method) getConfig, gensym("getconfig"), A_DEFSYMBOL, 0);
	class_addmethod(gphoto2_class, (t_method) setConfig, gensym("setconfig"), A_GIMME, 0);
}

_______________________________________________
Pd-dev mailing list
[email protected]
http://lists.puredata.info/listinfo/pd-dev

Reply via email to