CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
ControlMessage.cpp
Go to the documentation of this file.
1
6#include "ControlMessage.h"
7#include "PsyTime.h"
8#include "UnitTestFramework.h"
9
10namespace cmlabs {
11
12ControlMessage::ControlMessage(uint16 command, uint64 from, uint64 to, char* data, uint32 dataSize) {
13 this->data = new char[sizeof(ControlMessageHeader) + dataSize];
14 ControlMessageHeader* header = (ControlMessageHeader*) this->data;
15 header->size = sizeof(ControlMessageHeader) + dataSize;
16 header->cid = CONTROLMESSAGEID;
17 header->command = command;
18 header->time = GetTimeNow();
19 header->from = from;
20 header->to = to;
21 if (dataSize > 0)
22 memcpy(this->data+sizeof(ControlMessageHeader), data, dataSize);
23}
24
26 this->data = data;
27}
28
32
34 if (!VerObj(data)) return 0;
35 return ((struct ControlMessageHeader*)data)->size;
36}
37
39 if (!VerObj(data)) return 0;
40 return ((struct ControlMessageHeader*)data)->command;
41}
42
44 if (!VerObj(data)) return 0;
45 return ((struct ControlMessageHeader*)data)->time;
46}
47
49 if (!VerObj(data)) return 0;
50 return ((struct ControlMessageHeader*)data)->from;
51}
52
54 if (!VerObj(data)) return 0;
55 return ((struct ControlMessageHeader*)data)->to;
56}
57
59 if (!VerObj(data)) return 0;
60 return ((struct ControlMessageHeader*)data)->status;
61}
62
63bool ControlMessage::setStatus(uint16 status) {
64 if (!VerObj(data)) return false;
65 ((ControlMessageHeader*)data)->status = status;
66 return true;
67}
68
69
71
72 // 1. Construction (no payload) and field accessors
73 unittest::progress(10, "construction and accessors");
74 {
75 const uint16 command = 7;
76 const uint64 from = 0x1122334455667788ULL;
77 const uint64 to = 0x99AABBCCDDEEFF00ULL;
78 uint64 t0 = GetTimeNow();
79 ControlMessage msg(command, from, to);
80
81 if (msg.getCommand() != command) { unittest::fail("ControlMessage test: getCommand mismatch\n"); return false; }
82 if (msg.getFrom() != from) { unittest::fail("ControlMessage test: getFrom mismatch\n"); return false; }
83 if (msg.getTo() != to) { unittest::fail("ControlMessage test: getTo mismatch\n"); return false; }
84 if (msg.getSize() != sizeof(ControlMessageHeader)) { unittest::fail("ControlMessage test: getSize (no payload) mismatch\n"); return false; }
85 // time is auto-stamped from GetTimeNow(); just sanity-check it is populated and not before we started
86 if (msg.getTime() == 0 || msg.getTime() < t0) { unittest::fail("ControlMessage test: getTime not stamped\n"); return false; }
87 // status defaults to 0 until set
88 if (msg.getStatus() != 0) { unittest::fail("ControlMessage test: default status != 0\n"); return false; }
89 }
90
91 // 2. Status set/get round-trip
92 unittest::progress(35, "status set/get");
93 {
94 ControlMessage msg(1, 100, 200);
95 if (!msg.setStatus(0xBEEF)) { unittest::fail("ControlMessage test: setStatus returned false\n"); return false; }
96 if (msg.getStatus() != 0xBEEF) { unittest::fail("ControlMessage test: getStatus mismatch after setStatus\n"); return false; }
97 if (!msg.setStatus(0)) { unittest::fail("ControlMessage test: setStatus(0) returned false\n"); return false; }
98 if (msg.getStatus() != 0) { unittest::fail("ControlMessage test: getStatus mismatch after setStatus(0)\n"); return false; }
99 }
100
101 // 3. Construction with a binary payload
102 unittest::progress(55, "payload construction");
103 {
104 const char payload[] = { 'C', 'M', 'D', 'A', 'T', 'A' };
105 const uint32 payloadSize = sizeof(payload);
106 ControlMessage msg(42, 5, 6, (char*)payload, payloadSize);
107
108 if (msg.getCommand() != 42) { unittest::fail("ControlMessage test: payload getCommand mismatch\n"); return false; }
109 if (msg.getSize() != sizeof(ControlMessageHeader) + payloadSize) {
110 unittest::fail("ControlMessage test: payload getSize mismatch\n"); return false;
111 }
112 // the payload bytes sit immediately after the header in the data buffer
113 const char* stored = msg.data + sizeof(ControlMessageHeader);
114 if (memcmp(stored, payload, payloadSize) != 0) {
115 unittest::fail("ControlMessage test: payload bytes not stored correctly\n"); return false;
116 }
117 }
118
119 // 4. Wrap an existing raw buffer (the ControlMessage(char*) constructor) - serialise / deserialise round-trip
120 unittest::progress(80, "raw buffer round-trip");
121 {
122 const char payload[] = { 0x01, 0x02, 0x03, 0x04 };
123 const uint32 payloadSize = sizeof(payload);
124 ControlMessage orig(99, 0xAAAA, 0xBBBB, (char*)payload, payloadSize);
125 orig.setStatus(0x1234);
126
127 // adopt the same underlying buffer through the raw-buffer constructor
128 ControlMessage wrapped(orig.data);
129 if (wrapped.getCommand() != 99) { unittest::fail("ControlMessage test: wrapped getCommand mismatch\n"); return false; }
130 if (wrapped.getFrom() != 0xAAAA) { unittest::fail("ControlMessage test: wrapped getFrom mismatch\n"); return false; }
131 if (wrapped.getTo() != 0xBBBB) { unittest::fail("ControlMessage test: wrapped getTo mismatch\n"); return false; }
132 if (wrapped.getStatus() != 0x1234) { unittest::fail("ControlMessage test: wrapped getStatus mismatch\n"); return false; }
133 if (wrapped.getSize() != sizeof(ControlMessageHeader) + payloadSize) {
134 unittest::fail("ControlMessage test: wrapped getSize mismatch\n"); return false;
135 }
136 if (memcmp(wrapped.data + sizeof(ControlMessageHeader), payload, payloadSize) != 0) {
137 unittest::fail("ControlMessage test: wrapped payload mismatch\n"); return false;
138 }
139 // wrapped's destructor only nulls its pointer (no free); orig owns and frees the buffer.
140 }
141
142 // 5. Edge / robustness - accessors on an invalid (NULL) buffer must be safe and return zero
143 unittest::progress(92, "edge / robustness");
144 {
145 ControlMessage bad((char*)NULL);
146 if (bad.getSize() != 0) { unittest::fail("ControlMessage test: NULL getSize != 0\n"); return false; }
147 if (bad.getCommand() != 0) { unittest::fail("ControlMessage test: NULL getCommand != 0\n"); return false; }
148 if (bad.getTime() != 0) { unittest::fail("ControlMessage test: NULL getTime != 0\n"); return false; }
149 if (bad.getFrom() != 0) { unittest::fail("ControlMessage test: NULL getFrom != 0\n"); return false; }
150 if (bad.getTo() != 0) { unittest::fail("ControlMessage test: NULL getTo != 0\n"); return false; }
151 if (bad.getStatus() != 0) { unittest::fail("ControlMessage test: NULL getStatus != 0\n"); return false; }
152 if (bad.setStatus(1)) { unittest::fail("ControlMessage test: NULL setStatus returned true\n"); return false; }
153 }
154
155 // 6. Construction performance metric
156 unittest::progress(97, "construction throughput");
157 {
158 const int N = 20000;
159 const char payload[] = { 'p', 'e', 'r', 'f' };
160 uint64 ts = GetTimeNow();
161 uint64 acc = 0;
162 for (int i = 0; i < N; i++) {
163 ControlMessage m((uint16)i, (uint64)i, (uint64)(i + 1), (char*)payload, sizeof(payload));
164 acc += m.getCommand();
165 }
166 double us = (double)(GetTimeNow() - ts);
167 if (us > 0)
168 unittest::metric("construct_throughput", (double)N / us * 1e6, "msg/s", true);
169 unittest::detail("constructed %d control messages, command checksum %llu", N, acc);
170 }
171
172 unittest::progress(100, "done");
173 return true;
174}
175
178 "Control message construction, status, payload, raw-buffer round-trip", "core");
179}
180
181
182} // namespace cmlabs
Lightweight internal control/command message used by the Psyclone runtime.
#define CONTROLMESSAGEID
Definition ObjectIDs.h:54
#define VerObj(data)
Extract and verify the cid of a binary object block in one step.
Definition ObjectIDs.h:28
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
Small, dependency-free unit test harness used by all CMSDK object tests.
char * data
The flat message block (ControlMessageHeader + payload); see class notes on ownership.
static bool UnitTest()
Run the built-in self test.
bool setStatus(uint16 status)
Set the status/result code.
ControlMessage(uint16 command, uint64 from, uint64 to, char *data=NULL, uint32 dataSize=0)
Create a new control message.
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
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.
void Register_ControlMessage_Tests()
Wire/shared-memory header of a ControlMessage; any payload follows immediately after.
uint32 size
Total block size in bytes (header + payload).