18 const char* triggerName;
61 api->
logPrint(1,
"Posted %d output messages", c);
65 api->
logPrint(1,
"Posted one output message", c);
68 api->
logPrint(1,
"Posted no messages (%d)", c);
70 api->
logPrint(1,
"Posted no messages");
79 api->
logPrint(1,
"Started running (internal)...");
82 int64 counter = 0, start, end;
84 const char* triggerName;
89 double current, last = 0;
102 int64 totalMessageCount = cycles*count;
107 if ( (
stricmp(triggerName,
"Ready") == 0) || (
stricmp(triggerName,
"Start") == 0) ) {
108 api->
logPrint(1,
"Starting %u cycles test...", cycles);
114 else if (
stricmp(triggerName,
"Ball") == 0) {
119 else if (counter % totalMessageCount == 0) {
121 current = ((double)(end-start))/(modules*count);
123 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus...",
124 counter, current, ((
double)t/count));
125 else if (last > current)
126 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus (%.1fus faster)...",
127 counter, current, ((
double)t/count), last-current);
129 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus (%.1fus slower)...",
130 counter, current, ((
double)t/count), current-last);
134 else if (counter % count == 0) {
136 current = ((double)(end-start))/(modules*count);
139 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus...",
140 counter, current, ((
double)t/count));
141 else if (last > current)
142 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus (%.1fus faster)...",
143 counter, current, ((
double)t/count), last-current);
145 api->
logPrint(1,
"Got msg %llu, avg msg time: %.1fus, avg msg age: %.1fus (%.1fus slower)...",
146 counter, current, ((
double)t/count), current-last);
170 api->
logPrint(1,
"Started running...");
172 const char* triggerName;
184 api->
logPrint(1,
"Started running...");
187 const char* triggerName;
201 api->
logPrint(1,
"Started running...");
204 const char* triggerName;
205 std::string userdata;
221 else if (userdata.length()) {
251 uint32 errorCount = 0;
255 const char* triggerName;
260 for (uint32 n=0; n<9; n++) {
262 for (uint32 m=0; m<1000; m++) {
263 var += sqrt((
double)m*m+1);
267 if ( (t < 0) || (t > 50) ) {
269 api->
logPrint(1,
"[%u] Timing error - %lld", errorCount, t, var);
278 const char* triggerName;
280 api->
logPrint(1,
"Started running...");
289 uint64 totalTime = 0;
293 if (
stricmp(triggerName,
"Start") == 0) {
294 api->
logPrint(1,
"Emitting signal [%u]...", count);
299 else if (inMsg = api->
waitForSignal(
"Input", 100, lastTime)) {
304 api->
logPrint(1,
"Got signal, average %.3fus [%u]...", ((
double)totalTime/count), count);
317 const char* triggerName;
319 api->
logPrint(1,
"Started running...");
327 else if (inMsg = api->
waitForSignal(
"Input", 100, lastTime)) {
345 api->
logPrint(1,
"Started running, %u steps...", steps);
349 const char* triggerName;
352 std::list<DataMessage*> retrievedMsgs;
353 std::list<DataMessage*>::iterator i, e;
357 if ( (
stricmp(triggerName,
"Ready") == 0) || (
stricmp(triggerName,
"Start") == 0) ) {
359 for (val = 0; val < 10; val++) {
361 outMsg->
setInt(
"count", val);
371 for (uint32 nn=0; nn<steps; nn++) {
372 status = api->
retrieve(retrievedMsgs,
"r1");
374 api->
logPrint(1,
"Successfully retrieved %u messages...", retrievedMsgs.size());
376 api->
logPrint(1,
"Retrieve 'r1' timed out...");
378 api->
logPrint(1,
"Retrieve 'r1' failed (%u)...", status);
380 for (i = retrievedMsgs.begin(), e = retrievedMsgs.end(); i != e; i++) {
385 retrievedMsgs.clear();
389 api->
logPrint(1,
"Successfully retrieved %u messages...", retrievedMsgs.size());
391 api->
logPrint(1,
"Retrieve 'r2' timed out...");
393 api->
logPrint(1,
"Retrieve 'r2' failed (%u)...", status);
395 for (i = retrievedMsgs.begin(), e = retrievedMsgs.end(); i != e; i++) {
400 retrievedMsgs.clear();
405 api->
logPrint(1,
"Successfully retrieved %u messages...", retrievedMsgs.size());
407 api->
logPrint(1,
"Retrieve 'r3' timed out...");
409 api->
logPrint(1,
"Retrieve 'r3' failed (%u)...", status);
411 for (i = retrievedMsgs.begin(), e = retrievedMsgs.end(); i != e; i++) {
416 retrievedMsgs.clear();
421 status = api->
queryCatalog(&result, datasize,
"MyFiles",
"test",
"read");
423 api->
logPrint(1,
"Successfully retrieved %u bytes from file catalog...", datasize);
425 api->
logPrint(1,
"Retrieve 'read' timed out for file catalog...");
427 api->
logPrint(1,
"Retrieve 'read' failed (%u) for file catalog...", status);
431 status = api->
queryCatalog(&result, datasize,
"MyFiles",
"test",
"write", data, datasize);
433 api->
logPrint(1,
"Successfully wrote %u bytes to file catalog...", datasize);
435 api->
logPrint(1,
"Retrieve 'write' timed out for file catalog...");
437 api->
logPrint(1,
"Retrieve 'write' failed (%u) for file catalog...", status);
441 status = api->
queryCatalog(&result, datasize,
"MyData",
"test",
"read");
443 api->
logPrint(1,
"Successfully read %u bytes from data catalog...", datasize);
445 api->
logPrint(1,
"Retrieve 'read' timed out from data catalog...");
447 api->
logPrint(1,
"Retrieve 'read' failed (%u) from data catalog, ok if starting with a fresh catalog ...", status);
451 status = api->
queryCatalog(&result, datasize,
"MyData",
"test",
"write", data, datasize);
453 api->
logPrint(1,
"Successfully wrote %u bytes to data catalog...", datasize);
455 api->
logPrint(1,
"Retrieve 'write' timed out to data catalog...");
457 api->
logPrint(1,
"Retrieve 'write' failed to data catalog (%u)...", status);
461 status = api->
queryCatalog(&result, datasize,
"MyData",
"test",
"read");
463 api->
logPrint(1,
"Successfully read %u bytes from data catalog...", datasize);
465 api->
logPrint(1,
"Retrieve 'read' timed out from data catalog...");
467 api->
logPrint(1,
"Retrieve 'read' failed (%u) from data catalog...", status);
487 if (!keytype || (
stricmp(
"String", keytype) == 0) || (
stricmp(
"Text", keytype) == 0))
489 else if ((
stricmp(
"Integer", keytype) == 0) || (
stricmp(
"Int", keytype) == 0))
491 else if ((
stricmp(
"Float", keytype) == 0) || (
stricmp(
"Double", keytype) == 0))
506 XMLNode entryNode, node, trackNode, mainNode = XMLNode::parseString(xml.c_str(),
"setup", &xmlResults);
512 api->
logPrint(0,
"Module setup error, main tag '<setup>' not found");
515 api->
logPrint(0,
"Module setup parsing error at line %i, column %i:\n %s\n",
521 uint64 lastTriggerTime = 0;
522 uint32 nextDelayEntry = 0;
523 uint32 globalIntervalMS = 0;
524 uint32 trackIntervalMS = 0;
525 std::string autoTrack;
527 std::map<std::string, std::vector<TrackPlayerMessage> > trackMap;
528 std::vector<TrackPlayerMessage>* trackEntries;
532 uint32 lastOffset = 0;
533 int n = 0, t = 0, m = 0;
534 const char* str, *postName, *key, *value, *keytype, *name, *output;
535 uint32 timeMS, intervalMS, delayMS;
544 while (!(node = mainNode.
getChildNode(
"post", n++)).isEmpty()) {
548 timeMS += lastOffset;
555 globalIntervalMS += timeMS;
556 api->
logPrint(1,
"Global track interval calculated: %ums", globalIntervalMS);
560 api->
logPrint(1,
"Global track interval: %ums", globalIntervalMS);
564 bool usingMainNode =
false;
565 if ((trackNode = mainNode.
getChildNode(
"track", t++)).isEmpty()) {
566 trackNode = mainNode;
567 usingMainNode =
true;
570 std::string trackName;
574 if (!(name = trackNode.
getAttribute(
"name")) || !strlen(name)) {
577 trackName =
"__default__";
578 api->
logPrint(1,
"Adding single global track (__default__)");
582 api->
logPrint(1,
"Adding track '%s'", trackName.c_str());
585 trackEntries = &trackMap[trackName];
588 autoTrack = trackName;
590 if (!usingMainNode && (str = trackNode.
getAttribute(
"intervalms"))) {
596 while (!(node = trackNode.
getChildNode(
"post", n++)).isEmpty()) {
600 timeMS += lastOffset;
607 trackIntervalMS += timeMS;
608 api->
logPrint(1,
"Track '%s' interval calculated: %ums", trackName.c_str(), trackIntervalMS);
612 api->
logPrint(1,
"Track '%s' interval: %ums", trackName.c_str(), trackIntervalMS);
618 while (!(node = trackNode.
getChildNode(
"post", n++)).isEmpty()) {
619 timeMS = intervalMS = delayMS = 0;
629 timeMS += lastOffset;
643 if (!intervalMS && trackIntervalMS)
644 intervalMS = trackIntervalMS;
645 if (!intervalMS && globalIntervalMS)
646 intervalMS = globalIntervalMS;
647 if (!timeMS && intervalMS)
654 entry.
nextTime = timeMS ? startTime + (timeMS * 1000) : 0;
656 entry.
postName = postName ? postName :
"";
659 if (output && (
stricmp(
"Signal", output) == 0)) {
660 if (!postName || !strlen(postName)) {
661 api->
logPrint(1,
"Signal posts must specify a signal name, ignoring post entry");
673 api->
logPrint(1,
"Trigger track '%s' cannot use time posts, ignoring time post entry", trackName.c_str());
675 api->
logPrint(1,
"Time track '%s' cannot use trigger posts, ignoring trigger post entry", trackName.c_str());
680 if (key && value && strlen(key) && strlen(value))
681 entry.
addEntry(key, value, keytype);
683 while (!(entryNode = node.
getChildNode(
"user", m++)).isEmpty()) {
689 if (key && value && strlen(key) && strlen(value))
690 entry.
addEntry(key, value, keytype);
692 trackEntries->push_back(entry);
694 api->
logPrint(1,
"Added %u posts to track '%s'", trackEntries->size(), trackName.c_str());
697 }
while (!trackNode.
isEmpty());
699 api->
logPrint(1,
"Added %u tracks in total", trackMap.size());
701 std::vector<TrackPlayerMessage>::iterator i, e;
702 std::map<std::string, TrackPlayerMessageEntry>::iterator iEntry, eEntry;
709 uint32 waitTime = 50;
711 const char* triggerName;
717 if (
stricmp(
"Start", triggerName) == 0) {
718 if (autoTrack.length()) {
719 trackEntries = &trackMap[autoTrack];
721 api->
logPrint(1,
"Auto starting track '%s'", autoTrack.c_str());
722 trackName = autoTrack;
729 else if (
stricmp(
"Restart", triggerName) == 0) {
733 i = trackEntries->begin();
734 e = trackEntries->end();
738 (*i).nextTime =
GetTimeNow() + ((*i).timeMS * 1000);
743 api->
logPrint(1,
"Auto starting track '%s'", autoTrack.c_str());
747 else if (trackMap.find(triggerName) != trackMap.end()) {
748 trackEntries = &trackMap[triggerName];
749 trackName = triggerName;
753 i = trackEntries->begin();
754 e = trackEntries->end();
758 (*i).nextTime =
GetTimeNow() + ((*i).timeMS * 1000);
765 if (!lastTriggerTime)
772 if (trackEntries && trackEntries->size()) {
774 i = trackEntries->begin();
775 if (i != trackEntries->end()) {
776 triggerType = (*i).triggerType;
781 entry = trackEntries->at(nextDelayEntry);
783 if (!nextDelayEntry) {
785 msg->
setString(
"Track", trackName.c_str());
791 while (iEntry != eEntry) {
792 if ((*iEntry).second.key.length() && (*iEntry).second.value.length()) {
798 msg->
setString((*iEntry).second.key.c_str(), (*iEntry).second.value.c_str());
818 api->
logPrint(1,
"Triggered all posts after delay of %ums", entry.
delayMS);
823 if (nextDelayEntry >= trackEntries->size()) {
825 msg->
setString(
"Track", trackName.c_str());
833 i = trackEntries->begin();
834 e = trackEntries->end();
837 if ((*i).nextTime && ((*i).nextTime < now)) {
840 msg->
setString(
"Track", trackName.c_str());
844 iEntry = (*i).entryMap.begin();
845 eEntry = (*i).entryMap.end();
846 while (iEntry != eEntry) {
847 if ((*iEntry).second.key.length() && (*iEntry).second.value.length()) {
853 msg->
setString((*iEntry).second.key.c_str(), (*iEntry).second.value.c_str());
858 if ((*i).postName.length()) {
862 if (!(*i).intervalMS)
871 if (!(*i).intervalMS)
882 if (!(*i).intervalMS)
890 if (!(*i).intervalMS)
893 (*i).nextTime += ((*i).intervalMS * 1000);
895 if (n == trackEntries->size()) {
897 msg->
setString(
"Track", trackName.c_str());
912 const char* triggerName;
915 std::list<DataMessage*> retrievedMsgs;
916 std::list<DataMessage*>::iterator i, e;
927 status = api->
queryCatalog(&resultMsg,
"Test", msg, 5000);
930 api->
logPrint(1,
"Successfully retrieved reply msg from catalog...");
932 api->
logPrint(1,
"Successfully got reply from catalog...");
935 api->
logPrint(1,
"Query timed out for catalog...");
937 api->
logPrint(1,
"Query failed (%u) for catalog...", status);
949 api->
logPrint(1,
"Started running...");
957 if (!outFile.length())
968 else if (shouldReplace) {
973 uint64 createdTime, sendTime, recvTime;
977 const char* triggerName;
987 recvTime - createdTime, recvTime - sendTime,
1008 api->
logPrint(1,
"Started running...");
1016 if (!updateIntervalMS)
1017 updateIntervalMS = 10000;
1022 std::vector<std::string> fileNames;
1025 for (n = 0; n<fileCount; n++) {
1028 fileNames.push_back(name);
1034 uint32 count, postCount = 0, currentNamePos = 0;
1037 const char* triggerName;
1042 if ((currentNamePos < fileNames.size()) && (
GetTimeAgeMS(lastPost) > intervalMS)) {
1043 name = fileNames[currentNamePos].c_str();
1045 bitmap =
new Bitmap(name);
1046 if (bitmap->
width > 0) {
1056 api->
logPrint(1,
"File '%s' isn't a valid BMP file", name);
1061 api->
logPrint(1,
"File '%s' doesn't exist", name);
1064 if ((currentNamePos >= fileNames.size()) && shouldRotate)
1071 if (count != fileCount) {
1072 api->
logPrint(1,
"File changes detected in '%s', updating list of files and starting over", sourceDir.c_str());
1074 for (n = 0; n<count; n++) {
1077 fileNames.push_back(name);
1094 if (!defaultState.length())
1095 defaultState = overrideState;
1096 std::string currentState = defaultState;
1098 if (!switchKey.length()) {
1099 api->
logPrint(1,
"No SwitchKey parameter provided, cannot proceed without it");
1104 const char* triggerName, *newState;
1105 std::string postName;
1109 if (
stricmp(triggerName,
"Ready") == 0) {
1110 if (defaultState.length()) {
1119 else if (
stricmp(triggerName,
"SwitchMessage") == 0) {
1120 if ((newState = inMsg->
getString(switchKey.c_str())) != 0) {
1121 if (!strlen(newState)) {
1122 currentState.clear();
1126 else if (
stricmp(currentState.c_str(), newState) != 0) {
1127 currentState = newState;
1138 if (overrideState.length()) {
1139 if (currentState.length())
1140 api->
logPrint(1,
"No post (%s) found for current state '%s', using override state instead (%s)",
1141 postName.c_str(), currentState.c_str(), overrideState.c_str());
1143 api->
logPrint(1,
"No post (%s) found for current empty state, using override state instead (%s)",
1144 postName.c_str(), overrideState.c_str());
1149 api->
logPrint(1,
"No post (%s) found for override state '%s'",
1150 postName.c_str(), overrideState.c_str());
1154 if (currentState.length())
1155 api->
logPrint(1,
"No post (%s) found for current state '%s'", postName.c_str(), currentState.c_str());
1157 api->
logPrint(1,
"No post (%s) found for current empty state", postName.c_str());
1168 const char* triggerName;
#define QUERY_SUCCESS
The query succeeded.
#define QUERY_TIMEOUT
No reply within the timeout.
Built-in internal cranks and message-script playback structures.
static struct PsyContext NOCONTEXT
The empty/unset context (isValid() == false).
32-bit RGBA raster image with drawing, compositing, scaling, BMP I/O and update-region tracking.
uint32 height
Height in pixels.
uint32 width
Width in pixels.
uint32 size
Data buffer size in bytes (width*height*4).
char * data
Pixel data, 32-bit RGBA, row-major top-down.
The central Psyclone data container: a self-contained binary message with typed, named user entries.
bool setFloat(const char *key, float64 value)
setFloat(const char* key, float64 value)
uint32 getFrom()
getFrom() Get the sender id
bool setString(const char *key, const char *value)
setString(const char* key, const char* value)
bool setInt(const char *key, int64 value)
setInt(const char* key, int64 value)
bool setTag(uint32 tag)
setTag(uint32 tag)
PsyContext getContextChange()
getContextChange()
DataMessageHeader * data
Pointer to the message's flat memory block (header + user entries).
PsyType getType()
getType()
uint64 getCreatedTime()
getCreatedTime()
bool setData(const char *key, const char *value, uint32 size)
setData(const char* key, const char* value, uint32 size)
const char * getString(const char *key)
getString(const char* key)
bool setSerial(uint64 serial)
setSerial(uint64 serial)
uint64 getRecvTime()
getRecvTime()
uint64 getSendTime()
getSendTime()
DataMessage * copy()
copy() Creates a full deep copy of the message and returns it.
std::string getUserEntriesAsString()
getUserEntriesAsString() Returns the textual representation of the full message including all user en...
The API handle a component (crank) uses to talk to the Psyclone system.
PsyContext getCurrentTriggerContext()
Get the context of the current trigger, just retrieved using waitForNewMessage().
uint8 retrieveIntegerParam(std::list< DataMessage * > &result, const char *name, int64 startInteger, int64 endInteger=INT64_NOVALUE, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Used by a module to retrieve messages from a whiteboard.
std::string getParameterString(const char *name)
Read and return value of parameter by name.
std::string contextToText(PsyContext context)
Get textual representation of the context.
uint8 retrieve(std::list< DataMessage * > &result, const char *name, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Retrieve stored messages from a whiteboard, by named <retrieve> spec entry.
int64 getParameterInt(const char *name)
Read and return value of parameter by name.
bool getParameter(const char *name, char *val, uint32 maxSize)
Read string parameter into existing data chunk val, maximum size maxSize.
int32 postOutputMessage(const char *postName=NULL, DataMessage *msg=NULL)
Post the crank's output according to the spec's post entries.
bool shouldContinue()
Check whether the crank should keep running, or exit its loop.
bool emitSignal(const char *name, DataMessage *msg=NULL)
Emit a signal by its spec name.
bool hasCurrentPostName(const char *name)
Check to see if the post name is currently active - i.e.
bool hasParameter(const char *name)
Checks if a named parameter exists.
std::string getOtherModuleName(uint32 id)
Get the name of another module by id.
DataMessage * waitForSignal(const char *name, uint32 timeout, uint64 lastReceivedTime=0)
Wait for a signal (latest-value broadcast) by its spec name.
uint8 queryCatalog(char **result, uint32 &resultsize, const char *name, const char *query, const char *operation=NULL, const char *data=NULL, uint32 datasize=0, uint32 timeout=5000)
Send a query to another module or catalog by named <query> spec entry, receiving raw bytes back.
bool getParameterAsBool(const char *name)
Read and interpret value of parameter by name as boolean True: String 'Yes', Integer and Float non-ze...
DataMessage * waitForNewMessage(uint32 ms)
Wait for the next trigger message from the component's input queue.
bool logPrint(int level, const char *formatstring,...)
Write a printf-style entry to the component's log (and the console when level is below the logging th...
std::set< std::string > getCurrentPostNames()
Get a list of post names currently active - i.e.
std::string typeToText(PsyType type)
Get textual representation of the type.
std::string PrintDateStringSortableDelimiter(uint64 t, const char *del, bool local=true)
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
std::string PrintTimeDifString(uint64 t, bool us=true, bool ms=true)
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
std::string PrintTimeSortableMicrosecString(uint64 t, bool local=true)
Sortable date+time with microseconds.
bool TextStartsWith(const char *str, const char *start, bool caseSensitive=true)
Test whether str starts with start.
bool Sleep(uint32 ms)
Suspend the calling thread.
uint32 Ascii2Uint32(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 32-bit decimal integer from a substring.
bool AppendToAFile(const char *filename, const char *data, uint32 length, bool binary=false)
Append to a file, creating it if missing.
char * GetFileList(const char *dirname, const char *ext, uint32 &count, bool fullpath, uint32 maxNameLen=256)
List files in a directory matching an extension.
bool MoveAFile(const char *oldfilename, const char *newfilename, bool force=false)
Move/rename a file.
bool DoesAFileExist(const char *filename)
Test whether a regular file exists.
bool DeleteAFile(const char *filename, bool force)
Delete a file.
std::string StringFormat(const char *format,...)
printf into a std::string.
int64 Ascii2Int64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a signed 64-bit decimal integer from a substring.
float64 Ascii2Float64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a 64-bit float from a substring (decimal point, not locale dependent).
int8 Internal_QueryTest(PsyAPI *api)
Exercises query/queryReply round-trips.
int8 Internal_Pong(PsyAPI *api)
Latency test counterpart: answers pings.
int8 Internal_Print(PsyAPI *api)
Prints incoming messages to the console/log.
int8 Internal_Simple(PsyAPI *api)
Pass-through test crank: copies each incoming message to its posts.
@ eXMLErrorFirstTagNotFound
int8 Internal_SignalPong(PsyAPI *api)
Signal-based pong counterpart.
int8 Internal_StatsLog(PsyAPI *api)
Periodically logs system statistics.
int8 Internal_SignalPing(PsyAPI *api)
Signal-based ping test.
int8 Internal_MessageToggler(PsyAPI *api)
Alternates/toggles message output for testing.
int8 Internal_Shutdown(PsyAPI *api)
Initiates system shutdown when triggered.
int8 Internal_Ping(PsyAPI *api)
Latency test: posts pings, expects pongs.
int8 Internal_Time(PsyAPI *api)
Posts time information/timestamps.
int8 Internal_BitmapPoster(PsyAPI *api)
Posts test bitmap/image messages.
int8 Internal_MessageTypeConverter(PsyAPI *api)
Converts incoming messages to another type before reposting.
int8 Internal_MessageScript(PsyAPI *api)
Plays back scripted TrackPlayerMessage sequences.
int8 Internal_RetrieveTest(PsyAPI *api)
Exercises whiteboard retrieve calls.
Hierarchical execution-context identifier.
One key/value entry of a scripted TrackPlayerMessage.
std::string key
Entry key placed in the generated message.
std::string value
Entry value (textual; converted per entryType).
enum cmlabs::TrackPlayerMessageEntry::EntryType entryType
Data type of the value string.
One scripted post/signal action for the message-script player (Internal_MessageScript).
std::string postName
Post/signal name to use.
enum cmlabs::TrackPlayerMessage::PostType postType
Send as a posted message or as a signal.
uint32 timeMS
Time offset in ms for time-triggered sends.
bool addEntry(const char *key, const char *value, const char *keytype=NULL)
Add an entry to the message.
uint32 intervalMS
Repeat interval in ms; 0 for one-shot.
uint64 nextTime
Next scheduled send time (PsyTime µs), maintained by the player.
std::map< std::string, TrackPlayerMessageEntry > entryMap
Entries copied into each generated message.
enum cmlabs::TrackPlayerMessage::TriggerType triggerType
What causes the send: incoming trigger, timer, or nothing.
uint32 delayMS
Delay in ms before sending (after the trigger).
XMLAttribute getAttribute(int i=0) const
XMLNode getChildNode(int i=0) const