kiro-camera-server.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /* Copyright (C) 2015 Timo Dritschler <timo.dritschler@kit.edu>
  2. (Karlsruhe Institute of Technology)
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Lesser General Public License as published by the
  5. Free Software Foundation; either version 2.1 of the License, or (at your
  6. option) any later version.
  7. This library is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  10. details.
  11. You should have received a copy of the GNU Lesser General Public License along
  12. with this library; if not, write to the Free Software Foundation, Inc., 51
  13. Franklin St, Fifth Floor, Boston, MA 02110, USA
  14. */
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "kiro-camera-server.h"
  18. #include "uca/uca-plugin-manager.h"
  19. typedef struct {
  20. gboolean exit_flag;
  21. UcaCamera *cam;
  22. KiroMessenger *messenger;
  23. gulong peer_rank;
  24. gulong *signal_handlers;
  25. GParamSpec **properties;
  26. } KiroCsData;
  27. static gulong
  28. pspec_size (GType type)
  29. {
  30. gulong ret = 0;
  31. switch (type) {
  32. case G_TYPE_BOOLEAN:
  33. ret = sizeof (GParamSpecBoolean);
  34. break;
  35. case G_TYPE_CHAR:
  36. ret = sizeof (GParamSpecChar);
  37. break;
  38. case G_TYPE_INT:
  39. ret = sizeof (GParamSpecInt);
  40. break;
  41. case G_TYPE_UINT:
  42. ret = sizeof (GParamSpecUInt);
  43. break;
  44. case G_TYPE_LONG:
  45. ret = sizeof (GParamSpecLong);
  46. break;
  47. case G_TYPE_ULONG:
  48. ret = sizeof (GParamSpecULong);
  49. break;
  50. case G_TYPE_INT64:
  51. ret = sizeof (GParamSpecInt64);
  52. break;
  53. case G_TYPE_UINT64:
  54. ret = sizeof (GParamSpecUInt64);
  55. break;
  56. case G_TYPE_FLOAT:
  57. ret = sizeof (GParamSpecFloat);
  58. break;
  59. case G_TYPE_DOUBLE:
  60. ret = sizeof (GParamSpecDouble);
  61. break;
  62. default:
  63. ret = sizeof (GParamSpec);
  64. }
  65. return ret;
  66. }
  67. static gulong
  68. gtype_size (GType type)
  69. {
  70. gulong ret = 0;
  71. switch (type) {
  72. case G_TYPE_BOOLEAN:
  73. ret = sizeof (gboolean);
  74. break;
  75. case G_TYPE_CHAR:
  76. ret = sizeof (gchar);
  77. break;
  78. case G_TYPE_INT:
  79. ret = sizeof (gint);
  80. break;
  81. case G_TYPE_ENUM:
  82. ret = sizeof (gint);
  83. break;
  84. case G_TYPE_UINT:
  85. ret = sizeof (guint);
  86. break;
  87. case G_TYPE_LONG:
  88. ret = sizeof (glong);
  89. break;
  90. case G_TYPE_ULONG:
  91. ret = sizeof (gulong);
  92. break;
  93. case G_TYPE_INT64:
  94. ret = sizeof (gint64);
  95. break;
  96. case G_TYPE_UINT64:
  97. ret = sizeof (guint64);
  98. break;
  99. case G_TYPE_FLOAT:
  100. ret = sizeof (gfloat);
  101. break;
  102. case G_TYPE_DOUBLE:
  103. ret = sizeof (gdouble);
  104. break;
  105. default:
  106. //ERROR
  107. break;
  108. }
  109. return ret;
  110. }
  111. gint
  112. property_id_from_name(const gchar* name)
  113. {
  114. gint idx = 0;
  115. gboolean found = FALSE;
  116. for (;idx < N_BASE_PROPERTIES; ++idx) {
  117. if (0 == g_strcmp0(name, uca_camera_props[idx])) {
  118. found = TRUE;
  119. break;
  120. }
  121. }
  122. return found ? idx : -1;
  123. }
  124. static void
  125. print_cam_name (gchar *name, gpointer unused)
  126. {
  127. (void) unused;
  128. g_print ("-- %s\n", name);
  129. }
  130. static void
  131. peer_inform_update (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
  132. {
  133. g_print ("Updated %s.\n", pspec->name);
  134. GError *error = NULL;
  135. GVariant *tmp = read_property_scalar (G_OBJECT (cam), pspec->name, pspec->value_type);
  136. gsize data_size = g_variant_get_size (tmp);
  137. PropUpdate *test = g_malloc0 (sizeof (PropUpdate) + data_size);
  138. test->id = property_id_from_name (pspec->name);
  139. test->type[0] = gtype_to_gvariant_class (pspec->value_type);
  140. test->size = data_size;
  141. g_variant_store (tmp, test->val);
  142. g_variant_unref (tmp);
  143. KiroMessage message;
  144. message.peer_rank = data->peer_rank;
  145. message.msg = KIROCS_UPDATE;
  146. message.payload = test;
  147. message.size = sizeof (PropUpdate) + data_size;
  148. kiro_messenger_send_blocking (data->messenger, &message, &error);
  149. if (error) {
  150. g_free (test);
  151. g_error ("Oh shit! (%s)", error->message);
  152. }
  153. g_free (test);
  154. }
  155. static gulong
  156. setup_signal_handler (UcaCamera *cam, GParamSpec *pspec, KiroCsData *data)
  157. {
  158. GString *signal_name = g_string_new ("notify::");
  159. signal_name = g_string_append (signal_name, pspec->name);
  160. gulong ret = g_signal_connect (cam, signal_name->str, G_CALLBACK (peer_inform_update), data);
  161. g_string_free (signal_name, TRUE);
  162. return ret;
  163. }
  164. static void
  165. null_callback (gpointer unused)
  166. {
  167. (void)unused;
  168. }
  169. static inline gpointer
  170. unpack_scalar (PropUpdate *src)
  171. {
  172. //Alloc max scalar size
  173. gpointer out = g_malloc0 (sizeof (guint64));
  174. GVariant *var = g_variant_new_from_data ((const GVariantType *)src->type, src->val, \
  175. src->size, TRUE, null_callback, NULL);
  176. g_variant_get (var, src->type, out);
  177. g_variant_unref (var);
  178. return out;
  179. }
  180. static KiroContinueFlag
  181. connect_callback (gulong rank, gulong *storage)
  182. {
  183. *storage = rank;
  184. return KIRO_CALLBACK_REMOVE;
  185. }
  186. // MAIN HANDLER //
  187. static KiroContinueFlag
  188. receive_callback (KiroMessageStatus *status, KiroCsData *data)
  189. {
  190. PropUpdate *update = (PropUpdate *)status->message->payload;
  191. if (status->message->msg == KIROCS_EXIT) {
  192. g_message ("Peer requested shut down...");
  193. data->exit_flag = TRUE;
  194. }
  195. if (status->message->msg == KIROCS_UPDATE) {
  196. g_debug ("Unpacking ID %u\n", update->id);
  197. gpointer unpacked = unpack_scalar (update);
  198. //Don't forget the -1, because the index starts at 0, but property IDs
  199. //start at 1...
  200. update_property_scalar (G_OBJECT (data->cam),
  201. data->properties[update->id -1]->name,
  202. data->properties[update->id -1]->value_type,
  203. data->signal_handlers[update->id],
  204. unpacked);
  205. g_free (unpacked);
  206. }
  207. status->request_cleanup = TRUE;
  208. return KIRO_CALLBACK_CONTINUE;
  209. }
  210. int main (int argc, char *argv[])
  211. {
  212. GOptionContext *context;
  213. GError *error = NULL;
  214. static gchar *camera_name = "mock";
  215. static gchar *addr = "127.0.0.1";
  216. static gchar *port = "60010";
  217. static gboolean list = FALSE;
  218. static GOptionEntry entries[] = {
  219. { "camera", 'c', 0, G_OPTION_ARG_STRING, &camera_name, "Uca camera plugin to load", NULL },
  220. { "address", 'a', 0, G_OPTION_ARG_STRING, &addr, "Address to listen on", NULL },
  221. { "port", 'p', 0, G_OPTION_ARG_STRING, &port, "Port to listen on", NULL },
  222. { "list", 'l', 0, G_OPTION_ARG_NONE, &list, "List all available plugins and exit", NULL },
  223. { NULL }
  224. };
  225. #if !(GLIB_CHECK_VERSION (2, 36, 0))
  226. g_type_init ();
  227. #endif
  228. context = g_option_context_new ("-l | [-c <CAMERA PLUGIN>] [-a <ADDRESS>] [-p <PORT>]");
  229. g_option_context_set_summary (context, "kiro-camera-server provides a remote control host for libuca cameras.\n\
  230. Once the server is started, you can use the uca-kiro-camera plugin to connect to the server\n\
  231. over an InfiniBand network and control the loaded remote camera as if it was connected locally.");
  232. g_option_context_add_main_entries (context, entries, NULL);
  233. if (!g_option_context_parse (context, &argc, &argv, &error)) {
  234. g_print ("Error parsing options: %s\n", error->message);
  235. exit (-1);
  236. }
  237. if (argc >= 2) {
  238. g_print ("%s", g_option_context_get_help (context, TRUE, NULL));
  239. exit (0);
  240. }
  241. KiroCsData data;
  242. data.exit_flag = FALSE;
  243. data.peer_rank = 0;
  244. UcaPluginManager *pm = uca_plugin_manager_new ();
  245. if (list) {
  246. GList *names = uca_plugin_manager_get_available_cameras (pm);
  247. if (!names) {
  248. g_print ("No available plugins found.\n");
  249. }
  250. else {
  251. g_print ("The following Uca camera plugins are available:\n");
  252. g_list_foreach (names, (GFunc) print_cam_name, NULL);
  253. g_list_free_full (names, g_free);
  254. }
  255. g_object_unref (pm);
  256. exit (0);
  257. }
  258. data.cam = uca_plugin_manager_get_camera (pm, camera_name, &error, NULL);
  259. if (!(data.cam)) {
  260. g_print ("Failed to load plugin '%s': %s. Exiting.\n", camera_name, error->message);
  261. g_object_unref (pm);
  262. exit (-1);
  263. }
  264. g_object_unref (pm);
  265. data.messenger = kiro_messenger_new ();
  266. kiro_messenger_start_listen (data.messenger, addr, port, (KiroConnectCallbackFunc) connect_callback, &(data.peer_rank), &error);
  267. if (error) {
  268. g_print ("Failed to launch Kiro Server: %s Exiting.\n", error->message);
  269. g_object_unref (data.cam);
  270. exit (-1);
  271. }
  272. // wait for the first peer
  273. while (data.peer_rank == 0) {};
  274. guint num_properties = 0;
  275. data.signal_handlers = NULL;
  276. data.properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (data.cam), &num_properties);
  277. if (!(*data.properties)) {
  278. g_object_unref (data.messenger);
  279. g_object_unref (data.cam);
  280. g_error ("No properties exposed by camera '%s'.", camera_name);
  281. }
  282. else {
  283. data.signal_handlers = g_malloc0 (sizeof (gulong) * (num_properties + 1)); //0 is not a valid property ID
  284. for (guint idx=0; idx < num_properties; idx++) {
  285. gint prop_id = property_id_from_name (data.properties[idx]->name);
  286. if (0 >= prop_id) {
  287. //NONE Base Property.
  288. //Inform peer and setup
  289. continue;
  290. }
  291. data.signal_handlers[prop_id] = setup_signal_handler (data.cam, data.properties[idx], &data);
  292. }
  293. }
  294. //All done. Send READY
  295. KiroMessage message;
  296. message.peer_rank = data.peer_rank;
  297. message.msg = KIROCS_READY;
  298. message.size = 0;
  299. message.payload = NULL;
  300. if (!kiro_messenger_send_blocking (data.messenger, &message, &error)) {
  301. g_error ("Oh shit!");
  302. //TODO
  303. //Things
  304. }
  305. kiro_messenger_add_receive_callback (data.messenger, (KiroMessageCallbackFunc)receive_callback, &data);
  306. while (!(data.exit_flag)) {};
  307. g_free (data.properties);
  308. g_free (data.signal_handlers);
  309. kiro_messenger_free (data.messenger);
  310. g_object_unref (data.cam);
  311. return 0;
  312. };