gusimplewhiteboard
Whiteboard.cc
Go to the documentation of this file.
1/*
2 * Whiteboard.cc
3 *
4 * Created by René Hexel on 21/12/11.
5 * Copyright (c) 2011-2014, 2018 Rene Hexel.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials
18 * provided with the distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgement:
22 *
23 * This product includes software developed by Rene Hexel.
24 *
25 * 4. Neither the name of the author nor the names of contributors
26 * may be used to endorse or promote products derived from this
27 * software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
33 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * -----------------------------------------------------------------------
42 * This program is free software; you can redistribute it and/or
43 * modify it under the above terms or under the terms of the GNU
44 * General Public License as published by the Free Software Foundation;
45 * either version 2 of the License, or (at your option) any later version.
46 *
47 * This program is distributed in the hope that it will be useful,
48 * but WITHOUT ANY WARRANTY; without even the implied warranty of
49 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50 * GNU General Public License for more details.
51 *
52 * You should have received a copy of the GNU General Public License
53 * along with this program; if not, see http://www.gnu.org/licenses/
54 * or write to the Free Software Foundation, Inc., 51 Franklin Street,
55 * Fifth Floor, Boston, MA 02110-1301, USA.
56 *
57 */
58#define FROM_WHITEBOARD_CC_
59
60#include <cstring>
61#include <gu_util.h>
62#include "Whiteboard.h"
64
65#pragma clang diagnostic push
66#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
67
68#ifndef DISPATCH_QUEUE_SERIAL
69#define DISPATCH_QUEUE_SERIAL NULLPTR
70#endif
71
72extern "C" {
73#ifdef GSW_IOS_DEVICE
74extern void init_ios_whiteboard_name(void);
75extern const char *wbname_prefixed_with_path(const char *wbname);
76#else // IOS needs to define this in ObjC-Whiteboard
77#define init_ios_whiteboard_name();
78const char *gsw_global_whiteboard_name = "guWhiteboard";
79#endif
80}
81
82using namespace guWhiteboard;
83using namespace std;
84
85static void subscription_callback(gu_simple_whiteboard_descriptor *wbd)
86{
87 Whiteboard *self = static_cast<Whiteboard *>(wbd->context);
88 if (self) self->subscriptionCallback();
89}
90
91Whiteboard::Whiteboard(const char *name, bool /*checkVersion*/, int number)
92{
94
95 if (!name) name = gsw_global_whiteboard_name;
96#ifdef GSW_IOS_DEVICE
97 else name = wbname_prefixed_with_path(name);
98#endif
99 if (!(callback_group = dispatch_group_create()))
100 {
101 cerr << "Unable to create dispatch group " << number << ": '" << name << "'" << endl;
102 throw "Whiteboard cannot create callback queue";
103 }
104 if (!(callback_queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL)))
105 {
106 cerr << "Unable to create dispatch queue " << number << ": '" << name << "'" << endl;
107 throw "Whiteboard cannot create dispatch queue";
108 }
109 if (!(_wbd = gsw_new_numbered_whiteboard(name, number)))
110 {
111 cerr << "Unable to create whiteboard " << number << ": '" << name << "'" << endl;
112 throw "Cannot create whiteboard";
113 }
114 _wbd->context = this;
115 _wbd->callback = subscription_callback;
116}
117
118
120{
121 _wbd->callback = NULLPTR; // avoid starvation
122 dispatch_group_wait(callback_group, DISPATCH_TIME_FOREVER);
123
125 dispatch_release(callback_queue);
126 dispatch_release(callback_group);
127}
128
129
130void Whiteboard::addMessage(gsw_hash_info *hashinfo, const WBMsg &msg, bool nonatomic, bool notifySubscribers)
131{
132 int t = hashinfo->msg_offset;
133
134#ifdef DEBUG
135 if (nonatomic < 0 || nonatomic > 1)
136 cerr << " *** Nonatomic parameter " << nonatomic << " not bool (are you using a life span?) ***" << endl;
137#endif
138 if (!nonatomic) gsw_procure(_wbd->sem, GSW_SEM_PUTMSG);
139
142 m->wbmsg.type = msg.getType();
143
144
145 switch (m->wbmsg.type)
146 {
147 case WBMsg::TypeEmpty:
148 m->wbmsg.len = 0;
149 break;
150
151 case WBMsg::TypeBool:
152 m->wbmsg.len = sizeof(int);
153 m->sint = msg.getBoolValue();
154 break;
155
156 case WBMsg::TypeInt:
157 m->wbmsg.len = sizeof(int);
158 m->sint = msg.getIntValue();
159 break;
160
161 case WBMsg::TypeFloat:
162 m->wbmsg.len = sizeof(float);
163 m->sfloat = msg.getFloatValue();
164 break;
165
167 gu_strlcpy(m->wbmsg.data, msg.getStringValue().c_str(), sizeof(m->wbmsg.data));
168 m->wbmsg.len = static_cast<unsigned char>(strlen(m->wbmsg.data) + 1);
169 break;
170
171 case WBMsg::TypeArray:
172 {
173 int k = 0;
174 for (vector<int>::const_iterator i = msg.getArrayValue().begin(); i < msg.getArrayValue().end(); i++)
175 m->ivec[k++] = *i;
176 m->wbmsg.len = static_cast<unsigned char>(k);
177 break;
178 }
180 {
181 unsigned len = static_cast<unsigned>(msg.getSizeInBytes());
182 if (len > sizeof(m->wbmsg.data)) len = sizeof(m->wbmsg.data);
183 m->wbmsg.len = static_cast<unsigned char>(len);
184 if (len) memcpy(m->wbmsg.data, msg.getBinaryValue(), len);
185 break;
186 }
187 }
188 gsw_increment(wb, t);
190 if (!nonatomic) gsw_vacate(_wbd->sem, GSW_SEM_PUTMSG);
191 if (notifySubscribers && wb->subscribed) gsw_signal_subscribers(wb);
192}
193
195{
196 int t = hashinfo->msg_offset;
197
199
200 if (result)
201 {
202 if (m->wbmsg.type || m->wbmsg.len)
203 *result = METHOD_OK;
204 else
205 *result = METHOD_FAIL;
206 }
207 return getWBMsg(m);
208}
209
211{
212 return new gsw_hash_info(getTypeOffset_private(type.c_str()));
213}
214
215int Whiteboard::getTypeOffset_private(std::string type)
216{
217 for(int i = 0; i < GSW_NUM_TYPES_DEFINED; i++)
218 {
219 if (type.compare(WBTypes_stringValues[i]) == 0)
220 return i;
221 }
222 return gsw_offset_for_message_type(_wbd, type.c_str());
223}
224
225#pragma mark - subscription and callbacks
226
228{
229 result = Whiteboard::METHOD_OK;
230
232 int offs = -1, current = -1;
233 if (hashinfo->msg_offset != GLOBAL_MSG_ID) // type != "*"
234 {
235 offs = hashinfo->msg_offset;
236 current = _wbd->wb->indexes[offs];
237 }
238 else for (int i = 0; i < _wbd->wb->num_types; i++) // subscribe to all
239 cball_indexes[i] = _wbd->wb->indexes[i];
240 _sub.push_back(callback_descr(func, offs, current));
242
244 gsw_add_process(_wbd, getpid());
245}
246
247struct callback_helper
248{
251 int offs, curr;
253
254 callback_helper(Whiteboard *s, gu_simple_whiteboard *w, int o, int c, const Whiteboard::callback_descr &d): self(s), wb(w), offs(o), curr(c), descr(d) {}
255};
256
257static void do_callback(void *m)
258{
259 callback_helper *h = static_cast<callback_helper *>(m);
260
261 WBMsg msg = h->self->getWBMsg(&h->wb->messages[h->offs][h->curr]);
262 h->descr.func->call(h->wb->typenames[h->offs].hash.string, &msg);
263
264 delete h;
265}
266
268{
271 for (vector<callback_descr>::iterator i = _sub.begin(); i != _sub.end(); i++)
272 {
273 callback_descr &descr = *i;
274 int offs = descr.type;
275 int curr = descr.current;
276 /*
277 * offs == -1 means all types "*", otherwise only check
278 * new postings for a specific message type
279 */
280 if (offs == -1) for (offs = 0; offs < wb->num_types; offs++)
281 {
282 curr = cball_indexes[offs];
283 while (curr != wb->indexes[offs]) // every new message
284 {
286 curr = 0;
287 cball_indexes[offs] = static_cast<uint8_t>(curr);
288 callback_helper *h = new callback_helper(this, wb, offs, curr, descr);
289 dispatch_group_async_f(callback_group, callback_queue, h, do_callback);
290 }
291 }
292 else while (curr != wb->indexes[offs]) // for every new message
293 {
295 curr = 0;
296 descr.current = curr;
297 callback_helper *h = new callback_helper(this, wb, offs, curr, descr);
298 dispatch_group_async_f(callback_group, callback_queue, h, do_callback);
299 }
300 }
302}
303
304
306{
308
310 for (vector<callback_descr>::iterator i = _sub.begin(); i != _sub.end(); i++)
311 {
312 callback_descr &descr = *i;
313 int offs = descr.type;
314 if ((offs == -1 && hashinfo->msg_offset == GLOBAL_MSG_ID) ||
315 hashinfo->msg_offset == offs)
316 {
317 _sub.erase(i);
318 result = Whiteboard::METHOD_OK;
319 break;
320 }
321 }
322 if (!_sub.size()) gsw_remove_process(_wbd, getpid());
324}
325
326#pragma mark - functions NOT using hash container
327
328void Whiteboard::addMessage(const std::string &type, const WBMsg &msg, bool nonatomic, bool notifySubscribers)
329{
330 gsw_hash_info tmp = gsw_hash_info(getTypeOffset_private(type.c_str()));
331 addMessage(&tmp, msg, nonatomic, notifySubscribers);
332}
333
335{
336 gsw_hash_info tmp = gsw_hash_info(getTypeOffset_private(type.c_str()));
337 return getMessage(&tmp, result);
338}
339
340void Whiteboard::subscribeToMessage(const string &type, WBFunctorBase *func, WBResult &result)
341{
342 gsw_hash_info tmp = gsw_hash_info(getTypeOffset_private(type.c_str()));
343 return subscribeToMessage(&tmp, func, result);
344}
345
347{
348 gsw_hash_info tmp = gsw_hash_info(getTypeOffset_private(type.c_str()));
349 return unsubscribeToMessage(&tmp, result);
350}
351
352#pragma clang diagnostic pop
353
#define DISPATCH_QUEUE_SERIAL
Definition: Whiteboard.cc:69
const char * gsw_global_whiteboard_name
global whiteboard name
Definition: Whiteboard.cc:78
#define init_ios_whiteboard_name()
Definition: Whiteboard.cc:77
#define GLOBAL_MSG_ID
Definition: Whiteboard.h:95
Base class for WBFunctor.
Definition: WBFunctor.h:41
virtual void call(std::string s, WBMsg *m)=0
Call method for the OLD whiteboard callbacks that used WBMsg - Deprecated.
Old WB class for storing shared data.
Definition: WBMsg.h:86
const std::string & getStringValue() const
getStringValue.
Definition: WBMsg.h:379
int getIntValue() const
getIntValue.
Definition: WBMsg.h:365
const std::vector< int > & getArrayValue() const
getArrayValue.
Definition: WBMsg.h:393
@ TypeEmpty
Definition: WBMsg.h:100
@ TypeString
Definition: WBMsg.h:97
@ TypeBinary
Definition: WBMsg.h:99
@ TypeFloat
Definition: WBMsg.h:96
@ TypeBool
Definition: WBMsg.h:94
@ TypeArray
Definition: WBMsg.h:98
@ TypeInt
Definition: WBMsg.h:95
float getFloatValue() const
getFloatValue.
Definition: WBMsg.h:372
WBType getType() const
getType.
Definition: WBMsg.h:199
const void * getBinaryValue() const
getBinaryValue.
Definition: WBMsg.h:386
int getSizeInBytes() const
getSizeInBytes.
Definition: WBMsg.h:400
bool getBoolValue() const
getBoolValue.
Definition: WBMsg.h:358
compatibility API for accessing the whiteboard
Definition: Whiteboard.h:116
WBMsg getMessage(gsw_hash_info *hashinfo, WBResult *result=NULLPTR)
Get Message Gets a message from a simple whiteboard.
Definition: Whiteboard.cc:194
void unsubscribeToMessage(gsw_hash_info *hashinfo, WBResult &result)
Unsubscribe To Message (sic!) Unsubscribes from a message type on a whiteboard or whiteboards.
Definition: Whiteboard.cc:305
gu_simple_whiteboard_descriptor * _wbd
underlying whiteboard
Definition: Whiteboard.h:136
virtual void subscribeToMessage(gsw_hash_info *hashinfo, WBFunctorBase *func, WBResult &result)
Subscribe To Message Subscribes to a message type on a whiteboard or whiteboards.
Definition: Whiteboard.cc:227
static WBMsg getWBMsg(gu_simple_message *m)
convert the new 'simple' whiteboard data structure into the old WBMsg format
Definition: Whiteboard.h:213
gsw_hash_info * getTypeOffset(std::string type)
create a hash offset from message type, needed for adding, getting from WB
Definition: Whiteboard.cc:210
@ METHOD_OK
No errors detected.
Definition: Whiteboard.h:168
@ METHOD_FAIL
Errors detected.
Definition: Whiteboard.h:169
void addMessage(gsw_hash_info *hashinfo, const WBMsg &msg, bool nonatomic=false, bool notifySubscribers=true)
Add Message Adds a message to the whiteboard that the API is connected to.
Definition: Whiteboard.cc:130
enum guWhiteboard::Whiteboard::wb_method_result WBResult
Return Type Enum.
void subscriptionCallback(void)
subscription callback: not really public!
Definition: Whiteboard.cc:267
virtual ~Whiteboard()
Destructor.
Definition: Whiteboard.cc:119
gu_simple_message * gsw_next_message(gu_simple_whiteboard *wb, int i)
get the next shared memory location for the given whiteboard message type i
void gsw_add_wbd_signal_handler(gu_simple_whiteboard_descriptor *wbd)
add subscription signal handler
void gsw_free_whiteboard(gu_simple_whiteboard_descriptor *wbd)
free the given whiteboard descriptor
void gsw_increment(gu_simple_whiteboard *wb, int i)
get the next shared memory location for the given whiteboard message type i
void gsw_increment_event_counter(gu_simple_whiteboard *wb, int i)
add to a messages event counter on the wb
gu_simple_message * gsw_current_message(gu_simple_whiteboard *wb, int i)
get the current shared memory location for the given whiteboard message type i
int gsw_procure(gsw_sema_t sem, enum gsw_semaphores s)
grab a whiteboard semaphore
int gsw_offset_for_message_type(gu_simple_whiteboard_descriptor *wbd, const char *name)
get the numerical index of a whiteboard message type
gu_simple_whiteboard_descriptor * gsw_new_numbered_whiteboard(const char *name, int n)
access a named whiteboard: this is the designated standard wb constructor for C programs that want to...
void gsw_remove_process(gu_simple_whiteboard_descriptor *wbd, const pid_t proc)
remove process for subscription signalling
int gsw_vacate(gsw_sema_t sem, enum gsw_semaphores s)
release a whiteboard semaphore
void gsw_add_process(gu_simple_whiteboard_descriptor *wbd, const pid_t proc)
add process for subscription signalling
void gsw_signal_subscribers(gu_simple_whiteboard *wb)
signal all subscribing processes
#define GU_SIMPLE_WHITEBOARD_GENERATIONS
lifespan (max)
const char ** WBTypes_stringValues
allow whiteboard to use old functions for whiteboard initialisation and choose which messages and con...
#define GSW_NUM_TYPES_DEFINED
allow whiteboard to use old functions for whiteboard initialisation and choose which messages and con...
@ GSW_SEM_CALLBACK
semaphore for callback data
@ GSW_SEM_PUTMSG
semaphore for adding to the whiteboard
/file APM_Interface.h
struct guWhiteboard::gsw_hash_info gsw_hash_info
Message offset holder.
An internal stuct for passing callback information to dispatch queues.
Whiteboard * self
Definition: Whiteboard.cc:249
callback_helper(Whiteboard *s, gu_simple_whiteboard *w, int o, int c, const Whiteboard::callback_descr &d)
Definition: Whiteboard.cc:254
int offs
type offset in shared memory, aka type enum value
gu_simple_whiteboard * wb
wb pointer
Whiteboard::callback_descr descr
Definition: Whiteboard.cc:252
the actual whiteboard in shared mem
gu_simple_message typenames[512]
message types for numbers
uint8_t indexes[512]
ring buffer indexes
uint16_t num_types
total number of current, registered types
gu_simple_message messages[512][4]
the actual messages stored in the whiteboard
uint16_t subscribed
subscribed processes
the underlying whiteboard object
gsw_subscription_f callback
subscription callback function
void * context
callback context
gsw_sema_t sem
semaphore to use
gu_simple_whiteboard * wb
the actual whiteboard in shared mem
WBFunctorBase * func
functor to call
Definition: Whiteboard.h:122
Message offset holder.
Definition: Whiteboard.h:104
int msg_offset
the index value to store
Definition: Whiteboard.h:109
union type that is used to store data in shared memory
float sfloat
signed float
char string[128]
string type
struct gsw_simple_message::@3 hash
whiteboard hash type
int ivec[128/sizeof(int)]
int array
struct gsw_simple_message::@4 wbmsg
compatibility WBMsg type
int sint
signed integer