1 /*
2 * Copyright (c) 2012-2015 Texas Instruments Incorporated - http://www.ti.com
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * ======== MessageQ.xs ========
34 *
35 */
37 var MultiProc = null;
38 var NameServer = null;
39 var MessageQ = null;
40 var GateThread = null;
41 var Settings = null;
42 var SyncSem = null;
44 var instCount = 0; /* use to determine if processing last instance */
46 /*
47 * ======== module$meta$init ========
48 */
49 function module$meta$init(name)
50 {
51 /* Only process during "cfg" phase */
52 if (xdc.om.$name != "cfg") {
53 return;
54 }
55 }
57 /*
58 * ======== module$use ========
59 */
60 function module$use()
61 {
62 MessageQ = this;
63 Settings = xdc.useModule('ti.sdo.ipc.family.Settings');
64 List = xdc.useModule("ti.sdo.utils.List");
65 MultiProc = xdc.useModule("ti.sdo.utils.MultiProc");
66 NameServer = xdc.useModule('ti.sdo.utils.NameServer');
67 GateThread = xdc.useModule('xdc.runtime.knl.GateThread');
68 SyncSem = xdc.useModule('ti.sysbios.syncs.SyncSem');
70 xdc.useModule('ti.sdo.ipc.interfaces.ITransport');
71 xdc.useModule('ti.sdo.ipc.interfaces.IMessageQTransport');
72 xdc.useModule('ti.sdo.ipc.interfaces.INetworkTransport');
73 xdc.useModule('ti.sdo.ipc.transports.TransportNetworkDummy');
75 /* Plug the SetupTransportProxy for the MessageQ transport */
76 if (MessageQ.SetupTransportProxy == null) {
77 try {
78 MessageQ.SetupTransportProxy =
79 xdc.useModule(Settings.getMessageQSetupDelegate());
80 }
81 catch (e) {
82 /* Plug in the generic shared memory transport */
83 MessageQ.SetupTransportProxy =
84 xdc.useModule('ti.sdo.ipc.transports.TransportShmSetup');
85 }
86 }
87 }
89 /*
90 * ======== module$static$init ========
91 * Initialize module values.
92 */
93 function module$static$init(state, mod)
94 {
95 /* initialize the NameServer param to be used now or later */
96 MessageQ.nameSrvPrms.maxRuntimeEntries = mod.maxRuntimeEntries;
97 MessageQ.nameSrvPrms.tableSection = mod.tableSection;
98 MessageQ.nameSrvPrms.maxNameLen = mod.maxNameLen;
100 /*
101 * Get the current number of created static instances of this module.
102 * Note: if user creates a static instance after this point and
103 * expects to use NameServer, this is a problem.
104 */
105 var instCount = this.$instances.length;
107 /* create NameServer here only if no static instances are created */
108 if (instCount == 0) {
109 state.nameServer = NameServer.create("MessageQ", MessageQ.nameSrvPrms);
110 }
111 else {
112 state.nameServer = null;
113 }
115 /*
116 * If no growth allowed, pre-allocate the max length
117 * Also pre-allocate if numReservedEntries is not zero.
118 * maxRuntimeEntries < numReservedEntries is caught in validate.
119 */
120 state.numQueues = this.$instances.length;
121 if (mod.maxRuntimeEntries != NameServer.ALLOWGROWTH) {
122 state.numQueues += mod.maxRuntimeEntries;
123 }
124 else if (mod.numReservedEntries != 0){
125 state.numQueues += mod.numReservedEntries;
126 }
128 state.queues.length = state.numQueues;
129 state.canFreeQueues = false;
130 state.freeHookFxn = mod.freeHookFxn;
131 state.putHookFxn = mod.putHookFxn;
133 if (mod.nameTableGate == null) {
134 state.gate = null;
135 }
136 else {
137 state.gate = mod.nameTableGate;
138 }
140 var messsageQParams = new this.Params;
142 /* Initial the seqNum used for tracing */
143 state.seqNum = 0;
145 /* Set the length of the heaps array */
146 state.numHeaps = mod.numHeaps;
147 state.heaps.length = state.numHeaps;
149 /* Initialize the heaps array to null */
150 for (var i = 0; i < state.heaps.length; i++) {
151 state.heaps[i] = null;
152 }
154 /*
155 * Sort the static heaps by heap id into the heaps array
156 */
157 for (var i = 0; i < mod.staticHeaps.length; i++) {
159 /* Make sure the id is not too big */
160 if (mod.staticHeaps[i].heapId >= state.numHeaps) {
161 MessageQ.$logError("Out of range heapId ("
162 + mod.staticHeaps[i].heapId + "). Max heapId is "
163 + (mod.numHeaps - 1) + " (MessageQ.numHeaps - 1).", this);
164 }
166 /* Make sure the same id is not used twice */
167 if (state.heaps[mod.staticHeaps[i].heapId] != null) {
168 MessageQ.$logError("Cannot register multiple heaps to heapId "
169 + mod.staticHeaps[i].heapId + ".", this);
170 }
172 state.heaps[mod.staticHeaps[i].heapId] = mod.staticHeaps[i].heap;
173 }
175 if (MultiProc.procAddrMode == MultiProc.ProcAddrMode_Global) {
176 /* global address mode: need transport handle for every processor */
177 state.transports.length = MultiProc.numProcessors;
178 }
179 else if (MultiProc.procAddrMode == MultiProc.ProcAddrMode_Cluster) {
180 /* cluster address mode: need transport only for cluster members */
181 state.transports.length = MultiProc.numProcsInCluster;
182 }
183 else {
184 MessageQ.$logError("Unknown MultiProc.procAddrMode", this);
185 }
187 for (var i = 0; i < state.transports.length; i++) {
188 state.transports[i][0] = null;
189 state.transports[i][1] = null;
190 }
192 /* sort the static transports by processor id into the transport array */
193 if (MultiProc.procAddrMode == MultiProc.ProcAddrMode_Global) {
194 for (var i = 0; i < mod.staticTransports.length; i++) {
195 /* make sure the procId is not too big */
196 if (mod.staticTransports[i].procId >= MultiProc.numProcessors) {
197 MessageQ.$logError("MessageQ Out of range procId ("
198 + mod.staticTransports[i].procId + "). Max procId is "
199 + (MultiProc.numProcessors) + " (MultiProc."
200 + "numProcessors).", this);
201 }
203 /* make sure the same id is not used twice */
204 if (state.transports[mod.staticTransports[i].procId] != null) {
205 MessageQ.$logError("Cannot register multiple transports to "
206 + "same remote processor ("
207 + mod.staticTransports[i].procId + ").", this);
208 }
210 state.transports[mod.staticTransports[i].procId] =
211 mod.staticTransports[i].transport;
212 }
213 }
214 else if (MultiProc.procAddrMode == MultiProc.ProcAddrMode_Cluster) {
215 for (var i = 0; i < mod.staticTransports.length; i++) {
216 var clusterId = mod.staticTransports[i].procId
217 - MultiProc.baseIdOfCluster;
219 /* validate clusterId */
220 if (clusterId >= MultiProc.numProcsInCluster) {
221 MessageQ.$logError("procId=" + mod.staticTransports[i].procId
222 + " is not in cluster", this);
223 }
225 /* make sure the same id is not used twice */
226 if (state.transports[clusterId] != null) {
227 MessageQ.$logError("Cannot register multiple transports to "
228 + "same remote processor ("
229 + mod.staticTransports[i].procId + ").", this);
230 }
232 state.transports[clusterId] = mod.staticTransports[i].transport;
233 }
234 }
235 else {
236 MessageQ.$logError("Unknown MultiProc.procAddrMode", this);
237 }
239 /* initialize the registered transport array */
240 for (var i = 0; i < state.regTrans.length; i++) {
241 state.regTrans[i].transport = null;
242 state.regTrans[i].type = mod.TransportType_Invalid;
243 }
244 }
246 /*
247 * ======== registerHeapMeta ========
248 */
249 function registerHeapMeta(heap, heapId)
250 {
251 var entry = new this.HeapEntry();
252 entry.heap = heap;
253 entry.heapId = heapId;
254 this.staticHeaps.$add(entry);
255 }
257 /*
258 * ======== registerTransportMeta ========
259 */
260 function registerTransportMeta(transport, procId, priority)
261 {
262 var entry = new this.transportEntry();
263 entry.transport = transport;
264 entry.procId = procId;
265 this.staticTransports.$add(entry);
266 }
268 /*
269 * ======== viewInitQueues ========
270 */
271 function viewInitQueues(view, obj)
272 {
273 var Program = xdc.useModule('xdc.rov.Program');
274 var NameServer = xdc.useModule('ti.sdo.utils.NameServer');
275 var SharedRegion = xdc.useModule('ti.sdo.ipc.SharedRegion');
276 var modCfg = Program.getModuleConfig('ti.sdo.ipc.MessageQ');
278 /* view.name */
279 try {
280 view.name = NameServer.getName$view("MessageQ", obj.queue);
281 if (view.name == null) {
282 view.name = "<null>";
283 }
284 }
285 catch(e) {
286 Program.displayError(view, "name",
287 "Error retrieving name from NameServer: " + e);
288 }
290 /* view.queueId */
291 view.queueId = obj.queue & 0xffff;
293 /* view.reserved */
294 if ((view.queueId - 128) < modCfg.numReservedEntries) {
295 view.reserved = true;
296 }
297 else {
298 view.reserved = false;
299 }
300 }
302 /*
303 * ======== viewInitMessages ========
304 */
305 function viewInitMessages(view, obj)
306 {
307 var Program = xdc.useModule('xdc.rov.Program');
308 var MessageQ = xdc.useModule('ti.sdo.ipc.MessageQ');
309 var NameServer = xdc.useModule('ti.sdo.utils.NameServer');
311 /* view.label */
312 try {
313 view.label = NameServer.getName$view("MessageQ", obj.queue);
314 if (view.label == null) {
315 view.label = "<null>";
316 }
317 }
318 catch(e) {
319 Program.displayError(view, "label",
320 "Error retrieving name from NameServer: " + e);
321 return;
322 }
324 /* Retrieve the ROV view for the embedded high priority message list. */
325 addMsgsFromList(view, obj.highList);
327 /* Retrieve the ROV view for the embedded normal priority message list. */
328 addMsgsFromList(view, obj.normalList);
329 }
331 /*
332 * ======== addMsgsFromList ========
333 * Scans the provided list object and adds the messages on it to the view.
334 */
335 function addMsgsFromList(view, list)
336 {
337 var Program = xdc.useModule('xdc.rov.Program');
339 /* Scan the list to retrieve the addresses of the messages. */
340 try {
341 var listView = Program.scanObjectView("ti.sdo.utils.List", list,
342 "Basic");
343 }
344 /* If there was a problem scanning the list, report it. */
345 catch (e) {
346 var msgView = Program.newViewStruct('ti.sdo.ipc.MessageQ', 'Messages');
347 /*
348 * If there was a problem, report it using the first field, and
349 * return.
350 */
351 Program.displayError(msgView, 'seqNum', String(e));
352 view.elements.$add(msgView);
353 return;
354 }
356 try {
357 /* Fetch each of the message headers on the list. */
358 for each (var addr in listView.elems) {
359 var msgView = getMsgView(Number(addr));
360 view.elements.$add(msgView);
361 }
362 }
363 catch (e) {
364 /*
365 * If there were any problems retrieving the view, add an element
366 * to report the error.
367 */
368 var msgView = Program.newViewStruct('ti.sdo.ipc.MessageQ', 'Messages');
369 Program.displayError(msgView, 'seqNum', String(e));
370 view.elements.$add(msgView);
371 }
372 }
374 /*
375 * ======== getMsgView ========
376 * Returns a view structure representing the message at the given address.
377 */
378 function getMsgView(addr)
379 {
380 var Program = xdc.useModule('xdc.rov.Program');
381 var MessageQ = xdc.useModule('ti.sdo.ipc.MessageQ');
383 /* Create a new message view to populate. */
384 var msgView = Program.newViewStruct('ti.sdo.ipc.MessageQ', 'Messages');
386 /* Fetch the message header from the given address. */
387 try {
388 var msgHeader = Program.fetchStruct(MessageQ.MsgHeader$fetchDesc,
389 Number(addr));
390 }
391 catch (e) {
392 /*
393 * If there was a problem, report it using the first field, and
394 * return the view.
395 */
396 Program.displayError(msgView, 'seqNum', String(e));
397 return (msgView);
398 }
400 /* Display the messages sequence number and size. */
401 msgView.seqNum = msgHeader.seqNum;
402 msgView.msgSize = msgHeader.msgSize;
404 /* The flags field contains the message priority. */
405 var priority = msgHeader.flags & MessageQ.PRIORITYMASK;
406 getPriority(msgView, priority);
408 /* The flags field also contains the trace enabled bit. */
409 msgView.traceEnabled = msgHeader.flags & MessageQ.TRACEMASK;
411 /* The flags field also contains the version bits. */
412 msgView.version = (msgHeader.flags & MessageQ.VERSIONMASK) >> 13;
414 /* Display the message ID set by the user. */
415 msgView.msgId = msgHeader.msgId;
417 /*
418 * Scan in the MultiProc view so we have the mapping from processor id
419 * to processor name.
420 */
421 try {
422 var multiProcView = Program.scanModuleView('ti.sdo.utils.MultiProc',
423 'Module');
424 }
425 catch (e) {
426 /*
427 * If there was a problem scanning the MultiProc view, display the
428 * error, but keep processing anyway.
429 */
430 Program.displayError(msgView, 'srcProc', String(e));
431 }
433 /* Lookup the names of the destination, reply, and source processors. */
434 msgView.srcProc = multiProcView.nameList[msgHeader.srcProc];
436 /* If a reply queue hasn't been specified, display "N/A" */
437 if (msgHeader.replyId == 0xFFFF) {
438 msgView.replyProc = "N/A";
439 msgView.replyId = "N/A";
440 }
441 /* Otherwise display the reply queue. */
442 else {
443 msgView.replyProc = multiProcView.nameList[msgHeader.replyProc];
444 // TODO - Should this display the name of the MessageQ?
445 msgView.replyId = String(msgHeader.replyId);
446 }
448 /* Display the heap that the message was allocated from. */
449 msgView.heap = getHeapNameFromId(msgHeader.heapId);
451 return (msgView);
452 }
454 /*
455 * ======== getPriority ========
456 * Fills in the message views 'priority' field given the priority value.
457 */
458 function getPriority(msgView, priority)
459 {
460 var MessageQ = xdc.useModule('ti.sdo.ipc.MessageQ');
461 var Program = xdc.useModule('xdc.rov.Program');
463 switch (priority) {
464 case MessageQ.NORMALPRI:
465 msgView.priority = "(" + MessageQ.NORMALPRI + ") Normal";
466 break;
467 case MessageQ.HIGHPRI:
468 msgView.priority = "(" + MessageQ.HIGHPRI + ") High";
469 break;
470 case MessageQ.RESERVEDPRI:
471 msgView.priority = "(" + MessageQ.RESERVEDPRI + ") Reserved";
472 break;
473 case MessageQ.URGENTPRI:
474 msgView.priority = "(" + MessageQ.URGENTPRI + ") Urgent";
475 break;
476 default:
477 Program.displayError(msgView, 'priority',
478 'Message has invalid priority: ' + priority);
479 }
480 }
482 /*
483 * ======== getHeapNameFromId ========
484 * This function takes the heap Id from a message (the heap ids are assigned
485 * by MessageQ) and retrieves a name for the heap.
486 */
487 function getHeapNameFromId(heapId)
488 {
489 var Program = xdc.useModule('xdc.rov.Program');
491 /* The module state contains the list of heaps. */
492 var modView = Program.scanModuleView('ti.sdo.ipc.MessageQ', 'Module');
494 /* Get the string representation of the address. */
495 if ((heapId == -1) || (heapId == 65535)) {
496 var heapAddr = "[static]";
497 }
498 else {
499 var heapAddr = String(modView.heaps[heapId]);
500 }
502 return (heapId + " (" + heapAddr + ")");
503 }
505 /*
506 * ======== viewInitModule ========
507 */
508 function viewInitModule(view, mod)
509 {
510 var Program = xdc.useModule('xdc.rov.Program');
512 /* Scan in the array of heaps. */
513 try {
514 view.heaps = Program.fetchArray(mod.heaps$fetchDesc, mod.heaps,
515 mod.numHeaps);
516 }
517 catch (e) {
518 Program.displayError(view, 'heaps', "Problem retrieving array of " +
519 "heaps: " + e);
520 }
522 /* Display the handle to the module's gate. */
523 view.gate = mod.gate;
525 /*
526 * Display the module's sequence number, which is the next value
527 * that will be used.
528 */
529 view.nextSeqNum = mod.seqNum;
531 /* Display the freeHookFxn if there is one. */
532 if (Number(mod.freeHookFxn) != 0 ) {
533 view.freeHookFxn = Program.lookupFuncName(Number(mod.freeHookFxn));
534 }
535 }
537 function module$validate()
538 {
539 if ((MessageQ.maxRuntimeEntries != NameServer.ALLOWGROWTH) &&
540 (MessageQ.maxRuntimeEntries < MessageQ.numReservedEntries)) {
541 MessageQ.$logFatal(
542 "If MessageQ.maxRuntimeEntries is not NameServer.ALLOWGROWTH, " +
543 "it cannot be less than MessageQ.numReservedEntries.",
544 MessageQ);
545 }
546 }