Fawkes API Fawkes Development Version
mod_blackboard.cpp
1
2/***************************************************************************
3 * mod_blackboard.cpp - OpenPRS blackboard module
4 *
5 * Created: Tue Sep 02 10:38:03 2014
6 * Copyright 2014 Tim Niemueller [www.niemueller.de]
7 ****************************************************************************/
8
9/* This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * Read the full text in the LICENSE.GPL file in the doc directory.
20 */
21
22#include <blackboard/remote.h>
23#include <plugins/openprs/mod_utils.h>
24#include <utils/misc/string_conversions.h>
25#include <utils/time/time.h>
26
27#include <lisp-list_f-pub.h>
28#include <oprs-array_f-pub.h>
29#include <oprs-type_f-pub.h>
30#include <oprs_f-pub.h>
31#include <slistPack_f.h>
32
33using namespace fawkes;
34
35extern "C" void finalize();
36
37// Global variables
38BlackBoard * g_blackboard = NULL;
39std::map<std::string, Interface *> g_interfaces_read;
40std::map<std::string, Interface *> g_interfaces_write;
41Symbol g_bb_read_sym;
42Symbol g_bb_write_sym;
43Symbol g_bb_data_sym;
44
45extern "C" Term *
46action_blackboard_open(TermList terms)
47{
48 int terms_len = sl_slist_length(terms);
49 if (terms_len != 3) {
50 fprintf(stderr,
51 "Error[bb-open-interface]: invalid number of "
52 "arguments: req 3, got %i\n",
53 terms_len);
54 ACTION_FAIL();
55 }
56
57 Term *type = (Term *)get_list_pos(terms, 1);
58 Term *id = (Term *)get_list_pos(terms, 2);
59 Term *mode = (Term *)get_list_pos(terms, 3);
60 if (type->type != STRING) {
61 fprintf(stderr, "Error[bb-open-interface]: interface type is not a STRING\n");
62 ACTION_FAIL();
63 }
64 if (id->type != STRING) {
65 fprintf(stderr, "Error[bb-open-interface]: interface ID is not a STRING\n");
66 ACTION_FAIL();
67 }
68 if (id->type != STRING) {
69 fprintf(stderr, "Error[bb-open-interface]: interface ID is not a STRING\n");
70 ACTION_FAIL();
71 }
72 if (mode->type != TT_ATOM) {
73 fprintf(stderr, "Error[bb-open-interface]: interface mode is not a symbol\n");
74 ACTION_FAIL();
75 }
76 if (mode->u.id != g_bb_read_sym && mode->u.id != g_bb_write_sym) {
77 fprintf(stderr, "Error[bb-open-interface]: interface mode must be BB-READ or BB-WRITE\n");
78 ACTION_FAIL();
79 }
80
81 std::string uid = std::string(type->u.string) + "::" + id->u.string;
82
83 if (mode->u.id == g_bb_read_sym) {
84 if (g_interfaces_read.find(uid) == g_interfaces_read.end()) {
85 try {
86 printf("Opening interface %s::%s for reading\n", type->u.string, id->u.string);
87 Interface *iface = g_blackboard->open_for_reading(type->u.string, id->u.string);
88 g_interfaces_read[uid] = iface;
89 } catch (Exception &e) {
90 fprintf(stderr,
91 "Failed to open interface %s::%s: %s",
92 type->u.string,
93 id->u.string,
95 ACTION_FAIL();
96 }
97 }
98 } else {
99 if (g_interfaces_write.find(uid) == g_interfaces_write.end()) {
100 try {
101 printf("Opening interface %s::%s for writing\n", type->u.string, id->u.string);
102 Interface *iface = g_blackboard->open_for_writing(type->u.string, id->u.string);
103 g_interfaces_write[uid] = iface;
104 } catch (Exception &e) {
105 fprintf(stderr,
106 "Failed to open interface %s::%s: %s\n",
107 type->u.string,
108 id->u.string,
110 ACTION_FAIL();
111 }
112 }
113 }
114
115 ACTION_FINAL();
116}
117
118extern "C" Term *
119action_blackboard_close(TermList terms)
120{
121 int terms_len = sl_slist_length(terms);
122 if (terms_len != 2) {
123 fprintf(stderr,
124 "Error[bb-close-interface]: invalid number of "
125 "arguments: req 2, got %i\n",
126 terms_len);
127 ACTION_FAIL();
128 }
129
130 Term *type = (Term *)get_list_pos(terms, 1);
131 Term *id = (Term *)get_list_pos(terms, 2);
132 if (type->type != STRING) {
133 fprintf(stderr, "Error[bb-close-interface]: interface type is not a STRING\n");
134 ACTION_FAIL();
135 }
136 if (id->type != STRING) {
137 fprintf(stderr, "Error[bb-close-interface]: interface ID is not a STRING\n");
138 ACTION_FAIL();
139 }
140 if (id->type != STRING) {
141 fprintf(stderr, "Error[bb-close-interface]: interface ID is not a STRING\n");
142 ACTION_FAIL();
143 }
144
145 std::string uid = std::string(type->u.string) + "::" + id->u.string;
146
147 if (g_interfaces_read.find(uid) != g_interfaces_read.end()) {
148 try {
149 printf("Closing reading interface %s::%s\n", type->u.string, id->u.string);
150 g_blackboard->close(g_interfaces_read[uid]);
151 g_interfaces_read.erase(uid);
152 } catch (Exception &e) {
153 fprintf(stderr,
154 "Failed to close interface %s::%s: %s",
155 type->u.string,
156 id->u.string,
158 ACTION_FAIL();
159 }
160 } else if (g_interfaces_write.find(uid) != g_interfaces_write.end()) {
161 try {
162 printf("Closing writing interface %s::%s\n", type->u.string, id->u.string);
163 g_blackboard->close(g_interfaces_write[uid]);
164 g_interfaces_write.erase(uid);
165 } catch (Exception &e) {
166 fprintf(stderr,
167 "Failed to close interface %s::%s: %s\n",
168 type->u.string,
169 id->u.string,
171 ACTION_FAIL();
172 }
173 }
174
175 ACTION_FINAL();
176}
177
178extern "C" Term *
179action_blackboard_print(TermList terms)
180{
181 Term *type = (Term *)get_list_pos(terms, 1);
182 Term *id = (Term *)get_list_pos(terms, 2);
183 if (type->type != STRING) {
184 fprintf(stderr, "Error[bb-print]: interface type is not a STRING\n");
185 ACTION_FAIL();
186 }
187 if (id->type != STRING) {
188 fprintf(stderr, "Error[bb-print]: interface ID is not a STRING\n");
189 ACTION_FAIL();
190 }
191 if (id->type != STRING) {
192 fprintf(stderr, "Error[bb-print]: interface ID is not a STRING\n");
193 ACTION_FAIL();
194 }
195
196 std::string uid = std::string(type->u.string) + "::" + id->u.string;
197 //printf("*** Called to print %s\n", uid.c_str());
198
199 Interface *i = NULL;
200 if (g_interfaces_read.find(uid) != g_interfaces_read.end()) {
201 i = g_interfaces_read[uid];
202 } else if (g_interfaces_write.find(uid) != g_interfaces_write.end()) {
203 i = g_interfaces_write[uid];
204 } else {
205 fprintf(stderr, "Error[bb-print]: interface %s has not been opened\n", uid.c_str());
206 fprintf(stderr, "Error[bb-print]: Open interfaces are:\n");
207 for (auto j : g_interfaces_read) {
208 fprintf(stderr, "Error[bb-print]: [R] %s\n", j.second->uid());
209 }
210 for (auto j : g_interfaces_write) {
211 fprintf(stderr, "Error[bb-print]: [W] %s\n", j.second->uid());
212 }
213 fprintf(stderr, "Error[bb-print]: -----\n");
214 ACTION_FAIL();
215 }
216
217 try {
218 i->read();
219 const Time *t = i->timestamp();
220
221 std::string fact = std::string("(bb-data \"type\" \"") + i->type() + "\"" + " \"id\" \""
222 + i->id() + "\"" + " \"time\" " + StringConversions::to_string(t->get_sec())
223 + " " + StringConversions::to_string(t->get_usec()) + "" + " (. ";
224
225 InterfaceFieldIterator f, f_end = i->fields_end();
226 for (f = i->fields(); f != f_end; ++f) {
227 std::string value;
228 if (f.get_type() == IFT_STRING) {
229 value = f.get_value_string();
230 std::string::size_type pos = 0;
231 while ((pos = value.find("\"", pos)) != std::string::npos) {
232 value.replace(pos, 1, "\\\"");
233 pos += 2;
234 }
235 value = std::string("\"") + value + "\"";
236 } else if (f.get_type() == IFT_ENUM) {
237 value = std::string("\"") + f.get_value_string(" ") + "\"";
238 } else {
239 value = f.get_value_string(" ");
240 std::string::size_type pos;
241 while ((pos = value.find(",")) != std::string::npos) {
242 value = value.erase(pos, 1);
243 }
244 }
245 if (f.get_length() > 1) {
246 fact += std::string(" \"") + f.get_name() + "\" [ " + value + " ]";
247 } else {
248 fact += std::string(" \"") + f.get_name() + "\" " + value;
249 }
250 }
251 fact += " .))";
252 //envs_[env_name]->assert_fact(fact);
253 printf("%s\n", fact.c_str());
254 } catch (Exception &e) {
255 fprintf(stderr, "Error[bb-print]: %s\n", e.what_no_backtrace());
256 ACTION_FAIL();
257 }
258 ACTION_FINAL();
259}
260
261#define ADD_ARRAY(src_type, target_type, array_type) \
262 do { \
263 target_type * array = (target_type *)OPRS_MALLOC(sizeof(target_type) * f.get_length()); \
264 src_type##_t *src_array = f.get_##src_type##s(); \
265 for (unsigned int j = 0; j < f.get_length(); ++j) \
266 array[j] = src_array[j]; \
267 data = l_add_to_tail(data, make_##array_type##_array_from_array(f.get_length(), array)); \
268 } while (0);
269
270#define BUILD_FUNC(singular_type) build_##singular_type
271#define GET_FUNC(src_type) get_##src_type
272
273#define ADD_NUM_DATA(src_type, target_type, array_type, singular_type) \
274 do { \
275 if (f.get_length() > 1) { \
276 ADD_ARRAY(src_type, target_type, array_type); \
277 } else { \
278 data = l_add_to_tail(data, BUILD_FUNC(singular_type)(f.GET_FUNC(src_type)())); \
279 } \
280 } while (0);
281
282static void
283post_interface(Interface *i)
284{
285 i->read();
286 if (i->refreshed()) {
287 const Time *t = i->timestamp();
288
289 TermList tl = sl_make_slist();
290 tl = build_term_list(tl, build_string("type"));
291 tl = build_term_list(tl, build_string(i->type()));
292 tl = build_term_list(tl, build_string("id"));
293 tl = build_term_list(tl, build_string(i->id()));
294 tl = build_term_list(tl, build_string("time"));
295 tl = build_term_list(tl, build_long_long(t->get_sec()));
296 tl = build_term_list(tl, build_long_long(t->get_usec()));
297
298 L_List data = l_nil;
299 InterfaceFieldIterator f, f_end = i->fields_end();
300 for (f = i->fields(); f != f_end; ++f) {
301 data = l_add_to_tail(data, build_string(f.get_name()));
302
303 switch (f.get_type()) {
304 case IFT_BOOL:
305 data = l_add_to_tail(data, build_id(f.get_bool() ? lisp_t_sym : nil_sym));
306 break;
307 case IFT_INT8: ADD_NUM_DATA(int8, int, int, integer); break;
308 case IFT_UINT8: ADD_NUM_DATA(uint8, int, int, integer); break;
309 case IFT_INT16: ADD_NUM_DATA(int16, int, int, integer); break;
310 case IFT_UINT16: ADD_NUM_DATA(uint16, int, int, integer); break;
311 case IFT_INT32: ADD_NUM_DATA(int32, int, int, integer); break;
312 case IFT_UINT32: ADD_NUM_DATA(uint32, double, float, long_long); break;
313 case IFT_INT64: ADD_NUM_DATA(int64, double, float, long_long); break;
314 case IFT_UINT64: ADD_NUM_DATA(uint64, double, float, long_long); break;
315 case IFT_FLOAT: ADD_NUM_DATA(float, double, float, float); break;
316 case IFT_DOUBLE: ADD_NUM_DATA(double, double, float, float); break;
317 case IFT_STRING: data = l_add_to_tail(data, build_string(f.get_value_string())); break;
318 case IFT_BYTE: ADD_NUM_DATA(uint8, int, int, integer); break;
319 case IFT_ENUM: data = l_add_to_tail(data, build_string(f.get_value_string())); break;
320 }
321 }
322
323 tl = build_term_list(tl, build_l_list(data));
324 add_external_fact((char *)"bb-data", tl);
325 }
326}
327
328extern "C" Term *
329action_blackboard_read_all(TermList terms)
330{
331 try {
332 for (auto &if_entry : g_interfaces_read) {
333 Interface *i = if_entry.second;
334 post_interface(i);
335 }
336 } catch (Exception &e) {
337 fprintf(stderr, "Error[bb-read]: read failed: %s\n", e.what_no_backtrace());
338 ACTION_FAIL();
339 }
340 ACTION_FINAL();
341}
342
343extern "C" Term *
344action_blackboard_read(TermList terms)
345{
346 int terms_len = sl_slist_length(terms);
347 if (terms_len != 2) {
348 fprintf(stderr,
349 "Error[bb-read]: invalid number of "
350 "arguments: req 2, got %i\n",
351 terms_len);
352 ACTION_FAIL();
353 }
354
355 Term *type = (Term *)get_list_pos(terms, 1);
356 Term *id = (Term *)get_list_pos(terms, 2);
357 if (type->type != STRING) {
358 fprintf(stderr, "Error[bb-read]: interface type is not a STRING\n");
359 ACTION_FAIL();
360 }
361 if (id->type != STRING) {
362 fprintf(stderr, "Error[bb-read]: interface ID is not a STRING\n");
363 ACTION_FAIL();
364 }
365 if (id->type != STRING) {
366 fprintf(stderr, "Error[bb-read]: interface ID is not a STRING\n");
367 ACTION_FAIL();
368 }
369
370 std::string uid = std::string(type->u.string) + "::" + id->u.string;
371
372 if (g_interfaces_read.find(uid) != g_interfaces_read.end()) {
373 try {
374 post_interface(g_interfaces_read[uid]);
375 } catch (Exception &e) {
376 fprintf(stderr,
377 "Failed to read interface %s::%s: %s",
378 type->u.string,
379 id->u.string,
381 ACTION_FAIL();
382 }
383 } else {
384 fprintf(stderr,
385 "Failed to read interface %s::%s: interface not opened",
386 type->u.string,
387 id->u.string);
388 ACTION_FAIL();
389 }
390
391 ACTION_FINAL();
392}
393
394/** Searches for a given entry in the bb-date object
395 * specified by String. Returns nil if entry not present */
396extern "C" Term *
397func_blackboard_value(TermList terms)
398{
399 int terms_len = sl_slist_length(terms);
400 if (terms_len != 2) {
401 fprintf(stderr,
402 "Error[bb-value]: invalid number of "
403 "arguments: req 2, got %i\n",
404 terms_len);
405 ACTION_FAIL();
406 }
407 Term *dlist = (Term *)get_list_pos(terms, 1);
408 Term *name = (Term *)get_list_pos(terms, 2);
409 Term *restemp;
410
411 if (dlist->type != LISP_LIST) {
412 fprintf(stderr, "Error[bb-value]: first argument is not a LISP_LIST\n");
413 ACTION_FAIL();
414 }
415 if (name->type != STRING) {
416 fprintf(stderr, "Error[bb-value]: interface ID is not a STRING\n");
417 ACTION_FAIL();
418 }
419 char *pattern = name->u.string;
420 int i = 1;
421 while (i < l_length(dlist->u.l_list) - 1) {
422 Term *t1 = get_term_from_l_car(l_nth(dlist->u.l_list, i));
423 if (t1->type == STRING) {
424 char *searched = t1->u.string;
425 if (strcmp(pattern, searched) == 0) {
426 restemp = get_term_from_l_car(l_nth((dlist->u).l_list, i + 1));
427 // cast string objects to symbols to prevent upper-/lowercase
428 // differences in db.
429 if (restemp->type == STRING) {
430 std::string outputs = std::string(restemp->u.string);
431 std::transform(outputs.begin(), outputs.end(), outputs.begin(), ::tolower);
432 restemp = build_id(declare_atom(outputs.c_str()));
433 }
434 return copy_term(restemp);
435 }
436 ++i;
437 }
438 }
439 fprintf(stderr, "Error[bb-value]: wanted entry in bb-data not present\n");
440 ACTION_FAIL();
441}
442
443/** Entry function for the OpenPRS module. */
444extern "C" void
445init()
446{
447 printf("*** LOADING mod_blackboard\n");
448
449 std::string fawkes_host;
450 unsigned short fawkes_port = 0;
451 get_fawkes_host_port(fawkes_host, fawkes_port);
452
453 printf("Connecting to Fawkes at %s:%u\n", fawkes_host.c_str(), fawkes_port);
454 try {
455 g_blackboard = new RemoteBlackBoard(fawkes_host.c_str(), fawkes_port);
456 } catch (Exception &e) {
457 fprintf(stderr, "Error: cannot establish blackboard connection: %s\n", e.what_no_backtrace());
458 }
459
460 g_bb_read_sym = declare_atom("BB-READ");
461 g_bb_write_sym = declare_atom("BB-WRITE");
462 g_bb_data_sym = declare_atom("bb-data");
463 declare_pred_from_symbol(g_bb_data_sym);
464 make_and_declare_eval_funct("bb-value", func_blackboard_value, 2);
465 make_and_declare_action("bb-open", action_blackboard_open, 3);
466 make_and_declare_action("bb-close", action_blackboard_close, 2);
467 make_and_declare_action("bb-read", action_blackboard_read, 2);
468 make_and_declare_action("bb-read-all", action_blackboard_read_all, 0);
469 make_and_declare_action("bb-print", action_blackboard_print, 2);
470 add_user_end_kernel_hook(finalize);
471}
472
473/** Finalization function for the OpenPRS module. */
474extern "C" void
475finalize()
476{
477 printf("*** DESTROYING mod_skiller\n");
478 for (auto &iface : g_interfaces_read) {
479 g_blackboard->close(iface.second);
480 }
481 g_interfaces_read.clear();
482 for (auto &iface : g_interfaces_write) {
483 g_blackboard->close(iface.second);
484 }
485 g_interfaces_write.clear();
486
487 delete g_blackboard;
488 g_blackboard = NULL;
489}
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual void close(Interface *interface)=0
Close interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
Interface field iterator.
size_t get_length() const
Get length of current field.
interface_fieldtype_t get_type() const
Get type of current field.
const char * get_name() const
Get name of current field.
bool get_bool(unsigned int index=0) const
Get value of current field as bool.
const char * get_value_string(const char *array_sep=", ")
Get value of current field as string.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
const char * type() const
Get type of interface.
Definition: interface.cpp:652
const Time * timestamp() const
Get timestamp of last write.
Definition: interface.cpp:714
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1240
const char * id() const
Get identifier of interface.
Definition: interface.cpp:661
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1231
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:479
bool refreshed() const
Check if data has been refreshed.
Definition: interface.cpp:811
Remote BlackBoard.
Definition: remote.h:50
A class for handling time.
Definition: time.h:93
long get_usec() const
Get microseconds.
Definition: time.h:127
long get_sec() const
Get seconds.
Definition: time.h:117
Fawkes library namespace.
@ IFT_INT8
8 bit integer field
Definition: types.h:38
@ IFT_UINT32
32 bit unsigned integer field
Definition: types.h:43
@ IFT_FLOAT
float field
Definition: types.h:46
@ IFT_BYTE
byte field, alias for uint8
Definition: types.h:49
@ IFT_UINT64
64 bit unsigned integer field
Definition: types.h:45
@ IFT_UINT16
16 bit unsigned integer field
Definition: types.h:41
@ IFT_INT32
32 bit integer field
Definition: types.h:42
@ IFT_INT64
64 bit integer field
Definition: types.h:44
@ IFT_DOUBLE
double field
Definition: types.h:47
@ IFT_INT16
16 bit integer field
Definition: types.h:40
@ IFT_STRING
string field
Definition: types.h:48
@ IFT_BOOL
boolean field
Definition: types.h:37
@ IFT_ENUM
field with interface specific enum type
Definition: types.h:50
@ IFT_UINT8
8 bit unsigned integer field
Definition: types.h:39