CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
Subscriptions.cpp
Go to the documentation of this file.
1
6#include "Subscriptions.h"
7#include "PsyTime.h"
8#include "UnitTestFramework.h"
9
10namespace cmlabs {
11
12
14 if (!name || !strlen(name) || !retrieveCount)
15 return NULL;
16
17 RetrieveSpec* spec = (RetrieveSpec*) (((char*)this) +
18 sizeof(TriggerSpec) + (filterCount*sizeof(FilterSpec)));
19
20 uint32 n = 0;
21 for (n = 0; n < retrieveCount; n++) {
22 if (stricmp(name, spec->name) == 0)
23 return spec;
24 spec++;
25 }
26 return NULL;
27}
28
30 if (!name || !strlen(name) || !queryCount)
31 return NULL;
32
33 QuerySpec* spec = (QuerySpec*) (((char*)this) +
34 sizeof(TriggerSpec) + (filterCount*sizeof(FilterSpec)) +
35 (retrieveCount*sizeof(RetrieveSpec)));
36
37 uint32 n = 0;
38 for (n = 0; n < queryCount; n++) {
39 if (stricmp(name, spec->name) == 0)
40 return spec;
41 spec++;
42 }
43 return NULL;
44}
45
46std::list<PostSpec*>* TriggerSpec::getPostSpecs(const char* name) {
47 std::list<PostSpec*>* postSpecs = new std::list<PostSpec*>;
48 uint32 n = 0;
49 PostSpec* spec = (PostSpec*) (((char*)this) +
50 sizeof(TriggerSpec) +
51 (filterCount*sizeof(FilterSpec)) +
52 (retrieveCount*sizeof(RetrieveSpec)) +
53 (queryCount*sizeof(QuerySpec)));
54
55 for (n = 0; n < postCount; n++) {
56 if (!name || !strlen(name) || stricmp(name, spec->name) == 0)
57 postSpecs->push_back(spec);
58 spec++;
59 }
60 return postSpecs;
61}
62
63std::list<PostSpec*>* TriggerSpec::getPostSpecs(PsyType type) {
64 std::list<PostSpec*>* postSpecs = new std::list<PostSpec*>;
65 if (!type.isValid())
66 return postSpecs;
67 uint32 n = 0;
68 PostSpec* spec = (PostSpec*) (((char*)this) +
69 sizeof(TriggerSpec) +
70 (filterCount*sizeof(FilterSpec)) +
71 (retrieveCount*sizeof(RetrieveSpec)) +
72 (queryCount*sizeof(QuerySpec)));
73
74 for (n = 0; n < postCount; n++) {
75 if (type.matches(spec->type))
76 postSpecs->push_back(spec);
77 spec++;
78 }
79 return postSpecs;
80}
81
83 uint32 n = 0;
84 PostSpec* spec = (PostSpec*) (((char*)this) +
85 sizeof(TriggerSpec) +
86 (filterCount*sizeof(FilterSpec)) +
87 (retrieveCount*sizeof(RetrieveSpec)) +
88 (queryCount*sizeof(QuerySpec)));
89
90 for (n = 0; n < postCount; n++) {
91 if (stricmp(name, spec->name) == 0)
92 return spec;
93 spec++;
94 }
95 return NULL;
96}
97
98
100
101 if (!type.isValid())
102 return NULL;
103
104 uint32 n = 0;
105 PostSpec* spec = (PostSpec*) (((char*)this) +
106 sizeof(TriggerSpec) +
107 (filterCount*sizeof(FilterSpec)) +
108 (retrieveCount*sizeof(RetrieveSpec)) +
109 (queryCount*sizeof(QuerySpec)));
110
111 for (n = 0; n < postCount; n++) {
112 if (type.matches(spec->type))
113 return spec;
114 spec++;
115 }
116 return NULL;
117}
118
120 uint32 n = 0;
121 SignalSpec* spec = (SignalSpec*) (((char*)this) +
122 sizeof(TriggerSpec) +
123 (filterCount*sizeof(FilterSpec)) +
124 (retrieveCount*sizeof(RetrieveSpec)) +
125 (queryCount*sizeof(QuerySpec)) +
126 (postCount*sizeof(PostSpec)));
127
128 for (n = 0; n < signalCount; n++) {
129 if (stricmp(name, spec->name) == 0)
130 return spec;
131 spec++;
132 }
133 return NULL;
134}
135
136
138
139 if (!type.isValid())
140 return NULL;
141
142 uint32 n = 0;
143 SignalSpec* spec = (SignalSpec*) (((char*)this) +
144 sizeof(TriggerSpec) +
145 (filterCount*sizeof(FilterSpec)) +
146 (retrieveCount*sizeof(RetrieveSpec)) +
147 (queryCount*sizeof(QuerySpec)) +
148 (postCount*sizeof(PostSpec)));
149
150 for (n = 0; n < signalCount; n++) {
151 if (type.matches(spec->type))
152 return spec;
153 spec++;
154 }
155 return NULL;
156}
157
158
159
160std::string TriggerSpec::toXML() {
161 uint32 n;
162 std::string str = utils::StringFormat("<trigger name=\"%s\" type=\"%s\" compid=\"%u\" interval=\"%u\" delay=\"%u\" from=\"%u\" to=\"%u\" tag=\"%u\" filtercount=\"%u\" signalcount=\"%u\" postcount=\"%u\" context=\"%s\" triggercontext=\"%s\"",
163 name, type.toString().c_str(), componentID, interval, delay, from, to, tag, filterCount, signalCount, postCount, context.toString().c_str(), triggerContext.toString().c_str());
164
166 str += " />\n";
167 return str;
168 }
169 else
170 str += ">\n";
171
172 for (n=0; n<retrieveCount; n++) {
173 RetrieveSpec* rSpec = getRetrieveSpec(n);
174 if (rSpec)
175 str += rSpec->toXML();
176 }
177
178 for (n=0; n<signalCount; n++) {
179 SignalSpec* sSpec = getSignalSpec(n);
180 if (sSpec)
181 str += sSpec->toXML();
182 }
183
184 for (n=0; n<queryCount; n++) {
185 QuerySpec* qSpec = getQuerySpec(n);
186 if (qSpec)
187 str += qSpec->toXML();
188 }
189
190 for (n=0; n<postCount; n++) {
191 PostSpec* pSpec = getPostSpec(n);
192 if (pSpec)
193 str += pSpec->toXML();
194 }
195
196 str += "</trigger>\n";
197 return str;
198
199}
200
201
202// ################# Unit test #################
203
205
206 // A TriggerSpec is a variable-length packed structure: a fixed header
207 // followed by filterCount FilterSpecs, retrieveCount RetrieveSpecs,
208 // queryCount QuerySpecs, postCount PostSpecs and signalCount SignalSpecs.
209 // We build one in a flat buffer, populate the sub-specs, then exercise the
210 // index / name / type accessors and the XML serialisation.
211
212 // 1. FilterSpec / RetrieveSpec / QuerySpec / PostSpec / SignalSpec XML round-trip
213 unittest::progress(10, "spec XML round-trip");
214 {
215 FilterSpec f;
216 memset(&f, 0, sizeof(FilterSpec));
218 f.time = 123ULL;
219 utils::strcpyavail(f.key, "fkey", MAXKEYNAMELEN, true);
220 utils::strcpyavail(f.value, "fval", MAXVALUENAMELEN, true);
221 std::string fxml = f.toXML();
222 if (fxml.empty()) { unittest::fail("Subscriptions test: FilterSpec toXML empty\n"); return false; }
223 FilterSpec f2;
224 memset(&f2, 0, sizeof(FilterSpec));
225 if (!f2.fromXML(fxml.c_str())) { unittest::fail("Subscriptions test: FilterSpec fromXML failed\n"); return false; }
226 if (f2.filter != f.filter || f2.time != f.time ||
227 strcmp(f2.key, "fkey") != 0 || strcmp(f2.value, "fval") != 0) {
228 unittest::fail("Subscriptions test: FilterSpec round-trip mismatch\n"); return false;
229 }
230
231 SignalSpec s;
232 memset(&s, 0, sizeof(SignalSpec));
233 s.type.fromString("3.4");
234 utils::strcpyavail(s.name, "sig", MAXKEYNAMELEN, true);
235 std::string sxml = s.toXML();
236 if (sxml.empty()) { unittest::fail("Subscriptions test: SignalSpec toXML empty\n"); return false; }
237 SignalSpec s2;
238 memset(&s2, 0, sizeof(SignalSpec));
239 if (!s2.fromXML(sxml.c_str())) { unittest::fail("Subscriptions test: SignalSpec fromXML failed\n"); return false; }
240 if (strcmp(s2.name, "sig") != 0 || s2.type != s.type) {
241 unittest::fail("Subscriptions test: SignalSpec round-trip mismatch\n"); return false;
242 }
243 }
244
245 // 2. PostSpec content build + addContentToMsg
246 unittest::progress(25, "post content -> message");
247 {
248 PostSpec p;
249 memset(&p, 0, sizeof(PostSpec));
250 p.to = 7;
251 p.type.fromString("1.2.3");
252 utils::strcpyavail(p.name, "post1", MAXKEYNAMELEN, true);
253 // content layout: ||<type>||<key>||<value>... with contentCount entries
254 utils::strcpyavail(p.content, "||S||s_key||s_val||I||i_key||42||F||f_key||1.5", MAXCONTENTLEN, true);
255 p.contentCount = 3;
256
257 std::string pxml = p.toXML();
258 if (pxml.empty() || pxml.find("post1") == std::string::npos) {
259 unittest::fail("Subscriptions test: PostSpec toXML missing name\n"); return false;
260 }
261
262 DataMessage msg(CTRL_TEST, 0);
263 uint32 added = p.addContentToMsg(&msg);
264 if (added != 3) { unittest::fail("Subscriptions test: addContentToMsg count != 3\n"); return false; }
265 if (msg.getAsString("s_key") != "s_val") { unittest::fail("Subscriptions test: addContentToMsg string mismatch\n"); return false; }
266 int64 iv = 0;
267 if (!msg.getInt("i_key", iv) || iv != 42) { unittest::fail("Subscriptions test: addContentToMsg int mismatch\n"); return false; }
268 double dv = 0;
269 if (!msg.getDouble("f_key", dv) || dv < 1.4 || dv > 1.6) { unittest::fail("Subscriptions test: addContentToMsg float mismatch\n"); return false; }
270 }
271
272 // 3. Build a packed TriggerSpec and exercise the accessors
273 unittest::progress(45, "packed trigger accessors");
274 {
275 const uint16 nFilter = 1;
276 const uint16 nRetrieve = 1;
277 const uint16 nQuery = 1;
278 const uint16 nPost = 2;
279 const uint16 nSignal = 2;
280
281 uint32 total = sizeof(TriggerSpec)
282 + nFilter * sizeof(FilterSpec)
283 + nRetrieve * sizeof(RetrieveSpec)
284 + nQuery * sizeof(QuerySpec)
285 + nPost * sizeof(PostSpec)
286 + nSignal * sizeof(SignalSpec);
287
288 char* buf = (char*)malloc(total);
289 if (!buf) { unittest::fail("Subscriptions test: malloc failed\n"); return false; }
290 memset(buf, 0, total);
291
292 TriggerSpec* trig = (TriggerSpec*)buf;
293 trig->reset(total);
294 trig->id = 99;
295 trig->componentID = 5;
296 trig->type.fromString("10.20");
297 utils::strcpyavail(trig->name, "mytrigger", MAXKEYNAMELEN, true);
298 trig->filterCount = nFilter;
299 trig->retrieveCount = nRetrieve;
300 trig->queryCount = nQuery;
301 trig->postCount = nPost;
302 trig->signalCount = nSignal;
303
304 // Populate sub-specs at the offsets the accessors expect.
305 FilterSpec* filt = (FilterSpec*)(buf + sizeof(TriggerSpec));
307 utils::strcpyavail(filt[0].key, "fk", MAXKEYNAMELEN, true);
308
309 RetrieveSpec* ret = (RetrieveSpec*)((char*)filt + nFilter * sizeof(FilterSpec));
310 utils::strcpyavail(ret[0].name, "ret1", MAXKEYNAMELEN, true);
311
312 QuerySpec* qry = (QuerySpec*)((char*)ret + nRetrieve * sizeof(RetrieveSpec));
313 utils::strcpyavail(qry[0].name, "qry1", MAXKEYNAMELEN, true);
314
315 PostSpec* posts = (PostSpec*)((char*)qry + nQuery * sizeof(QuerySpec));
316 utils::strcpyavail(posts[0].name, "postA", MAXKEYNAMELEN, true);
317 posts[0].type.fromString("1.2");
318 utils::strcpyavail(posts[1].name, "postB", MAXKEYNAMELEN, true);
319 posts[1].type.fromString("1.3");
320
321 SignalSpec* sigs = (SignalSpec*)((char*)posts + nPost * sizeof(PostSpec));
322 utils::strcpyavail(sigs[0].name, "sigA", MAXKEYNAMELEN, true);
323 sigs[0].type.fromString("4.5");
324 utils::strcpyavail(sigs[1].name, "sigB", MAXKEYNAMELEN, true);
325 sigs[1].type.fromString("4.6");
326
327 // --- index accessors return the same pointers we wrote ---
328 if (trig->getRetrieveSpec((uint32)0) != ret) { unittest::fail("Subscriptions test: getRetrieveSpec(0) wrong ptr\n"); free(buf); return false; }
329 if (trig->getQuerySpec((uint32)0) != qry) { unittest::fail("Subscriptions test: getQuerySpec(0) wrong ptr\n"); free(buf); return false; }
330 if (trig->getPostSpec((uint32)0) != &posts[0]) { unittest::fail("Subscriptions test: getPostSpec(0) wrong ptr\n"); free(buf); return false; }
331 if (trig->getPostSpec((uint32)1) != &posts[1]) { unittest::fail("Subscriptions test: getPostSpec(1) wrong ptr\n"); free(buf); return false; }
332 if (trig->getSignalSpec((uint32)0) != &sigs[0]) { unittest::fail("Subscriptions test: getSignalSpec(0) wrong ptr\n"); free(buf); return false; }
333 if (trig->getSignalSpec((uint32)1) != &sigs[1]) { unittest::fail("Subscriptions test: getSignalSpec(1) wrong ptr\n"); free(buf); return false; }
334
335 // --- out-of-range index returns NULL ---
336 if (trig->getRetrieveSpec(nRetrieve) != NULL) { unittest::fail("Subscriptions test: getRetrieveSpec out-of-range not NULL\n"); free(buf); return false; }
337 if (trig->getQuerySpec(nQuery) != NULL) { unittest::fail("Subscriptions test: getQuerySpec out-of-range not NULL\n"); free(buf); return false; }
338 if (trig->getPostSpec(nPost) != NULL) { unittest::fail("Subscriptions test: getPostSpec out-of-range not NULL\n"); free(buf); return false; }
339 if (trig->getSignalSpec(nSignal) != NULL) { unittest::fail("Subscriptions test: getSignalSpec out-of-range not NULL\n"); free(buf); return false; }
340
341 // --- name accessors ---
342 if (trig->getRetrieveSpec("ret1") != ret) { unittest::fail("Subscriptions test: getRetrieveSpec(name) miss\n"); free(buf); return false; }
343 if (trig->getRetrieveSpec("nope") != NULL) { unittest::fail("Subscriptions test: getRetrieveSpec(bad name) not NULL\n"); free(buf); return false; }
344 if (trig->getQuerySpec("qry1") != qry) { unittest::fail("Subscriptions test: getQuerySpec(name) miss\n"); free(buf); return false; }
345 if (trig->getQuerySpec("nope") != NULL) { unittest::fail("Subscriptions test: getQuerySpec(bad name) not NULL\n"); free(buf); return false; }
346 if (trig->getPostSpec("postB") != &posts[1]) { unittest::fail("Subscriptions test: getPostSpec(name) miss\n"); free(buf); return false; }
347 if (trig->getPostSpec("nope") != NULL) { unittest::fail("Subscriptions test: getPostSpec(bad name) not NULL\n"); free(buf); return false; }
348 if (trig->getSignalSpec("sigA") != &sigs[0]) { unittest::fail("Subscriptions test: getSignalSpec(name) miss\n"); free(buf); return false; }
349 if (trig->getSignalSpec("nope") != NULL) { unittest::fail("Subscriptions test: getSignalSpec(bad name) not NULL\n"); free(buf); return false; }
350 // name lookup is case-insensitive (stricmp)
351 if (trig->getPostSpec("POSTA") != &posts[0]) { unittest::fail("Subscriptions test: getPostSpec name not case-insensitive\n"); free(buf); return false; }
352
353 // --- type accessors (PsyType::matches) ---
354 PsyType t12; t12.fromString("1.2");
355 PsyType t13; t13.fromString("1.3");
356 PsyType t99; t99.fromString("9.9");
357 if (trig->getPostSpec(t12) != &posts[0]) { unittest::fail("Subscriptions test: getPostSpec(type 1.2) miss\n"); free(buf); return false; }
358 if (trig->getPostSpec(t13) != &posts[1]) { unittest::fail("Subscriptions test: getPostSpec(type 1.3) miss\n"); free(buf); return false; }
359 if (trig->getPostSpec(t99) != NULL) { unittest::fail("Subscriptions test: getPostSpec(type 9.9) not NULL\n"); free(buf); return false; }
360 PsyType t45; t45.fromString("4.5");
361 if (trig->getSignalSpec(t45) != &sigs[0]) { unittest::fail("Subscriptions test: getSignalSpec(type 4.5) miss\n"); free(buf); return false; }
362
363 // --- getPostSpecs list variants ---
364 std::list<PostSpec*>* all = trig->getPostSpecs((const char*)NULL);
365 if (!all || all->size() != nPost) { unittest::fail("Subscriptions test: getPostSpecs(NULL) wrong count\n"); delete all; free(buf); return false; }
366 delete all;
367
368 std::list<PostSpec*>* named = trig->getPostSpecs("postA");
369 if (!named || named->size() != 1 || named->front() != &posts[0]) {
370 unittest::fail("Subscriptions test: getPostSpecs(name) wrong\n"); delete named; free(buf); return false;
371 }
372 delete named;
373
374 // wildcard match in PsyType: a post whose type matches 0xFFFF wildcard
375 PsyType wild; wild.fromString("1");
376 wild.setLevel(1, 0xFFFF); // 1.* matches both 1.2 and 1.3
377 std::list<PostSpec*>* byType = trig->getPostSpecs(wild);
378 if (!byType || byType->size() != 2) {
379 unittest::fail("Subscriptions test: getPostSpecs(wildcard type) wrong count\n"); delete byType; free(buf); return false;
380 }
381 delete byType;
382
383 // --- toXML produces a self-describing trigger document ---
384 std::string xml = trig->toXML();
385 if (xml.empty() || xml.find("mytrigger") == std::string::npos) {
386 unittest::fail("Subscriptions test: TriggerSpec toXML missing name\n"); free(buf); return false;
387 }
388 if (xml.find("postA") == std::string::npos || xml.find("sigA") == std::string::npos) {
389 unittest::fail("Subscriptions test: TriggerSpec toXML missing sub-specs\n"); free(buf); return false;
390 }
391
392 // --- lookup throughput metric ---
393 unittest::progress(80, "lookup throughput");
394 const uint32 iterations = 200000;
395 uint64 t0 = GetTimeNow();
396 volatile uint64 sink = 0;
397 for (uint32 i = 0; i < iterations; i++) {
398 if (trig->getPostSpec("postB")) sink++;
399 if (trig->getSignalSpec("sigB")) sink++;
400 }
401 double us = (double)(GetTimeNow() - t0);
402 if (us > 0.0)
403 unittest::metric("name_lookup", (double)(iterations * 2) / us * 1e6, "ops/s", true);
404 unittest::detail("trigger name lookups: %u in %.0f us\n", iterations * 2, us);
405
406 free(buf);
407 }
408
409 unittest::progress(100, "done");
410 return true;
411}
412
415 "Trigger/filter/retrieve/query/post/signal spec lookup and XML", "core");
416}
417
418} // namespace cmlabs
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
Subscription, trigger, retrieval, query, post and signal specifications — the declarative wiring of a...
#define TRIGGERFILTER_EQUALS
String equality between entry value and filter value.
#define TRIGGERFILTER_HASKEY
Fire only if the message has the named key.
Small, dependency-free unit test harness used by all CMSDK object tests.
#define MAXKEYNAMELEN
Definition Utils.h:85
#define stricmp
Definition Utils.h:132
#define MAXCONTENTLEN
Definition Utils.h:87
#define MAXVALUENAMELEN
Definition Utils.h:86
The central Psyclone data container: a self-contained binary message with typed, named user entries.
bool getDouble(const char *key, double &value)
getDouble(const char* key, double& value)
bool getInt(const char *key, int64 &value)
getInt(const char* key, int64& value)
std::string getAsString(const char *key)
getAsString(const char* key)
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:6626
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:6056
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
static struct PsyType CTRL_TEST
Definition ObjectIDs.h:82
void Register_Subscriptions_Tests()
Hierarchical message type identifier — the key used for publish/subscribe matching in Psyclone.
Definition Types.h:123
bool fromString(const char *text)
Parse dotted decimal notation (e.g.
Definition Types.h:233
bool setLevel(int i, uint16 value)
Set an individual hierarchy level.
Definition Types.h:163
One filter condition attached to a TriggerSpec: a test on a user entry of the candidate message.
char key[MAXKEYNAMELEN+1]
Name of the user entry to test.
char value[MAXVALUENAMELEN+1]
Comparison operand as text (parsed numerically for the numeric operations).
std::string toXML()
Serialise as a <filter .../> XML element.
bool fromXML(const char *xml)
Parse from an XML string containing a <filter .../> element.
uint8 filter
Filter operation, one of the TRIGGERFILTER_... codes.
uint64 time
Time operand in microseconds (used by TRIGGERFILTER_MAXAGE).
Specification of a message to post when a trigger fires (or a crank completes).
PsyType type
Type of the posted message.
uint32 addContentToMsg(DataMessage *msg)
Unpack the inline content entries into msg as typed user entries.
char name[MAXKEYNAMELEN+1]
Name of this post spec.
uint32 contentCount
Number of inline content entries packed into content.
char content[MAXCONTENTLEN+1]
Packed content entries: "||T||key||value" repeated (T = S, I or F).
uint32 to
Addressee component id (0 = publish to subscribers).
std::string toXML()
Serialise as a <post ...>...</post> XML element including content children.
Specification of a query against a catalog/service/feed, attached to a TriggerSpec.
char name[MAXKEYNAMELEN+1]
Name of this query, used to reference its results in the crank.
std::string toXML()
Serialise as a <query .../> XML element.
Specification of a whiteboard retrieval attached to a TriggerSpec.
char name[MAXKEYNAMELEN+1]
Name of this retrieve, used to reference its results in the crank.
std::string toXML()
Serialise as a <retrieve .../> XML element.
Specification of a signal (a typed notification without payload) emitted when a trigger fires.
PsyType type
Type of the signal to emit.
bool fromXML(const char *xml)
Parse from an XML string containing a <signal .../> element.
std::string toXML()
Serialise as a <signal .../> XML element.
char name[MAXKEYNAMELEN+1]
Name of this signal spec.
A complete trigger definition: what fires a component's crank and what happens then.
uint16 signalCount
Number of SignalSpecs in the tail.
uint16 filterCount
Number of FilterSpecs in the tail.
uint32 id
Unique id of this trigger.
uint32 tag
Only messages with this tag fire the trigger (0 = any).
PsyContext context
Context in which the trigger is active.
RetrieveSpec * getRetrieveSpec(uint32 n)
uint32 from
Only messages sent by this component id fire the trigger (0 = any).
PostSpec * getPostSpec(const char *name)
uint32 interval
Periodic trigger interval in ms (0 = message-triggered only).
bool reset(uint32 s=0)
Zero the header and stamp size/cid.
uint32 delay
Delay in ms between trigger match and crank execution.
uint16 queryCount
Number of QuerySpecs in the tail.
std::list< PostSpec * > * getPostSpecs(const char *name)
PsyContext triggerContext
Context the triggering message must match.
char name[MAXKEYNAMELEN+1]
Trigger name.
QuerySpec * getQuerySpec(uint32 n)
PsyType type
Message type that fires the trigger (wildcards allowed).
std::string toXML()
Serialise the whole trigger (with all attached specs) as XML.
uint16 postCount
Number of PostSpecs in the tail.
uint16 retrieveCount
Number of RetrieveSpecs in the tail.
static bool UnitTest()
Run the built-in self test.
uint32 componentID
Id of the component owning the trigger.
uint32 to
Only messages addressed to this component id fire the trigger (0 = any).
SignalSpec * getSignalSpec(const char *name)