123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- /* Copyright (C) 2015 Timo Dritschler <timo.dritschler@kit.edu>
- (Karlsruhe Institute of Technology)
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by the
- Free Software Foundation; either version 2.1 of the License, or (at your
- option) any later version.
- This library 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 Lesser General Public License for more
- details.
- You should have received a copy of the GNU Lesser General Public License along
- with this library; if not, write to the Free Software Foundation, Inc., 51
- Franklin St, Fifth Floor, Boston, MA 02110, USA
- */
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include "uca-kiro-camera.h"
- #include "uca/uca-plugin-manager.h"
- typedef struct {
- gboolean exit_flag;
- UcaCamera *cam;
- KiroMessenger *messenger;
- gulong peer_rank;
- gulong *signal_handlers;
- GParamSpec **properties;
- guint n_properties;
- KiroRequest *peer_update_request;
- } KiroCsData;
- static gulong
- pspec_size (GType type)
- {
- gulong ret = 0;
- switch (type) {
- case G_TYPE_BOOLEAN:
- ret = sizeof (GParamSpecBoolean);
- break;
- case G_TYPE_CHAR:
- ret = sizeof (GParamSpecChar);
- break;
- case G_TYPE_INT:
- ret = sizeof (GParamSpecInt);
- break;
- case G_TYPE_UINT:
- ret = sizeof (GParamSpecUInt);
- break;
- case G_TYPE_LONG:
- ret = sizeof (GParamSpecLong);
- break;
- case G_TYPE_ULONG:
- ret = sizeof (GParamSpecULong);
- break;
- case G_TYPE_INT64:
- ret = sizeof (GParamSpecInt64);
- break;
- case G_TYPE_UINT64:
- ret = sizeof (GParamSpecUInt64);
- break;
- case G_TYPE_FLOAT:
- ret = sizeof (GParamSpecFloat);
- break;
- case G_TYPE_DOUBLE:
- ret = sizeof (GParamSpecDouble);
- break;
- default:
- ret = sizeof (GParamSpec);
- }
- return ret;
- }
- static gulong
- gtype_size (GType type)
- {
- gulong ret = 0;
- switch (type) {
- case G_TYPE_BOOLEAN:
- ret = sizeof (gboolean);
- break;
- case G_TYPE_CHAR:
- ret = sizeof (gchar);
- break;
- case G_TYPE_INT:
- ret = sizeof (gint);
- break;
- case G_TYPE_ENUM:
- ret = sizeof (gint);
- break;
- case G_TYPE_UINT:
- ret = sizeof (guint);
- break;
- case G_TYPE_LONG:
- ret = sizeof (glong);
- break;
- case G_TYPE_ULONG:
- ret = sizeof (gulong);
- break;
- case G_TYPE_INT64:
- ret = sizeof (gint64);
- break;
- case G_TYPE_UINT64:
- ret = sizeof (guint64);
- break;
- case G_TYPE_FLOAT:
- ret = sizeof (gfloat);
- break;
- case G_TYPE_DOUBLE:
- ret = sizeof (gdouble);
- break;
- default:
- //ERROR
- break;
- }
- return ret;
- }
- static void
- print_cam_name (gchar *name, gpointer unused)
- {
- (void) unused;
- g_print ("-- %s\n", name);
- }
- static void
- send_clear_callback (KiroRequest *request, gpointer data)
- {
- (void) data;
- if (request->status != KIRO_MESSAGE_SEND_SUCCESS)
- g_error ("OH SHIT!");
- else
- g_debug ("Peer informed successfully");
- if (request->message->payload)
- g_free (request->message->payload);
- g_free (request->message);
- g_free (request);
- }
- static void
- peer_inform_update (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
- {
- g_print ("Updated %s.\n", pspec->name);
- gpointer buff = g_malloc0 (sizeof (guint64));
- g_object_get (G_OBJECT (cam),
- pspec->name, buff,
- NULL);
- KiroMessage *message = g_malloc0 (sizeof (KiroMessage));
- message->msg = KIROCS_UPDATE;
- message->size = sizeof (PropUpdateScalar);
- message->payload = g_malloc0 (message->size);
- PropUpdateScalar *update = message->payload;
- update->base.id = property_id_from_name (pspec->name, data->n_properties, data->properties);
- update->base.size = 1;
- update->base.scalar = TRUE;
- memcpy (&update->prop_raw, buff, sizeof (guint64));
- GError *error = NULL;
- kiro_messenger_send_blocking (data->messenger, message, data->peer_rank, &error);
- if (error) {
- g_free (message);
- g_error ("Oh shit! (%s)", error->message);
- g_error_free (error);
- }
- }
- static gulong
- setup_signal_handler (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
- {
- GString *signal_name = g_string_new ("notify::");
- signal_name = g_string_append (signal_name, pspec->name);
- gulong ret = g_signal_connect (cam, signal_name->str, G_CALLBACK (peer_inform_update), data);
- g_string_free (signal_name, TRUE);
- return ret;
- }
- static KiroContinueFlag
- connect_callback (gulong rank, gulong *storage)
- {
- *storage = rank;
- return KIRO_CALLBACK_REMOVE;
- }
- // MAIN HANDLER //
- static void
- receive_callback (KiroRequest *request, KiroCsData *data)
- {
- if (request->message->msg == KIROCS_EXIT) {
- g_message ("Peer requested shut down...");
- data->exit_flag = TRUE;
- }
- if (request->message->msg == KIROCS_UPDATE) {
- PropUpdate *update = (PropUpdate *)request->message->payload;
- g_signal_handler_block (data->cam, data->signal_handlers[update->id]);
- //Don't forget the -1, because the index starts at 0, but property IDs
- //start at 1...
- const gchar *name = data->properties[update->id -1]->name;
- g_debug ("Unpacking '%s' with ID %u\n", name, update->id);
- if (update->scalar == TRUE) {
- PropUpdateScalar *scalar_update = (PropUpdateScalar *)update;
- GValue tmp = G_VALUE_INIT;
- g_value_init (&tmp, data->properties[update->id -1]->value_type);
- g_value_set_from_raw_data (&tmp, &scalar_update->prop_raw);
- g_object_set_property (G_OBJECT (data->cam), name, &tmp);
- }
- g_signal_handler_unblock (data->cam, data->signal_handlers[update->id]);
- g_debug ("Done.");
- }
- if (request->message->msg == KIROCS_FETCH) {
- gchar* property_name = (gchar *)request->message->payload;
- KiroRequest *request = g_malloc0 (sizeof (KiroRequest));
- request->peer_rank = data->peer_rank;
- request->callback = send_clear_callback;
- request->user_data = NULL;
- request->message = g_malloc0 (sizeof (KiroMessage));
- request->message->msg = KIROCS_UPDATE;
- request->message->size = sizeof (PropUpdateScalar);
- request->message->payload = g_malloc0 (request->message->size);
- PropUpdateScalar *update = (PropUpdateScalar *)request->message->payload;
- g_object_get (data->cam, property_name, &update->prop_raw, NULL);
- update->base.id = property_id_from_name (property_name, data->n_properties, data->properties);
- update->base.size = 1;
- update->base.scalar = TRUE;
- GError *error = NULL;
- if (!kiro_messenger_send (data->messenger, request, &error)) {
- g_error ("Oh shit! '%s'", error->message);
- g_error_free (error);
- //TODO
- //Things
- }
- }
- if (request->message->payload)
- g_free (request->message->payload);
- g_free (request->message);
- kiro_messenger_receive (data->messenger, request);
- }
- int main (int argc, char *argv[])
- {
- GOptionContext *context;
- GError *error = NULL;
- static gchar *camera_name = "mock";
- static gchar *addr = "127.0.0.1";
- static gchar *port = "60010";
- static gboolean list = FALSE;
- static GOptionEntry entries[] = {
- { "camera", 'c', 0, G_OPTION_ARG_STRING, &camera_name, "Uca camera plugin to load", NULL },
- { "address", 'a', 0, G_OPTION_ARG_STRING, &addr, "Address to listen on", NULL },
- { "port", 'p', 0, G_OPTION_ARG_STRING, &port, "Port to listen on", NULL },
- { "list", 'l', 0, G_OPTION_ARG_NONE, &list, "List all available plugins and exit", NULL },
- { NULL }
- };
- #if !(GLIB_CHECK_VERSION (2, 36, 0))
- g_type_init ();
- #endif
- context = g_option_context_new ("-l | [-c <CAMERA PLUGIN>] [-a <ADDRESS>] [-p <PORT>]");
- g_option_context_set_summary (context, "kiro-camera-server provides a remote control host for libuca cameras.\n\
- Once the server is started, you can use the uca-kiro-camera plugin to connect to the server\n\
- over an InfiniBand network and control the loaded remote camera as if it was connected locally.");
- g_option_context_add_main_entries (context, entries, NULL);
- if (!g_option_context_parse (context, &argc, &argv, &error)) {
- g_print ("Error parsing options: %s\n", error->message);
- exit (-1);
- }
- if (argc >= 2) {
- g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
- exit (0);
- }
- KiroCsData data;
- data.exit_flag = FALSE;
- data.peer_rank = 0;
- UcaPluginManager *pm = uca_plugin_manager_new ();
- if (list) {
- GList *names = uca_plugin_manager_get_available_cameras (pm);
- if (!names) {
- g_print ("No available plugins found.\n");
- }
- else {
- g_print ("The following Uca camera plugins are available:\n");
- g_list_foreach (names, (GFunc) print_cam_name, NULL);
- g_list_free_full (names, g_free);
- }
- g_object_unref (pm);
- exit (0);
- }
- data.cam = uca_plugin_manager_get_camera (pm, camera_name, &error, NULL);
- if (!(data.cam)) {
- g_print ("Failed to load plugin '%s': %s. Exiting.\n", camera_name, error->message);
- g_object_unref (pm);
- exit (-1);
- }
- g_object_unref (pm);
- data.messenger = kiro_messenger_new ();
- kiro_messenger_start_listen (data.messenger, addr, port, (KiroConnectCallbackFunc) connect_callback, &(data.peer_rank), &error);
- if (error) {
- g_print ("Failed to launch Kiro Server: %s Exiting.\n", error->message);
- g_object_unref (data.cam);
- exit (-1);
- }
- // wait for the first peer
- while (data.peer_rank == 0) {};
- KiroMessage message;
- data.signal_handlers = NULL;
- data.properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (data.cam), &data.n_properties);
- if (!(*data.properties)) {
- g_object_unref (data.messenger);
- g_object_unref (data.cam);
- g_error ("No properties exposed by camera '%s'.", camera_name);
- }
- else {
- data.signal_handlers = g_malloc0 (sizeof (gulong) * (data.n_properties + 1)); //0 is not a valid property ID
- for (guint idx=0; idx < data.n_properties; idx++) {
- if (idx >= N_BASE_PROPERTIES - 1) {
- //NONE Base Property.
- //Inform peer and setup
- g_debug ("Asking peer to install property '%s' with ID %u", data.properties[idx]->name, idx + 1);
- message.msg = KIROCS_INSTALL;
- message.size = sizeof (PropertyRequisition) + strlen (data.properties[idx]->name);
- message.payload = g_malloc0 (message.size);
- PropertyRequisition *req = message.payload;
- req->id = idx + 1;
- req->value_type = data.properties[idx]->value_type;
- switch (req->value_type) {
- case G_TYPE_BOOLEAN:
- req->spec.bool_spec = *(GParamSpecBoolean *)data.properties[idx];
- break;
- default:
- g_debug ("FOOBAR");
- }
- strcpy (req->name, data.properties[idx]->name);
- if (!kiro_messenger_send_blocking (data.messenger, &message, data.peer_rank, &error)) {
- g_error ("Oh shit!");
- //TODO
- //Things
- }
- g_free (req);
- }
- else
- peer_inform_update (data.cam, data.properties[idx], &data);
- guint handler_id = setup_signal_handler (data.cam, data.properties[idx], &data);
- data.signal_handlers[idx + 1] = handler_id;
- g_debug ("Setup handler for property '%s' with handler ID %u", data.properties[idx]->name, handler_id);
- }
- }
- //All done. Send READY
- message.msg = KIROCS_READY;
- message.size = 0;
- message.payload = NULL;
- if (!kiro_messenger_send_blocking (data.messenger, &message, data.peer_rank, &error)) {
- g_error ("Oh shit!");
- //TODO
- //Things
- }
- KiroRequest request;
- request.id = 0;
- request.callback = (KiroMessageCallbackFunc) receive_callback;
- request.user_data = (gpointer) &data;
- kiro_messenger_receive (data.messenger, &request);
- while (!(data.exit_flag)) {
- sleep (5);
- //TODO
- //Check if connection is still alive, and if not, reinitialize
- };
- g_free (data.properties);
- g_free (data.signal_handlers);
- kiro_messenger_free (data.messenger);
- g_object_unref (data.cam);
- return 0;
- };
|