gRCM: Pulled in gRCM from omapzoom sysbios-rpmsg wholsale.
authorG Anthony <a0783926@ti.com>
Fri, 1 Mar 2013 18:08:53 +0000 (10:08 -0800)
committerG Anthony <a0783926@ti.com>
Fri, 1 Mar 2013 18:08:53 +0000 (10:08 -0800)
This is required by the ServiceMgr and test_omx sample for OMAP5.

Pulled from omapzoom.org, sysbios-rpmsg, master branch, tag: 2.00.11.31.

Signed-off-by: G Anthony <a0783926@ti.com>
18 files changed:
packages/ti/grcm/RcmClient.c [new file with mode: 0644]
packages/ti/grcm/RcmClient.h [new file with mode: 0644]
packages/ti/grcm/RcmClient.xdc [new file with mode: 0644]
packages/ti/grcm/RcmClient.xs [new file with mode: 0644]
packages/ti/grcm/RcmServer.c [new file with mode: 0644]
packages/ti/grcm/RcmServer.h [new file with mode: 0644]
packages/ti/grcm/RcmServer.xdc [new file with mode: 0644]
packages/ti/grcm/RcmServer.xs [new file with mode: 0644]
packages/ti/grcm/RcmTypes.h [new file with mode: 0644]
packages/ti/grcm/RcmUtils.c [new file with mode: 0644]
packages/ti/grcm/Settings.xdc [new file with mode: 0644]
packages/ti/grcm/Settings.xs [new file with mode: 0644]
packages/ti/grcm/doxygen.txt [new file with mode: 0644]
packages/ti/grcm/link.xdt [new file with mode: 0644]
packages/ti/grcm/package.bld [new file with mode: 0644]
packages/ti/grcm/package.xdc [new file with mode: 0644]
packages/ti/grcm/package.xs [new file with mode: 0644]
packages/ti/grcm/prologue.mak [new file with mode: 0644]

diff --git a/packages/ti/grcm/RcmClient.c b/packages/ti/grcm/RcmClient.c
new file mode 100644 (file)
index 0000000..1b38969
--- /dev/null
@@ -0,0 +1,1663 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  ======== RcmClient.c ========
+ */
+
+/* this define must precede inclusion of any xdc header file */
+#define Registry_CURDESC ti_rcm_RcmClient__Desc
+#define MODULE_NAME "ti.rcm.RcmClient"
+
+#define xdc_runtime_Memory__nolocalnames  /* short name clashes with SysLink */
+
+/* rtsc header files */
+#include <xdc/std.h>
+#include <xdc/runtime/Assert.h>
+#include <xdc/runtime/Diags.h>
+#include <xdc/runtime/Error.h>
+#include <xdc/runtime/IHeap.h>
+#include <xdc/runtime/Log.h>
+#include <xdc/runtime/Memory.h>
+#include <xdc/runtime/Registry.h>
+#include <xdc/runtime/Startup.h>
+#include <xdc/runtime/knl/GateThread.h>
+#include <xdc/runtime/knl/Semaphore.h>
+#include <xdc/runtime/knl/SemThread.h>
+#include <xdc/runtime/knl/SyncSemThread.h>
+#include <xdc/runtime/knl/ISemaphore.h>
+
+/* package header files */
+#include <ti/ipc/MessageQ.h>
+
+#if defined(RCM_ti_ipc)
+#include <ti/sdo/utils/List.h>
+
+#elif defined(RCM_ti_syslink)
+#include <ti/syslink/utils/List.h>
+
+#else
+    #error "undefined ipc binding"
+#endif
+
+/* local header files */
+#include <ti/rcm/RcmServer.h>
+#include "RcmTypes.h"
+#include "RcmClient.h"
+
+/* recipient list element structure */
+typedef struct {
+    List_Elem elem;
+    UInt16 msgId;
+    RcmClient_Message *msg;
+    SemThread_Struct event;
+} Recipient;
+
+typedef struct RcmClient_Object_tag {
+    GateThread_Struct   gate;           // instance gate
+    MessageQ_Handle     msgQue;         // message queue
+    MessageQ_Handle     errorMsgQue;    // error message queue
+    UInt16              heapId;         // heap used for message allocation
+    Ptr                 sync;           // synchronizer for message queue
+    UInt32              serverMsgQ;     // server message queue
+    Bool                cbNotify;       // callback notification
+    UInt16              msgId;          // last used message id
+    ISemaphore_Handle   mbxLock;        // mailbox lock
+    ISemaphore_Handle   queueLock;      // message queue lock
+    List_Handle         recipients;     // list of waiting recipients
+    List_Handle         newMail;        // list of undelivered messages
+} RcmClient_Object;
+
+typedef struct RcmClient_Module_tag {
+    String              name;
+    Bits16              id;
+    Bits16              diagsMask;
+    IHeap_Handle        heap;
+} RcmClient_Module;
+
+/* private functions */
+static
+UInt16 RcmClient_genMsgId_P(
+        RcmClient_Object *      obj
+    );
+
+static inline
+RcmClient_Packet *RcmClient_getPacketAddr_P(
+        RcmClient_Message *     msg
+    );
+
+static inline
+RcmClient_Packet *getPacketAddrMsgqMsg(
+        MessageQ_Msg            msg
+    );
+
+static inline
+RcmClient_Packet *getPacketAddrElem(
+        List_Elem *             elem
+    );
+
+static Int RcmClient_getReturnMsg_P(
+        RcmClient_Object *      obj,
+        const UInt16            msgId,
+        RcmClient_Message **    returnMsg
+    );
+
+static
+Int RcmClient_Instance_init(
+        RcmClient_Object *              obj,
+        String                          server,
+        const RcmClient_Params *        params
+    );
+
+static
+Int RcmClient_Instance_finalize(
+        RcmClient_Object *      obj
+    );
+
+
+#define RcmClient_Module_heap() (RcmClient_Mod.heap)
+
+/* static objects */
+static Int curInit = 0;
+
+static RcmClient_Module RcmClient_Mod = {
+    "ti.rcm.RcmClient",     /* name */
+    (Bits16)0,                  /* id */
+    (Bits16)0,                  /* diagsMask */
+    (IHeap_Handle)NULL          /* heap */
+};
+
+/* module diags mask */
+Registry_Desc Registry_CURDESC;
+
+
+/*
+ *  ======== RcmClient_init ========
+ *
+ *  This function *must* be serialized by the caller
+ */
+Void RcmClient_init(Void)
+{
+    Registry_Result result;
+
+
+    if (curInit++ != 0) {
+        return; /* module already initialized */
+    }
+
+    /* register with xdc.runtime to get a diags mask */
+    result = Registry_addModule(&Registry_CURDESC, MODULE_NAME);
+    Assert_isTrue(result == Registry_SUCCESS, (Assert_Id)NULL);
+
+    /* the size of object and struct must be the same */
+    Assert_isTrue(sizeof(RcmClient_Object) == sizeof(RcmClient_Struct), NULL);
+}
+
+
+/*
+ *  ======== RcmClient_exit ========
+ *
+ *  This function *must* be serialized by the caller
+ */
+Void RcmClient_exit(Void)
+{
+//  Registry_Result result;
+
+
+    if (--curInit != 0) {
+        return; /* module still in use */
+    }
+
+    /* unregister from xdc.runtime */
+//  result = Registry_removeModule(MODULE_NAME);
+//  Assert_isTrue(result == Registry_SUCCESS, (Assert_Id)NULL);
+}
+
+
+/*
+ *  ======== RcmClient_Params_init ========
+ */
+Void RcmClient_Params_init(RcmClient_Params *params)
+{
+    params->heapId = RcmClient_INVALIDHEAPID;
+    params->callbackNotification = FALSE;
+}
+
+
+/*
+ *  ======== RcmClient_create ========
+ */
+#define FXNN "RcmClient_create"
+Int RcmClient_create(String server, const RcmClient_Params *params,
+        RcmClient_Handle *handle)
+{
+    RcmClient_Object *obj;
+    Error_Block eb;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> %s: ()", (IArg)FXNN);
+
+    /* initialize the error block */
+    Error_init(&eb);
+    *handle = (RcmClient_Handle)NULL;
+
+    /* TODO: add check that params was initialized correctly */
+
+    /* allocate the object */
+    obj = (RcmClient_Handle)xdc_runtime_Memory_calloc(RcmClient_Module_heap(),
+        sizeof(RcmClient_Object), sizeof(Int), &eb);
+
+    if (NULL == obj) {
+        Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+            (IArg)RcmClient_Module_heap(), sizeof(RcmClient_Object));
+        status = RcmClient_E_NOMEMORY;
+        goto leave;
+    }
+
+    Log_print1(Diags_LIFECYCLE, FXNN": instance create: 0x%x", (IArg)obj);
+
+    /* object-specific initialization */
+    status = RcmClient_Instance_init(obj, server, params);
+
+    if (status < 0) {
+        RcmClient_Instance_finalize(obj);
+        xdc_runtime_Memory_free(RcmClient_Module_heap(),
+            (Ptr)obj, sizeof(RcmClient_Object));
+        goto leave;
+    }
+
+    /* success, return opaque pointer */
+    *handle = (RcmClient_Handle)obj;
+
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_construct ========
+ */
+#define FXNN "RcmClient_construct"
+Int RcmClient_construct(RcmClient_Struct *structPtr, String server,
+    const RcmClient_Params *params)
+{
+    RcmClient_Object *obj = (RcmClient_Object*)structPtr;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> %s: ()", (IArg)FXNN);
+
+    /* TODO: add check that params was initialized correctly */
+
+    Log_print1(Diags_LIFECYCLE, FXNN": instance construct: 0x%x", (IArg)obj);
+
+    /* ensure the constructed object is zeroed */
+    _memset((Void *)obj, 0, sizeof(RcmClient_Object));
+
+    /* object-specific initialization */
+    status = RcmClient_Instance_init(obj, server, params);
+
+    if (status < 0) {
+        RcmClient_Instance_finalize(obj);
+        goto leave;
+    }
+
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_Instance_init ========
+ */
+#define FXNN "RcmClient_Instance_init"
+Int RcmClient_Instance_init(RcmClient_Object *obj, String server,
+        const RcmClient_Params *params)
+{
+    Error_Block eb;
+    MessageQ_Params mqParams;
+    SyncSemThread_Params syncParams;
+    SemThread_Params semParams;
+    SemThread_Handle semHndl;
+    List_Params listP;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY, "--> %s: (obj=0x%x)", (IArg)FXNN, (IArg)obj);
+
+    /* must initialize error block */
+    Error_init(&eb);
+
+    /* initialize instance data */
+    obj->msgId = 0xFFFF;
+    obj->sync = NULL;
+    obj->serverMsgQ = MessageQ_INVALIDMESSAGEQ;
+    obj->msgQue = NULL;
+    obj->errorMsgQue = NULL;
+    obj->mbxLock = NULL;
+    obj->queueLock = NULL;
+    obj->recipients = NULL;
+    obj->newMail = NULL;
+
+    /* create the instance gate */
+    GateThread_construct(&obj->gate, NULL, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create gate object");
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+
+    /* create a synchronizer for the message queue */
+    SyncSemThread_Params_init(&syncParams);
+    obj->sync = SyncSemThread_create(&syncParams, &eb);
+
+    if (Error_check(&eb)) {
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+
+    /* create the message queue for return messages */
+    MessageQ_Params_init(&mqParams);
+    obj->msgQue = MessageQ_create(NULL, &mqParams);
+
+    if (obj->msgQue == NULL) {
+        Log_error0(FXNN": could not create return message queue");
+        status = RcmClient_E_MSGQCREATEFAILED;
+        goto leave;
+    }
+
+    /* create the message queue for error messages */
+    MessageQ_Params_init(&mqParams);
+    obj->errorMsgQue = MessageQ_create(NULL, &mqParams);
+
+    if (NULL == obj->errorMsgQue) {
+        Log_error0(FXNN": could not create error message queue");
+        status = RcmClient_E_MSGQCREATEFAILED;
+        goto leave;
+    }
+
+    /* locate server message queue */
+    rval = MessageQ_open(server, (MessageQ_QueueId *)(&obj->serverMsgQ));
+
+    if (MessageQ_E_NOTFOUND == rval) {
+        Log_error1(FXNN": given server not found, server=0x%x", (IArg)server);
+        status = RcmClient_E_SERVERNOTFOUND;
+        goto leave;
+    }
+    else if (status < 0) {
+        Log_error1(FXNN": could not open server message queue, server=0x%x",
+            (IArg)server);
+        status = RcmClient_E_MSGQOPENFAILED;
+        goto leave;
+    }
+
+    /* create callback server */
+    if ((obj->cbNotify = params->callbackNotification)) {
+        /* TODO create callback server thread */
+        /* make sure to free resources acquired by thread */
+        Error_raise(&eb, Error_E_generic, "Not Implemented", 0);
+        goto leave;
+    }
+
+    /* register the heapId used for message allocation */
+    if ((obj->heapId = params->heapId) == RcmClient_INVALIDHEAPID) {
+        Log_error0(FXNN": must specify a heap id in create params");
+        status = RcmClient_E_INVALIDHEAPID;
+        goto leave;
+    }
+
+    /* create the mailbox lock */
+    SemThread_Params_init(&semParams);
+    semHndl = SemThread_create(1, &semParams, &eb);
+    if (Error_check(&eb)) {
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+    obj->mbxLock = SemThread_Handle_upCast(semHndl);
+
+    /* create the message queue lock */
+    SemThread_Params_init(&semParams);
+    semHndl = SemThread_create(1, &semParams, &eb);
+    if (Error_check(&eb)) {
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+    obj->queueLock = SemThread_Handle_upCast(semHndl);
+
+    /* create the return message recipient list */
+#if defined(RCM_ti_ipc)
+    List_Params_init(&listP);
+    obj->recipients = List_create(&listP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmClient_E_LISTCREATEFAILED;
+        goto leave;
+    }
+#elif defined(RCM_ti_syslink)
+    List_Params_init(&listP);
+    obj->recipients = List_create(&listP, NULL);
+
+    if (NULL == obj->recipients) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmClient_E_LISTCREATEFAILED;
+        goto leave;
+    }
+#endif
+
+    /* create list of undelivered messages (new mail) */
+#if defined(RCM_ti_ipc)
+    List_Params_init(&listP);
+    obj->newMail = List_create(&listP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmClient_E_LISTCREATEFAILED;
+        goto leave;
+    }
+#elif defined(RCM_ti_syslink)
+    List_Params_init(&listP);
+    obj->newMail = List_create(&listP, NULL);
+
+    if (NULL == obj->newMail) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmClient_E_LISTCREATEFAILED;
+        goto leave;
+    }
+#endif
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_delete ========
+ */
+#define FXNN "RcmClient_delete"
+Int RcmClient_delete(RcmClient_Handle *handlePtr)
+{
+    RcmClient_Object *obj = (RcmClient_Object *)(*handlePtr);
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> %s: ()", (IArg)FXNN);
+
+    /* finalize the object */
+    status = RcmClient_Instance_finalize(obj);
+
+    /* free the object memory */
+    Log_print1(Diags_LIFECYCLE, FXNN": instance delete: 0x%x", (IArg)obj);
+
+    xdc_runtime_Memory_free(RcmClient_Module_heap(),
+        (Ptr)obj, sizeof(RcmClient_Object));
+    *handlePtr = NULL;
+
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_destruct ========
+ */
+#define FXNN "RcmClient_destruct"
+Int RcmClient_destruct(RcmClient_Struct *structPtr)
+{
+    RcmClient_Object *obj = (RcmClient_Object *)(structPtr);
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> %s: ()", (IArg)FXNN);
+    Log_print1(Diags_LIFECYCLE, FXNN": instance destruct: 0x%x", (IArg)obj);
+
+    /* finalize the object */
+    status = RcmClient_Instance_finalize(obj);
+
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_Instance_finalize ========
+ */
+#define FXNN "RcmClient_Instance_finalize"
+Int RcmClient_Instance_finalize(RcmClient_Object *obj)
+{
+    SemThread_Handle semH;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (obj=0x%x)", (IArg)obj);
+
+    if (NULL != obj->newMail) {
+        List_delete(&obj->newMail);
+    }
+
+    if (NULL != obj->recipients) {
+        List_delete(&obj->recipients);
+    }
+
+    if (NULL != obj->queueLock) {
+        semH = SemThread_Handle_downCast(obj->queueLock);
+        SemThread_delete(&semH);
+        obj->queueLock = NULL;
+    }
+
+    if (NULL != obj->mbxLock) {
+        semH = SemThread_Handle_downCast(obj->mbxLock);
+        SemThread_delete(&semH);
+        obj->mbxLock = NULL;
+    }
+
+    if (MessageQ_INVALIDMESSAGEQ != obj->serverMsgQ) {
+        MessageQ_close((MessageQ_QueueId *)(&obj->serverMsgQ));
+    }
+
+    if (NULL != obj->errorMsgQue) {
+        MessageQ_delete(&obj->errorMsgQue);
+    }
+
+    if (NULL != obj->msgQue) {
+        MessageQ_delete(&obj->msgQue);
+    }
+
+    if (NULL != obj->sync) {
+        SyncSemThread_delete((SyncSemThread_Handle *)(&obj->sync));
+    }
+
+    /* destruct the instance gate */
+    GateThread_destruct(&obj->gate);
+
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_acquireJobId ========
+ */
+#define FXNN "RcmClient_acquireJobId"
+Int RcmClient_acquireJobId(RcmClient_Object *obj, UInt16 *jobIdPtr)
+{
+    RcmClient_Message *msg;
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    UInt16 msgId;
+    Int rval;
+    UInt16 serverStatus;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, jobIdPtr=0x%x)", (IArg)obj, (IArg)jobIdPtr);
+
+    /* allocate a message */
+    status = RcmClient_alloc(obj, sizeof(UInt16), &msg);
+
+    if (status < 0) {
+        goto leave;
+    }
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(msg);
+    packet->desc |= RcmClient_Desc_JOB_ACQ << RcmClient_Desc_TYPE_SHIFT;
+    msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+
+    /* get the return message from the server */
+    status = RcmClient_getReturnMsg_P(obj, msgId, &msg);
+
+    if (status < 0) {
+        goto leave;
+    }
+
+    /* check message status for error */
+    packet = RcmClient_getPacketAddr_P(msg);
+    serverStatus = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+            RcmClient_Desc_TYPE_SHIFT;
+
+    switch (serverStatus) {
+        case RcmServer_Status_SUCCESS:
+            break;
+
+        default:
+            Log_error1(FXNN": server returned error %d", (IArg)serverStatus);
+            status = RcmClient_E_SERVERERROR;
+            goto leave;
+    }
+
+    /* extract return value */
+    *jobIdPtr = (UInt16)(msg->data[0]);
+
+
+leave:
+    if (msg != NULL) {
+        RcmClient_free(obj, msg);
+    }
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_addSymbol ========
+ */
+#define FXNN "RcmClient_addSymbol"
+Int RcmClient_addSymbol(RcmClient_Object *obj, String name,
+        Fxn address, UInt32 *index)
+{
+//  Int status = RcmClient_S_SUCCESS;
+    Int status = RcmClient_E_FAIL;
+
+
+    Log_print2(Diags_ENTRY, "--> %s: (obj=0x%x)", (IArg)FXNN, (IArg)obj);
+
+    /* TODO */
+
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_alloc ========
+ */
+#define FXNN "RcmClient_alloc"
+Int RcmClient_alloc(RcmClient_Object *obj, UInt32 dataSize,
+    RcmClient_Message **message)
+{
+    SizeT totalSize;
+    RcmClient_Packet *packet;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> RcmClient_alloc: obj: 0x%x, dataSize: %d, message: 0x%x",
+        (IArg)obj, (IArg)dataSize, (IArg)message);
+
+    /* ensure minimum size of UInt32[1] */
+    dataSize  = (dataSize < sizeof(UInt32) ? sizeof(UInt32) : dataSize);
+
+    /* total memory size (in chars) needed for headers and payload */
+    totalSize = sizeof(RcmClient_Packet) - sizeof(UInt32) + dataSize;
+
+    /* allocate the message */
+    packet = (RcmClient_Packet*)MessageQ_alloc(obj->heapId, totalSize);
+
+    if (NULL == packet) {
+        Log_error1(FXNN": could not allocate message, size = %u",
+            (IArg)totalSize);
+        status = RcmClient_E_MSGALLOCFAILED;
+        goto leave;
+    }
+
+    /* Log_info() */
+    Log_print2(Diags_INFO,
+        FXNN": RcmMessage allocated: addr=0x%x, size=%u (total size)",
+        (IArg)packet, (IArg)totalSize);
+
+    /* initialize the packet structure */
+    packet->desc = 0;
+    packet->msgId = RcmClient_genMsgId_P(obj);
+    packet->message.poolId = RcmClient_DEFAULTPOOLID;
+    packet->message.jobId = RcmClient_DISCRETEJOBID;
+    packet->message.fxnIdx = RcmClient_INVALIDFXNIDX;
+    packet->message.result = 0;
+    packet->message.dataSize = dataSize;
+
+    /* set message pointer to start of the message struct */
+    *message = (RcmClient_Message *)(&(packet->message));
+
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_checkForError ========
+ *  If success, no message will be returned. If error message returned,
+ *  then function return value will always be < 0.
+ *
+ *  status      msgPtr
+ *  --------------------
+ *  success     null (always)
+ *  < 0         null (internal error)
+ *  < 0         msg  (error message returned)
+ */
+#define FXNN "RcmClient_checkForError"
+Int RcmClient_checkForError(RcmClient_Object *obj, RcmClient_Message **rtnMsg)
+{
+    RcmClient_Message *rcmMsg;
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    UInt16 serverStatus;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, rtnMsg=0x%x)", (IArg)rtnMsg);
+
+    *rtnMsg = NULL;
+
+    /* get error message if available (non-blocking) */
+    rval = MessageQ_get(obj->errorMsgQue, &msgqMsg, 0);
+
+    if ((MessageQ_E_TIMEOUT != rval) && (rval < 0)) {
+        Log_error1(FXNN": MessageQ_get() returned error %d", (IArg)rval);
+        status = RcmClient_E_IPCERROR;
+        goto leave;
+    }
+    else if (msgqMsg == NULL) {
+        goto leave;
+    }
+
+    /* received an error message */
+    packet = getPacketAddrMsgqMsg(msgqMsg);
+    rcmMsg = &packet->message;
+    *rtnMsg = rcmMsg;
+
+    /* check the server status stored in the packet header */
+    serverStatus = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+            RcmClient_Desc_TYPE_SHIFT;
+
+    switch (serverStatus) {
+        case RcmServer_Status_JobNotFound:
+            Log_error1(FXNN": job id=%d not found", (IArg)rcmMsg->jobId);
+            break;
+
+        case RcmServer_Status_PoolNotFound:
+            Log_error1(FXNN": pool id=0x%x not found", (IArg)rcmMsg->poolId);
+            break;
+
+        case RcmServer_Status_INVALID_FXN:
+            Log_error1(FXNN": invalid function index: 0x%x",
+                (IArg)rcmMsg->fxnIdx);
+            status = RcmClient_E_INVALIDFXNIDX;
+            break;
+
+        case RcmServer_Status_MSG_FXN_ERR:
+            Log_error1(FXNN": message function error %d", (IArg)rcmMsg->result);
+            status = RcmClient_E_MSGFXNERROR;
+            break;
+
+        default:
+            Log_error1(FXNN": server returned error %d", (IArg)serverStatus);
+            status = RcmClient_E_SERVERERROR;
+            goto leave;
+    }
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_exec ========
+ */
+#define FXNN "RcmClient_exec"
+Int RcmClient_exec(RcmClient_Object *obj,
+        RcmClient_Message *cmdMsg, RcmClient_Message **returnMsg)
+{
+    RcmClient_Packet *packet;
+    RcmClient_Message *rtnMsg;
+    MessageQ_Msg msgqMsg;
+    UInt16 msgId;
+    UInt16 serverStatus;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (cmdMsg=0x%x, rtnMsg=0x%x)", (IArg)obj, (IArg)returnMsg);
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(cmdMsg);
+    packet->desc |= RcmClient_Desc_RCM_MSG << RcmClient_Desc_TYPE_SHIFT;
+    msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    status = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (status < 0) {
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_EXECFAILED;
+        goto leave;
+    }
+
+    /* get the return message from the server */
+    rval = RcmClient_getReturnMsg_P(obj, msgId, &rtnMsg);
+
+    if (rval < 0) {
+        *returnMsg = NULL;
+        status = rval;
+        goto leave;
+    }
+    *returnMsg = rtnMsg;
+
+    /* check the server's status stored in the packet header */
+    packet = RcmClient_getPacketAddr_P(rtnMsg);
+    serverStatus = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+            RcmClient_Desc_TYPE_SHIFT;
+
+    switch (serverStatus) {
+        case RcmServer_Status_SUCCESS:
+            break;
+
+        case RcmServer_Status_INVALID_FXN:
+            Log_error1(FXNN": invalid function index: 0x%x",
+                (IArg)rtnMsg->fxnIdx);
+            status = RcmClient_E_INVALIDFXNIDX;
+            goto leave;
+
+        case RcmServer_Status_MSG_FXN_ERR:
+            Log_error1(FXNN": message function error %d", (IArg)rtnMsg->result);
+            status = RcmClient_E_MSGFXNERROR;
+            goto leave;
+
+        default:
+            Log_error1(FXNN": server returned error %d", (IArg)serverStatus);
+            status = RcmClient_E_SERVERERROR;
+            goto leave;
+    }
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_execAsync ========
+ */
+#define FXNN "RcmClient_execAsync"
+Int RcmClient_execAsync(RcmClient_Object *obj, RcmClient_Message *cmdMsg,
+    RcmClient_CallbackFxn callback, Ptr appData)
+{
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> %s: 0x%x, 0x%x", (IArg)FXNN, (IArg)obj, (IArg)cmdMsg);
+
+    /* cannot use this function if callback notification is false */
+    if (!obj->cbNotify) {
+        Log_error0(FXNN": asynchronous notification not enabled");
+        status = RcmClient_E_EXECASYNCNOTENABLED;
+        goto leave;
+    }
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(cmdMsg);
+    packet->desc |= RcmClient_Desc_RCM_MSG << RcmClient_Desc_TYPE_SHIFT;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_EXECFAILED;
+        goto leave;
+    }
+
+    /* TODO finish this function */
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_execCmd ========
+ */
+#define FXNN "RcmClient_execCmd"
+Int RcmClient_execCmd(RcmClient_Object *obj, RcmClient_Message *msg)
+{
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY | Diags_INFO,
+        "--> "FXNN": (obj=0x%x, msg=0x%x)", (IArg)obj, (IArg)msg);
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(msg);
+    packet->desc |= RcmClient_Desc_CMD << RcmClient_Desc_TYPE_SHIFT;
+
+    /* set the return address to the error message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->errorMsgQue, msgqMsg);
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        Log_error0(FXNN": unable to send message to server");
+        status = RcmClient_E_IPCERROR;
+    }
+
+    Log_print1(Diags_EXIT | Diags_INFO, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_execDpc ========
+ */
+#define FXNN "RcmClient_execDpc"
+Int RcmClient_execDpc(RcmClient_Object *obj,
+    RcmClient_Message *cmdMsg, RcmClient_Message **returnMsg)
+{
+    RcmClient_Packet *packet;
+    RcmClient_Message *rtnMsg;
+    MessageQ_Msg msgqMsg;
+    UInt16 msgId;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> %s: 0x%x, 0x%x", (IArg)FXNN, (IArg)obj, (IArg)returnMsg);
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(cmdMsg);
+    packet->desc |= RcmClient_Desc_DPC << RcmClient_Desc_TYPE_SHIFT;
+    msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        /* Log_error() */
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_EXECFAILED;
+        goto leave;
+    }
+
+    /* get the return message from the server */
+    rval = RcmClient_getReturnMsg_P(obj, msgId, &rtnMsg);
+
+    if (rval < 0) {
+        *returnMsg = NULL;
+        status = rval;
+        goto leave;
+    }
+    *returnMsg = rtnMsg;
+
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_execNoWait ========
+ */
+#define FXNN "RcmClient_execNoWait"
+Int RcmClient_execNoWait(RcmClient_Object *obj, RcmClient_Message *cmdMsg,
+    UInt16 *msgId)
+{
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print4(Diags_ENTRY,
+        "--> %s: 0x%x, 0x%x, 0x%x",
+        (IArg)FXNN, (IArg)obj, (IArg)cmdMsg, (IArg)msgId);
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(cmdMsg);
+    packet->desc |= RcmClient_Desc_RCM_MSG << RcmClient_Desc_TYPE_SHIFT;
+    *msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    Log_print1(Diags_ANALYSIS, "%s: >>> MessageQ_put", (IArg)FXNN);
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+    Log_print1(Diags_ANALYSIS, "%s: <<< MessageQ_put", (IArg)FXNN);
+
+    if (rval < 0) {
+        *msgId = RcmClient_INVALIDMSGID;
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_EXECFAILED;
+        goto leave;
+    }
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_free ========
+ */
+#define FXNN "RcmClient_free"
+Int RcmClient_free(RcmClient_Object *obj, RcmClient_Message *msg)
+{
+    Int rval;
+    MessageQ_Msg msgqMsg;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, msg=0x%x)", (IArg)obj, (IArg)msg);
+
+    msgqMsg = (MessageQ_Msg)RcmClient_getPacketAddr_P(msg);
+    rval = MessageQ_free(msgqMsg);
+
+    if (rval < 0) {
+        Log_error1(FXNN": ipc returned error %d", (IArg)rval);
+        status = RcmClient_E_IPCERROR;
+        goto leave;
+    }
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_getSymbolIndex ========
+ */
+#define FXNN "RcmClient_getSymbolIndex"
+Int RcmClient_getSymbolIndex(RcmClient_Object *obj, String name, UInt32 *index)
+{
+    SizeT len;
+    RcmClient_Packet *packet;
+    UInt16 msgId;
+    MessageQ_Msg msgqMsg;
+    Int rval;
+    UInt16 serverStatus;
+    RcmClient_Message *rcmMsg = NULL;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, name=0x%x, index=0x%x",
+        (IArg)obj, (IArg)name, (IArg)index);
+
+    /* allocate a message */
+    len = _strlen(name) + 1;
+    rval = RcmClient_alloc(obj, len, &rcmMsg);
+
+    if (rval < 0) {
+        status = rval;
+        goto leave;
+    }
+
+    /* copy the function name into the message payload */
+    rcmMsg->dataSize = len;  //TODO this is not proper!
+    _strcpy((Char *)rcmMsg->data, name);
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(rcmMsg);
+    packet->desc |= RcmClient_Desc_SYM_IDX << RcmClient_Desc_TYPE_SHIFT;
+    msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_EXECFAILED;
+        goto leave;
+    }
+
+    /* get the return message from the server */
+    rval = RcmClient_getReturnMsg_P(obj, msgId, &rcmMsg);
+
+    if (rval < 0) {
+        status = rval;
+        goto leave;
+    }
+
+    /* check message status for error */
+    packet = RcmClient_getPacketAddr_P(rcmMsg);
+    serverStatus = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+            RcmClient_Desc_TYPE_SHIFT;
+
+    switch (serverStatus) {
+        case RcmServer_Status_SUCCESS:
+            break;
+
+        case RcmServer_Status_SYMBOL_NOT_FOUND:
+            Log_error1(FXNN": symbol not found, name=0x%x", (IArg)name);
+            status = RcmClient_E_SYMBOLNOTFOUND;
+            goto leave;
+
+        default:
+            Log_error1(FXNN": server returned error %d", (IArg)serverStatus);
+            status = RcmClient_E_SERVERERROR;
+            goto leave;
+    }
+
+    /* extract return value */
+    *index = rcmMsg->data[0];
+
+
+leave:
+    if (rcmMsg != NULL) {
+        RcmClient_free(obj, rcmMsg);
+    }
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_releaseJobId ========
+ */
+#define FXNN "RcmClient_releaseJobId"
+Int RcmClient_releaseJobId(RcmClient_Object *obj, UInt16 jobId)
+{
+    RcmClient_Message *msg;
+    RcmClient_Packet *packet;
+    MessageQ_Msg msgqMsg;
+    UInt16 msgId;
+    Int rval;
+    UInt16 serverStatus;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, jobId=0x%x)", (IArg)obj, (IArg)jobId);
+
+    /* allocate a message */
+    status = RcmClient_alloc(obj, sizeof(UInt16), &msg);
+
+    if (status < 0) {
+        goto leave;
+    }
+
+    /* classify this message */
+    packet = RcmClient_getPacketAddr_P(msg);
+    packet->desc |= RcmClient_Desc_JOB_REL << RcmClient_Desc_TYPE_SHIFT;
+    msgId = packet->msgId;
+
+    /* set the return address to this instance's message queue */
+    msgqMsg = (MessageQ_Msg)packet;
+    MessageQ_setReplyQueue(obj->msgQue, msgqMsg);
+
+    /* marshal the job id into the message payload */
+    *(UInt16 *)(&msg->data[0]) = jobId;
+
+    /* send the message to the server */
+    rval = MessageQ_put((MessageQ_QueueId)obj->serverMsgQ, msgqMsg);
+
+    if (rval < 0) {
+        Log_error0(FXNN": unable to the send message to the server");
+        status = RcmClient_E_FAIL;
+        goto leave;
+    }
+
+    /* get the return message from the server */
+    status = RcmClient_getReturnMsg_P(obj, msgId, &msg);
+
+    if (status < 0) {
+        goto leave;
+    }
+
+    /* check message status for error */
+    packet = RcmClient_getPacketAddr_P(msg);
+    serverStatus = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+            RcmClient_Desc_TYPE_SHIFT;
+
+    switch (serverStatus) {
+        case RcmServer_Status_SUCCESS:
+            break;
+
+        case RcmServer_Status_JobNotFound:
+            Log_error1(FXNN": jobId=%d not found on server", (IArg)jobId);
+            status = RcmClient_E_JOBIDNOTFOUND;
+            break;
+
+        default:
+            Log_error1(FXNN": server returned error %d", (IArg)serverStatus);
+            status = RcmClient_E_SERVERERROR;
+            break;
+    }
+
+
+leave:
+    if (msg != NULL) {
+        RcmClient_free(obj, msg);
+    }
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+
+}
+#undef FXNN
+
+/*
+ *  ======== RcmClient_removeSymbol ========
+ */
+#define FXNN "RcmClient_removeSymbol"
+Int RcmClient_removeSymbol(RcmClient_Object *obj, String name)
+{
+//  Int status = RcmClient_S_SUCCESS;
+    Int status = RcmClient_E_FAIL;
+
+
+    Log_print2(Diags_ENTRY, "--> %s: (obj=0x%x)", (IArg)FXNN, (IArg)obj);
+
+    /* TODO */
+
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_waitUntilDone ========
+ */
+#define FXNN "RcmClient_waitUntilDone"
+Int RcmClient_waitUntilDone(RcmClient_Object *obj,
+    UInt16 msgId, RcmClient_Message **returnMsg)
+{
+    RcmClient_Message *rtnMsg;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print4(Diags_ENTRY, "--> %s: (obj=0x%x, msgId=%d, msg=0x%x)",
+        (IArg)FXNN, (IArg)obj, (IArg)msgId, (IArg)returnMsg);
+
+    /* get the return message from the server */
+    rval = RcmClient_getReturnMsg_P(obj, msgId, &rtnMsg);
+
+    if (rval < 0) {
+        *returnMsg = NULL;
+        status = rval;
+        goto leave;
+    }
+    *returnMsg = rtnMsg;
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_genMsgId_P ========
+ */
+UInt16 RcmClient_genMsgId_P(RcmClient_Object *obj)
+{
+    GateThread_Handle gateH;
+    IArg key;
+    UInt16 msgId;
+
+
+    gateH = GateThread_handle(&obj->gate);
+    key = GateThread_enter(gateH);
+
+    msgId = (obj->msgId == 0xFFFF ? obj->msgId = 1 : ++(obj->msgId));
+
+    GateThread_leave(gateH, key);
+
+    return(msgId);
+}
+
+
+/*
+ *  ======== RcmClient_getReturnMsg_P ========
+ *  A thread safe algorithm for message delivery
+ *
+ *  This function is called to pickup a specified return message from
+ *  the server. Messages are taken from the queue and either delivered
+ *  to the mailbox if not the specified message or returned to the caller.
+ *  The calling thread might take the role of mailman or simply wait
+ *  on a list of recipients.
+ *
+ *  This algorithm guarantees that a waiting recipient is released as soon
+ *  as his message arrives. All new unclaimed mail is placed in the mailbox
+ *  until the recipient arrives to collect it. The messages can arrive in
+ *  any order and will be processed as they arrive. Message delivery is never
+ *  stalled waiting on an absent recipient.
+ */
+#define FXNN "RcmClient_getReturnMsg_P"
+Int RcmClient_getReturnMsg_P(RcmClient_Object *obj, const UInt16 msgId,
+    RcmClient_Message **returnMsg)
+{
+    List_Elem *elem;
+    Recipient *recipient;
+    RcmClient_Packet *packet;
+    Bool messageDelivered;
+    MessageQ_Msg msgqMsg = NULL;
+    Bool messageFound = FALSE;
+    Int queueLockAcquired = 0;
+    Error_Block eb;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, msgId=%d, returnMsgPtr=0x%x",
+        (IArg)obj, (IArg)msgId, (IArg)returnMsg);
+
+    Error_init(&eb);
+    *returnMsg = NULL;
+
+    /* keep trying until message found */
+    while (!messageFound) {
+
+        /* acquire the mailbox lock */
+        Semaphore_pend(obj->mbxLock, Semaphore_FOREVER, &eb);
+        if (Error_check(&eb)) {
+            /* TODO */
+            goto leave;
+        }
+
+        /* search new mail list for message */
+        elem = NULL;
+        while ((elem = List_next(obj->newMail, elem)) != NULL) {
+            packet = getPacketAddrElem(elem);
+            if (msgId == packet->msgId) {
+                List_remove(obj->newMail, elem);
+                *returnMsg = &packet->message;
+                messageFound = TRUE;
+                break;
+            }
+        }
+
+        if (messageFound) {
+            /* release the mailbox lock */
+            Semaphore_post(obj->mbxLock, &eb);
+            if (Error_check(&eb)) {
+                /* TODO */
+            }
+        }
+        else {
+            /* attempt the message queue lock */
+            queueLockAcquired = Semaphore_pend(obj->queueLock, 0, &eb);
+            if (Error_check(&eb)) {
+                /* TODO */
+                goto leave;
+            }
+
+            if (1 == queueLockAcquired) {
+                /*
+                 * mailman role
+                 */
+
+                /* deliver new mail until message found */
+                while (!messageFound) {
+
+                    /* get message from queue if available (non-blocking) */
+                    if (NULL == msgqMsg) {
+                        rval = MessageQ_get(obj->msgQue, &msgqMsg, 0);
+
+                        if ((MessageQ_E_TIMEOUT != rval) && (rval < 0)) {
+                            Log_error0(FXNN": lost return message");
+                            status = RcmClient_E_LOSTMSG;
+                            goto leave;
+                        }
+                        Log_print0(Diags_INFO, FXNN": return message received");
+                    }
+
+                    while (NULL != msgqMsg) {
+
+                        /* check if message found */
+                        packet = getPacketAddrMsgqMsg(msgqMsg);
+                        messageFound = (msgId == packet->msgId);
+
+                        if (messageFound) {
+                            *returnMsg = &packet->message;
+
+                            /* search wait list for new mailman */
+                            elem = NULL;
+                            while ((elem =
+                                List_next(obj->recipients, elem)) != NULL) {
+                                recipient = (Recipient *)elem;
+                                if (NULL == recipient->msg) {
+                                    /* signal recipient's event */
+                                    SemThread_post(SemThread_handle(
+                                        &recipient->event), &eb);
+                                    break;
+                                }
+                            }
+
+                            /* release the message queue lock */
+                            Semaphore_post(obj->queueLock, &eb);
+                            if (Error_check(&eb)) {
+                                /* TODO */
+                            }
+
+                            /* release the mailbox lock */
+                            Semaphore_post(obj->mbxLock, &eb);
+                            if (Error_check(&eb)) {
+                                /* TODO */
+                            }
+
+                            break;
+                        }
+                        else {
+                            /*
+                             * deliver message to mailbox
+                             */
+
+                            /* search recipient list for message owner */
+                            elem = NULL;
+                            messageDelivered = FALSE;
+                            while ((elem =
+                                List_next(obj->recipients, elem)) != NULL) {
+                                recipient = (Recipient *)elem;
+                                if (recipient->msgId == packet->msgId) {
+                                    recipient->msg = &packet->message;
+                                    /* signal the recipient's event */
+                                    SemThread_post(SemThread_handle(
+                                        &recipient->event), &eb);
+                                    messageDelivered = TRUE;
+                                    break;
+                                }
+                            }
+
+                            /* add undelivered message to new mail list */
+                            if (!messageDelivered) {
+                                /* use the elem in the MessageQ header */
+                                elem = (List_Elem *)&packet->msgqHeader;
+                                List_put(obj->newMail, elem);
+                            }
+                        }
+
+                        /* get next message from queue if available */
+                        rval = MessageQ_get(obj->msgQue, &msgqMsg, 0);
+
+                        if ((MessageQ_E_TIMEOUT != rval) && (rval < 0)) {
+                            Log_error0(FXNN": lost return message");
+                            status = RcmClient_E_LOSTMSG;
+                            goto leave;
+                        }
+                        Log_print0(Diags_INFO, FXNN": return message received");
+                    }
+
+                    if (!messageFound) {
+                        /*
+                         * message queue empty
+                         */
+
+                        /* release the mailbox lock */
+                        Semaphore_post(obj->mbxLock, &eb);
+                        if (Error_check(&eb)) {
+                            /* TODO */
+                        }
+
+                        /* get next message, this blocks the thread */
+                        rval = MessageQ_get(obj->msgQue, &msgqMsg,
+                            MessageQ_FOREVER);
+
+                        if (rval < 0) {
+                            Log_error0(FXNN": lost return message");
+                            status = RcmClient_E_LOSTMSG;
+                            goto leave;
+                        }
+                        Log_print0(Diags_INFO, FXNN": return message received");
+
+                        if (msgqMsg == NULL) {
+                            Log_error0(FXNN": reply message has been lost");
+                            status = RcmClient_E_LOSTMSG;
+                            goto leave;
+                        }
+
+                        /* acquire the mailbox lock */
+                        Semaphore_pend(obj->mbxLock, Semaphore_FOREVER, &eb);
+                        if (Error_check(&eb)) {
+                            goto leave;  /* TODO */
+                        }
+                    }
+                }
+            }
+            else {
+                /* construct recipient on local stack */
+                Recipient self;
+                self.msgId = msgId;
+                self.msg = NULL;
+                SemThread_construct(&self.event, 0, NULL, &eb);
+                if (Error_check(&eb)) {
+                    /* TODO */
+                }
+
+                /* add recipient to wait list */
+                elem = &self.elem;
+                List_put(obj->recipients, elem);
+
+                /* release the mailbox lock */
+                Semaphore_post(obj->mbxLock, &eb);
+                if (Error_check(&eb)) {
+                    /* TODO */
+                }
+
+                /* wait on event */
+                SemThread_pend(SemThread_handle(&self.event),
+                    Semaphore_FOREVER, &eb);
+                if (Error_check(&eb)) {
+                    /* TODO */
+                }
+
+                /* acquire the mailbox lock */
+                Semaphore_pend(obj->mbxLock, Semaphore_FOREVER, &eb);
+                if (Error_check(&eb)) {
+                    goto leave;  /* TODO */
+                }
+
+                if (NULL != self.msg) {
+                    /* pickup message */
+                    *returnMsg = self.msg;
+                    messageFound = TRUE;
+                }
+
+                /* remove recipient from wait list */
+                List_remove(obj->recipients, elem);
+                SemThread_destruct(&self.event);
+
+                /* release the mailbox lock */
+                Semaphore_post(obj->mbxLock, &eb);
+                if (Error_check(&eb)) {
+                    /* TODO */
+                }
+            }
+        }
+    } /* while (!messageFound) */
+
+leave:
+    Log_print2(Diags_EXIT, "<-- %s: %d", (IArg)FXNN, (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmClient_getPacketAddr_P ========
+ */
+RcmClient_Packet *RcmClient_getPacketAddr_P(RcmClient_Message *msg)
+{
+    Int offset = (Int)&(((RcmClient_Packet *)0)->message);
+    return ((RcmClient_Packet *)((Char *)msg - offset));
+}
+
+
+/*
+ *  ======== getPacketAddrMsgqMsg ========
+ */
+static inline
+RcmClient_Packet *getPacketAddrMsgqMsg(MessageQ_Msg msg)
+{
+    Int offset = (Int)&(((RcmClient_Packet *)0)->msgqHeader);
+    return ((RcmClient_Packet *)((Char *)msg - offset));
+}
+
+
+/*
+ *  ======== getPacketAddrElem ========
+ */
+static inline
+RcmClient_Packet *getPacketAddrElem(List_Elem *elem)
+{
+    Int offset = (Int)&(((RcmClient_Packet *)0)->msgqHeader);
+    return ((RcmClient_Packet *)((Char *)elem - offset));
+}
diff --git a/packages/ti/grcm/RcmClient.h b/packages/ti/grcm/RcmClient.h
new file mode 100644 (file)
index 0000000..133a10a
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmClient.h ========
+ *
+ */
+
+/*!
+ *  @file ti/grcm/RcmClient.h
+ *
+ *  @brief Remote Command Message Client Module. An RcmClient is used
+ *  for sending messages to an RcmServer for processing.
+ *
+ *  @sa RcmServer.h <br>
+ *  @ref ti_grcm "RCM Overview"
+ */
+
+/*!
+ *  @defgroup ti_grcm_RcmClient RcmClient
+ *
+ *  @brief Remote Command Message Client Module. An RcmClient is used
+ *  for sending messages to an RcmServer for processing.
+ *
+ *  The RcmClient module is used to send messages to an RcmServer for
+ *  processing. An RcmClient instance must be created which will
+ *  communicate with a single RcmServer instance. An RcmServer instance
+ *  can receive messages from many RcmClient instances but an RcmClient
+ *  instance can send messages to only one RcmServer instance.
+ *
+ *  <a name="error_handling"></a><h2>Error Handling</h2>
+ *
+ *  Errors may be raised at various points in the execution flow of a
+ *  single message. These are the types of errors raised by RCM:
+ *  - RCM Errors
+ *  - User Errors
+ *  - Message Function Errors
+ *  - Library Function Errors
+ *
+ *  The following diagram illustrates the call flow and highlights the
+ *  points at which errors can be raised.
+ *
+ *  @image html ti/grcm/doc-files/ExecFlow.png "Diagram 1: Execution Flow"
+ *
+ *  RCM errors are raised by the RCM implementation. For example, when
+ *  calling RcmClient_exec(), it may raise an error if it
+ *  is unable to send the message. This will be reported immediately to
+ *  the caller, the server is never involved. This is highlighted in the
+ *  diagram at point [A].
+ *
+ *  RCM errors may also be raised by the RcmServer. Once RcmClient_exec()
+ *  sends a message, it waits for the return message. When the server
+ *  receives the message, it has to decode its type. If this fails, the
+ *  server records this error in the message and sends it back to the
+ *  client. This is highlighted at point [B] in the diagram. When
+ *  RcmClient_exec() receives the return message, it inspects the status
+ *  field and recognizes the error. It then raises an appropriate error
+ *  to the caller.
+ *
+ *  User errors are raised by RCM as a result of an invalid runtime
+ *  condition. They are typically detected and raised by the server and
+ *  then sent back to the client for processing. For example, when the
+ *  server receives a message, it will lookup the function index in it's
+ *  table and invoke the corresponding message function. If the index is
+ *  invalid, this is detected by the server and reported as an error.
+ *  The message function is never invoked. The message is returned to
+ *  the client and RcmClient_exec() will raise the appropriate error.
+ *  This error is raised at point [B] in the diagram.
+ *
+ *  Message function errors are raised by the message function itself.
+ *  This is highlighted at point [C] in the diagram. In the body of the
+ *  message function, an error is encountered either when calling a
+ *  framework function or when unmarshalling the arguments from the
+ *  message payload. In both cases, the message function will abort and
+ *  return an error value as its return value. The error value must be
+ *  less than zero (< 0). When control returns to the server, it inspects
+ *  the message function's return value. If the message was sent by
+ *  RcmClient_exec(), then the server simply stores the return value in
+ *  the message and returns it to the client. However, if the message was
+ *  send by RcmClient_execCmd(), the behavior is slightly
+ *  different. If the return value is < 0 (error condition), then the
+ *  server behaves the same as for the RcmClient_exec() case. However,
+ *  if there is no error, the server simply frees the message. The message
+ *  is never returned to the client.
+ *
+ *  Library functions errors are raised by the library functions invoked
+ *  by the message function, highlighted at point [D] in the diagram. It
+ *  is the responsibility of the message function to detect a library
+ *  function error and to marshal the appropriate error code into the
+ *  message payload. The message function must also return an error value
+ *  (< 0) so that server can do proper error handing as described
+ *  in the preceeding paragraph. It is the stub function's responsibility
+ *  to unmarshal the error value from the message payload and take the
+ *  appropriate action.
+ *
+ *  Understanding the types of errors raised by RCM and where they are
+ *  raised is important when writing the upper layer software. The following
+ *  code fragment illustrates how to check for the errors discussed above.
+ *  See <a href"#error_handling">Error Handling</a> above.
+ *
+ *  @code
+ *  RcmClient_Message *msg;
+ *
+ *  // send message
+ *  status = RcmClient_exec(h, msg, &msg);
+ *
+ *  // check for error
+ *  switch (status) {
+ *
+ *      case RcmClient_S_SUCCESS:
+ *          // no error, all is well
+ *          break;
+ *
+ *      case RcmClient_E_EXECFAILED:
+ *          // RCM error, unable to send message
+ *          :
+ *          break;
+ *
+ *      case RcmClient_E_INVALIDFXNIDX:
+ *          // user error, bad function index
+ *          :
+ *          break;
+ *
+ *      case RcmClient_E_MSGFXNERROR:
+ *          // decode message function error
+ *          msgFxnErr = msg->result;
+ *          :
+ *          // decode library function error
+ *          libFxnErr = msg->data[0];
+ *          :
+ *          break;
+ *  }
+ *
+ *  // free message if one was returned
+ *  if (msg != NULL) {
+ *      RcmClient_free(h, msg);
+ *      msg = NULL;
+ *  }
+ *  @endcode
+ *
+ *  The upper layer software begins by calling RcmClient_exec()
+ *  to send the message to the server. If RCM encounters a transport error
+ *  and is unable to send the message, an RcmClient_E_EXECFAILED error is
+ *  returned.
+ *
+ *  If the server encounters an error while decoding the message, say an
+ *  invalid function index, the server returns the message and an
+ *  RcmClient_E_INVALIDFXNIDX error is returned.
+ *
+ *  If the message function or the library function encounter an error,
+ *  the message is returned and an RcmClient_E_MSGFXNERROR error is
+ *  returned. The upper layer software must decode the results field to
+ *  see what error the message function returned. If the library function
+ *  returned an error, its error code must be unmarshalled from the payload.
+ *  This is illustrated by decoding the first word in the payload
+ *  (msg->data[0]). The actual marshal format is implementation specific.
+ *
+ *  The message function must return >=0 for success, <0 for error.
+ *  Here is a very simple message function which simply turns on an LED.
+ *
+ *  @code
+ *  Int32 Led_On(UInt32 size, UInt32 *data)
+ *  {
+ *      Ptr led = <addr>;
+ *
+ *      *led = 1;  // turn on LED
+ *      return(0); // success
+ *  }
+ *  @endcode
+ *
+ *  In this example, the message payload is not used. The message function
+ *  does all the work, it just sets a bit in the LED control register, and
+ *  returns success.
+ *
+ *  This next example illustrates a very simple RPC style skel function.
+ *  It unmarshalls two arguments and invokes the libraray function. If the
+ *  library function succeeds, the message function returns 0, otherwise it
+ *  returns -1 to indicate failure. In both cases, the library function's
+ *  return value is marshalled into the payload. The calling stub function
+ *  can umarshal the return value to get the library function's error code.
+ *
+ *  @code
+ *  Int32 MediaSkel_process(UInt32 size, UInt32 *data)
+ *  {
+ *      Int a, b, x;
+ *      Int32 status = 0;  // success
+ *
+ *      // unmarshal args
+ *      a = (Int)data[1];
+ *      b = (Int)data[2];
+ *
+ *      // invoke library function, returns >=0 on success
+ *      x = Media_process(a, b);
+ *
+ *      // marshal return value
+ *      data[0] = (Int32)x;
+ *
+ *      // return status
+ *      return(x >= 0 ? 0 : -1);
+ *  }
+ *  @endcode
+ *
+ *  @sa ti_grcm_RcmServer <br>
+ *  @ref ti_grcm "RCM Overview"
+ */
+
+#ifndef ti_grcm_RcmClient__include
+#define ti_grcm_RcmClient__include
+
+#include <xdc/runtime/knl/GateThread.h>
+
+
+/** @ingroup ti_grcm_RcmClient */
+/*@{*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+// -------- status codes --------
+
+/*!
+ *  @brief Success return code
+ */
+#define RcmClient_S_SUCCESS (0)
+
+/*!
+ *  @brief General failure return code
+ */
+#define RcmClient_E_FAIL (-1)
+
+/*!
+ *  @brief The client has not been configured for asynchronous notification
+ *
+ *  In order to use the RcmClient_execAsync() function, the RcmClient
+ *  must be configured with callbackNotification set to true in the
+ *  instance create parameters.
+ */
+#define RcmClient_E_EXECASYNCNOTENABLED (-2)
+
+/*!
+ *  @brief The client was unable to send the command message to the server
+ *
+ *  An IPC transport error occurred. The message was never sent to the server.
+ */
+#define RcmClient_E_EXECFAILED (-3)
+
+/*!
+ *  @brief A heap id must be provided in the create params
+ *
+ *  When an RcmClient instance is created, a heap id must be given
+ *  in the create params. This heap id must be registered with MessageQ
+ *  before calling RcmClient_create().
+ */
+#define RcmClient_E_INVALIDHEAPID (-4)
+
+/*!
+ *  @brief Invalid function index
+ *
+ *  An RcmClient_Message was sent to the server which contained a
+ *  function index value (in the fxnIdx field) that was not found
+ *  in the server's function table.
+ */
+#define RcmClient_E_INVALIDFXNIDX (-5)
+
+/*!
+ *  @brief Message function error
+ *
+ *  There was an error encountered in either the message function or
+ *  the library function invoked by the message function. The semantics
+ *  of the error code are implementation dependent.
+ */
+#define RcmClient_E_MSGFXNERROR (-6)
+
+/*!
+ *  @brief An unknown error has been detected from the IPC layer
+ *
+ *  Check the error log for additional information.
+ */
+#define RcmClient_E_IPCERROR (-7)
+
+/*!
+ *  @brief Failed to create the list object
+ */
+#define RcmClient_E_LISTCREATEFAILED (-8)
+
+/*!
+ *  @brief The expected reply message from the server was lost
+ *
+ *  A command message was sent to the RcmServer but the reply
+ *  message was not received. This is an internal error.
+ */
+#define RcmClient_E_LOSTMSG (-9)
+
+/*!
+ *  @brief Insufficient memory to allocate a message
+ *
+ *  The message heap cannot allocate a buffer of the requested size.
+ *  The reported size it the requested data size and the underlying
+ *  message header size.
+ */
+#define RcmClient_E_MSGALLOCFAILED (-10)
+
+/*!
+ *  @brief The client message queue could not be created
+ *
+ *  Each RcmClient instance must create its own message queue for
+ *  receiving return messages from the RcmServer. The creation of
+ *  this message queue failed, thus failing the RcmClient instance
+ *  creation.
+ */
+#define RcmClient_E_MSGQCREATEFAILED (-11)
+
+/*!
+ *  @brief The server message queue could not be opened
+ *
+ *  Each RcmClient instance must open the server's message queue.
+ *  This error is raised when an internal error occurred while trying
+ *  to open the server's message queue.
+ */
+#define RcmClient_E_MSGQOPENFAILED (-12)
+
+/*!
+ *  @brief The server returned an unknown error code
+ *
+ *  The server encountered an error with the given message but
+ *  the error code is not recognized by the client.
+ */
+#define RcmClient_E_SERVERERROR (-13)
+
+/*!
+ *  @brief The server specified in the create params was not found
+ *
+ *  When creating an RcmClient instance, the specified server could not
+ *  be found. This could occur if the server name is incorrect, or
+ *  if the RcmClient instance is created before the RcmServer. In such an
+ *  instance, the client can retry when the RcmServer is expected to
+ *  have been created.
+ */
+#define RcmClient_E_SERVERNOTFOUND (-14)
+
+/*!
+ *  @brief The given symbol was not found in the server symbol table
+ *
+ *  This error could occur if the symbol spelling is incorrect or
+ *  if the RcmServer is still loading its symbol table.
+ */
+#define RcmClient_E_SYMBOLNOTFOUND (-15)
+
+/*!
+ *  @brief There is insufficient memory left in the heap
+ */
+#define RcmClient_E_NOMEMORY (-16)
+
+/*!
+ *  @brief The given job id was not found on the server
+ *
+ *  When releasing a job id with a call to RcmClient_releaseJobId(),
+ *  this error return value indicates that the given job id was not
+ *  previously allocated with a call to RcmClient_acquireJobId().
+ */
+#define RcmClient_E_JOBIDNOTFOUND (-17)
+
+
+// -------- constants and types --------
+
+/*!
+ *  @brief Invalid function index
+ */
+#define RcmClient_INVALIDFXNIDX ((UInt32)(0xFFFFFFFF))
+
+/*!
+ *  @brief Invalid heap id
+ */
+#define RcmClient_INVALIDHEAPID ((UInt16)(0xFFFF))
+
+/*!
+ *  @brief Invalid message id
+ */
+#define RcmClient_INVALIDMSGID (0)
+
+/*!
+ *  @brief Default worker pool id
+ *
+ *  The default worker pool is used to process all anonymous messages.
+ *  When a new message is allocated, the pool id property is
+ *  initialized to this value.
+ */
+#define RcmClient_DEFAULTPOOLID ((UInt16)(0x8000))
+
+/*!
+ *  @brief Invalid job stream id
+ *
+ *  All discrete messages must have their jobId property set to this value.
+ *  When a new message is allocated, the jobId property is initialized tothis value.
+ */
+#define RcmClient_DISCRETEJOBID (0)
+
+/*!
+ *  @brief RcmClient instance object handle
+ */
+typedef struct RcmClient_Object_tag *RcmClient_Handle;
+
+/*!
+ *  @brief Remote Command Message structure
+ *
+ *  An RcmClient needs to fill in this message before sending it
+ *  to the RcmServer for execution.
+ */
+typedef struct {
+    /*!
+     *  @brief The worker pool id that will process this message.
+     *
+     *  The message will be processed by a worker thread from the worker
+     *  pool specified in this field. The default value is the default
+     *  pool id.
+     */
+    UInt16      poolId;
+
+    /*!
+     *  @brief The job id associated with this message.
+     *
+     *  All messages beloging to a job id must have this field set to
+     *  that id. Use the value RcmClient_DISCRETEJOBID if the message
+     *  does not belong to any job.
+     */
+    UInt16      jobId;
+
+    /*!
+     *  @brief The index of the remote function to execute.
+     */
+    UInt32      fxnIdx;
+
+    /*!
+     *  @brief The return value of the remote message function.
+     */
+    Int32       result;
+
+    /*!
+     *  @brief The size of the data buffer (in chars).
+     *
+     *  This field should be considered as read-only. It is set by
+     *  the call to the RcmClient_alloc() function.
+     */
+    UInt32      dataSize;
+
+    /*!
+     *  @brief The data buffer containing the message payload.
+     *
+     *  The size of this field is dataSize chars. The space is allocated
+     *  by the call to the RcmClient_alloc() function.
+     */
+    UInt32      data[1];
+
+} RcmClient_Message;
+
+/*!
+ *  @brief Callback function type
+ *
+ *  When using callback notification, the application must supply a
+ *  callback function of this type. The callback will be invoked with
+ *  the pointer to the RcmClient_Message returned from the server and
+ *  the application data pointer supplied in the call to RcmClient_execAsync().
+ */
+typedef Void (*RcmClient_CallbackFxn)(RcmClient_Message *, Ptr);
+
+/*!
+ *  @brief Instance create parameters
+ */
+typedef struct {
+    /*!
+     *  @brief The heapId used by this instance for allocating messages
+     *
+     *  If sending messages to a remote server, the specified heap must
+     *  be compatible with the transport used for delivering messages
+     *  to the remote processor.
+     */
+    UInt16 heapId;
+
+    /*!
+     *  @brief Asynchronous callback notification support
+     *
+     *  When remote functions submitted with RcmClient_execAsync()
+     *  complete, the given callback function is invoked. The callback
+     *  function executes in the context of this RcmClient instance's
+     *  callback server thread.
+     *
+     *  This config param must be set to true when using RcmClient_execAsync()
+     *  to execute remote functions.
+     *
+     *  When set to false, the callback server thread is not created.
+     */
+    Bool callbackNotification;
+
+} RcmClient_Params;
+
+/*!
+ *  @brief Opaque client structure large enough to hold an instance object
+ *
+ *  Use this structure to define an embedded RcmClient object.
+ *
+ *  @sa RcmClient_construct
+ */
+typedef struct {
+    xdc_runtime_knl_GateThread_Struct   _f1;
+    Ptr                 _f2;
+    Ptr                 _f3;
+    UInt16              _f4;
+    Ptr                 _f5;
+    UInt32              _f6;
+    Bool                _f7;
+    UInt16              _f8;
+    Ptr                 _f9;
+    Ptr                 _f10;
+    Ptr                 _f11;
+    Ptr                 _f12;
+} RcmClient_Struct;
+
+
+// -------- functions --------
+
+/*
+ *  ======== RcmClient_acquireJobId ========
+ */
+/*!
+ *  @brief Get a job id from the server
+ *
+ *  Acquire a unique job id from the server. The job id is used to associate
+ *  messages with a common job id. The server will process all messages for
+ *  a given job id in sequence.
+ */
+Int RcmClient_acquireJobId(
+        RcmClient_Handle        handle,
+        UInt16 *                jobId
+    );
+
+/*
+ *  ======== RcmClient_addSymbol ========
+ */
+/*!
+ *  @brief Add a symbol and its address to the server table
+ *
+ *  This function is used by the client to dynamically load a new
+ *  function address into the server's function pointer table. The
+ *  given address must be in the server's address space. The function
+ *  must already be loaded into the server's memory.
+ *
+ *  This function is useful when dynamically loading code onto the
+ *  remote processor (as in the case of DLL's).
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] name The function's name.
+ *
+ *  @param[in] addr The function's address as specified in the
+ *  remote processor's address space.
+ *
+ *  @param[out] index The function's index value to be used in the
+ *  RcmClient_Message.fxnIdx field.
+ *
+ *  @retval RcmClient_S_SUCCESS Success
+ *  @retval RcmClient_E_FAIL Failure
+ */
+Int RcmClient_addSymbol(
+        RcmClient_Handle        handle,
+        String                  name,
+        Fxn                     addr,
+        UInt32 *                index
+    );
+
+/*
+ *  ======== RcmClient_alloc ========
+ */
+/*!
+ *  @brief Allocate a message from the heap configured for this instance
+ *
+ *  When a message is allocated, the RcmClient instance is the owner
+ *  of the message. All messages must be returned to the heap by
+ *  calling RcmClient_free().
+ *
+ *  During a call to all of the exec functions, the ownership of the
+ *  message is temporarily transfered to the server. If the exec
+ *  function returns an RcmClient_Message pointer, then ownership of
+ *  the message is returned to the instance. For the other exec
+ *  functions, the client acquires ownership of the return message
+ *  by calling RcmClient_waitUntilDone().
+ *
+ *  A message should not be accessed when ownership has been given
+ *  away. Once ownership has been reacquired, the message can be
+ *  either reused or returned to the heap.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] dataSize Specifies (in chars) how much space to allocate
+ *  for the RcmClient_Message.data array. The actual memory allocated
+ *  from the heap will be larger as it includes the size of the
+ *  internal message header.
+ *
+ *  @param[out] message A pointer to the allocated message or NULL on error.
+ */
+Int RcmClient_alloc(
+        RcmClient_Handle        handle,
+        UInt32                  dataSize,
+        RcmClient_Message **    message
+    );
+
+/*
+ *  ======== RcmClient_checkForError ========
+ */
+/*!
+ *  @brief Check if an error message has been returned from the server
+ *
+ *  When using RcmClient_execCmd() to send messages to the server, the
+ *  message will be freed by the server unless an error occurs. In the
+ *  case of an error, the message is returned to the client. Use this
+ *  function to check for and to retrieve these error messages.
+ *
+ *  Note that the latency of the return message is dependent on many
+ *  system factors. In particular, the server's response time to processing
+ *  a message will be a significant factor. It is possible to call
+ *  RcmClient_execCmd() several times before any error message is returned.
+ *  There is no way to know when all the messages have been processed.
+ *
+ *  The return value of RcmClient_checkForError() is designed to mimic
+ *  the return value of RcmClient_exec(). When an error message is returned
+ *  to the caller, the return value of RcmClient_checkForError() will be
+ *  the appropriate error code as if the error had occured during a call
+ *  to RcmClient_exec(). For example, if a message is prepared with an
+ *  incorrect function index, the return value from RcmClient_exec() would
+ *  be RcmClient_E_INVALIDFXNIDX. However, the same message sent with
+ *  RcmClient_execCmd() will not return an error, because the function does
+ *  not wait for the return message. When the server receives the message
+ *  and detects the function index error, it will return the message to
+ *  the client on a special error queue. The subsequent call to
+ *  RcmClient_checkForError() will pickup this error message and return
+ *  with a status value of RcmClient_E_INVALIDFXNIDX, just as the call
+ *  to RcmClient_exec() would have done.
+ *
+ *  A return value of RcmClient_S_SUCCESS means there are no error messages.
+ *  This function will never return a message and a success status code at
+ *  the same time.
+ *
+ *  When this function returns an error message, the caller must return
+ *  the message to the heap by calling RcmClient_free().
+ *
+ *  It is possible that RcmClient_checkForError() will return with an error
+ *  but without an error message. This can happen when an internal error
+ *  occurs in RcmClient_checkForError() before it has checked the error
+ *  queue. In this case, an error is returned but the returnMsg argument
+ *  will be set to NULL.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[out] returnMsg A pointer to the error message or NULL if there
+ *  are no error messages in the queue.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmClient_E_IPCERROR
+ *  @retval RcmClient_E_INVALIDFXNIDX
+ *  @retval RcmClient_E_MSGFXNERROR
+ *  @retval RcmClient_E_SERVERERROR
+ */
+Int RcmClient_checkForError(
+        RcmClient_Handle        handle,
+        RcmClient_Message **    returnMsg
+    );
+
+/*
+ *  ======== RcmClient_construct ========
+ */
+/*!
+ *  @brief Initialize a new instance object inside the provided structure
+ *
+ *  This function is the same as RcmClient_create() except that it does not
+ *  allocate memory for the instance object. The instance object is
+ *  constructed inside the provided structure. Call RcmClient_destruct()
+ *  to finalize a constructed instance object.
+ *
+ *  @param[in] structPtr A pointer to an allocated structure.
+ *
+ *  @param[in] server The name of the server that messages will be sent to for
+ *  executing commands. The name must be a system-wide unique name.
+ *
+ *  @param[in] params The create params used to customize the instance object.
+ *
+ *  @sa RcmClient_create
+ */
+Int RcmClient_construct(
+        RcmClient_Struct *      structPtr,
+        String                  server,
+        const RcmClient_Params *params
+    );
+
+/*
+ *  ======== RcmClient_create ========
+ */
+/*!
+ *  @brief Create an RcmClient instance
+ *
+ *  The RcmClient instance is used by the application to send messages to
+ *  an RcmServer for executing remote functions. A given
+ *  instance can send messages only to the server it was configured
+ *  for. If an application needs to send messages to multiple servers,
+ *  then create an RcmClient instance for each server.
+ *
+ *  The assigned server to this instance must already exist and be
+ *  running before creating RcmClient instances which send messages to it.
+ *
+ *  @param[in] server The name of the server that messages will be sent to for
+ *  executing commands. The name must be a system-wide unique name.
+ *
+ *  @param[in] params The create params used to customize the instance object.
+ *
+ *  @param[out] handle An opaque handle to the created instance object.
+ */
+Int RcmClient_create(
+        String                  server,
+        const RcmClient_Params *params,
+        RcmClient_Handle *      handle
+    );
+
+/*
+ *  ======== RcmClient_delete ========
+ */
+/*!
+ *  @brief Delete an RcmClient instance
+ *
+ *  @param[in,out] handlePtr Handle to the instance object to delete.
+ */
+Int RcmClient_delete(
+        RcmClient_Handle *      handlePtr
+    );
+
+/*
+ *  ======== RcmClient_destruct ========
+ */
+/*!
+ *  @brief Finalize the instance object inside the provided structure
+ *
+ *  @param[in] structPtr A pointer to the structure containing the
+ *  instance object to finalize.
+ */
+Int RcmClient_destruct(
+        RcmClient_Struct *      structPtr
+    );
+
+/*
+ *  ======== RcmClient_exec ========
+ */
+/*!
+ *  @brief Execute a command message on the server
+ *
+ *  The message is sent to the server for processing. This call will
+ *  block until the remote function has completed. When this function
+ *  returns, the message will contain the return value of the remote
+ *  function as well as a possibly modified context.
+ *
+ *  After calling exec, the message can be either reused for another
+ *  call to exec or it can be freed.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] cmdMsg Pointer to an RcmClient_Message structure.
+ *
+ *  @param[out] returnMsg A pointer to the return message or NULL on
+ *  error. The client must free this message. The return value of the
+ *  message function is stored in the results field. The return value
+ *  of the library function is marshalled into the data field.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmClient_E_EXECFAILED
+ *  @retval RcmClient_E_INVALIDFXNIDX
+ *  @retval RcmClient_E_LOSTMSG
+ *  @retval RcmClient_E_MSGFXNERROR
+ *  @retval RcmClient_E_SERVERERROR
+ */
+Int RcmClient_exec(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     cmdMsg,
+        RcmClient_Message **    returnMsg
+    );
+
+/*
+ *  ======== RcmClient_execAsync ========
+ */
+/*!
+ *  @brief Execute a command message and use a callback for notification
+ *
+ *  The message is sent to the server for execution, but this call does
+ *  not wait for the remote function to execute. This call returns
+ *  as soon as the message has been dispatched to the transport. Upon
+ *  returning from this function, the ownership of the message has been
+ *  lost; do not access the message at this time.
+ *
+ *  When the remote function completes, the given callback function is
+ *  invoked by this RcmClient instance's callback server thread. The
+ *  callback function is used to asynchronously notify the client that
+ *  the remote function has completed.
+ *
+ *  The RcmClient instance must be create with callbackNotification
+ *  set to true in order to use this function.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] cmdMsg Pointer to an RcmClient_Message structure.
+ *
+ *  @param[in] callback A callback function pointer supplied by the
+ *  application. It will be invoked by the callback server thread to
+ *  notify the application that the remote function has completed.
+ *
+ *  @param[in] appData A private data pointer supplied by the application.
+ *  This allows the application to provide its own context when
+ *  receiving the callback.
+ */
+Int RcmClient_execAsync(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     cmdMsg,
+        RcmClient_CallbackFxn   callback,
+        Ptr                     appData
+    );
+
+/*
+ *  ======== RcmClient_execCmd ========
+ */
+/*!
+ *  @brief Execute a one-way command message on the server
+ *
+ *  The message is sent to the server for processing but this function
+ *  does not wait for the return message. This function is non-blocking.
+ *  The server will processes the message and then free it, unless an
+ *  error occurs. The return value from the remote function is discarded.
+ *
+ *  If an error occurs on the server while processing the message, the server
+ *  will return the message to the client. Use RcmClient_checkForError()
+ *  to collect these return error messages.
+ *
+ *  When this function returns, ownership of the message has been transfered
+ *  to the server. Do not access the message after this function returns,
+ *  it could cause cache inconsistencies or a memory access violation.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] cmdMsg Pointer to an RcmClient_Message structure.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmClient_E_IPCERROR
+ */
+Int RcmClient_execCmd(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     cmdMsg
+    );
+
+/*
+ *  ======== RcmClient_execDpc ========
+ */
+/*!
+ *  @brief Execute a deferred procedure call on the server
+ *
+ *  The return field of the message is not used.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] cmdMsg Pointer to an RcmClient_Message structure.
+ *
+ *  @param[out] returnMsg A pointer to the return message or NULL
+ *  on error. The client must free this message.
+ */
+Int RcmClient_execDpc(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     cmdMsg,
+        RcmClient_Message **    returnMsg
+    );
+
+/*
+ *  ======== RcmClient_execNoWait ========
+ */
+/*!
+ *  @brief Submit a command message to the server and return immediately
+ *
+ *  The message is sent to the server for execution but this call does
+ *  not wait for the remote function to execute. The call returns
+ *  as soon as the message has been dispatched to the transport. Upon
+ *  returning from this function, the ownership of the message has been
+ *  lost; do not access the message at this time.
+ *
+ *  Using this call to execute a remote message does not require a
+ *  callback server thread. The application must call
+ *  RcmClient_waitUntilDone() to get the return message from the remote
+ *  function.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] cmdMsg A pointer to an RcmClient_Message structure.
+ *
+ *  @param[out] msgId Pointer used for storing the message id. Use
+ *  the message id in a call to RcmClient_WaitUntilDone() to retrieve
+ *  the return value of the remote function.
+ */
+Int RcmClient_execNoWait(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     cmdMsg,
+        UInt16 *                msgId
+    );
+
+/*
+ *  ======== RcmClient_exit ========
+ */
+/*!
+ *  @brief Finalize the RcmClient module
+ *
+ *  This function is used to finalize the RcmClient module. Any resources
+ *  acquired by RcmClient_init() will be released. Do not call any RcmClient
+ *  functions after calling RcmClient_exit().
+ *
+ *  This function must be serialized by the caller.
+ */
+Void RcmClient_exit(Void);
+
+/*
+ *  ======== RcmClient_free ========
+ */
+/*!
+ *  @brief Free the given message
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param msg Pointer to an RcmClient_Message structure.
+ */
+Int RcmClient_free(
+        RcmClient_Handle        handle,
+        RcmClient_Message *     msg
+    );
+
+/*
+ *  ======== RcmClient_getSymbolIndex ========
+ */
+/*!
+ *  @brief Return the function index from the server
+ *
+ *  Query the server for the given function name and return its index.
+ *  Use the index in the fxnIdx field of the RcmClient_Message struct.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] name The function's name.
+ *
+ *  @param[out] index The function's index.
+ */
+Int RcmClient_getSymbolIndex(
+        RcmClient_Handle        handle,
+        String                  name,
+        UInt32 *                index
+    );
+
+/*
+ *  ======== RcmClient_init ========
+ */
+/*!
+ *  @brief Initialize the RcmClient module
+ *
+ *  This function is used to initialize the RcmClient module. Call this
+ *  function before calling any other RcmClient function.
+ *
+ *  This function must be serialized by the caller
+ */
+Void RcmClient_init(Void);
+
+/*
+ *  ======== RcmClient_Parmas_init ========
+ */
+/*!
+ *  @brief Initialize the instance create params structure
+ */
+Void RcmClient_Params_init(
+        RcmClient_Params *      params
+    );
+
+/*
+ *  ======== RcmClient_releaseJobId ========
+ */
+/*!
+ *  @brief Return a job id to the server and release all resources
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] jobId The job id to be released
+ */
+Int RcmClient_releaseJobId(
+        RcmClient_Handle        handle,
+        UInt16                  jobId
+    );
+
+/*
+ *  ======== RcmClient_removeSymbol ========
+ */
+/*!
+ *  @brief Remove a symbol and from the server function table
+ *
+ *  Useful when unloading a DLL from the server.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] name The function name.
+ */
+Int RcmClient_removeSymbol(
+        RcmClient_Handle        handle,
+        String                  name
+    );
+
+/*
+ *  ======== RcmClient_waitUntilDone ========
+ */
+/*!
+ *  @brief Block until the specified message has been executed
+ *
+ *  This function will wait until the remote function invoked by the
+ *  specified message has completed. Upon return from this call, the
+ *  message will contain the return value and the return context of
+ *  the remote function.
+ *
+ *  @param[in] handle Handle to an instance object
+ *
+ *  @param[in] msgId The message ID to wait for.
+ *
+ *  @param[out] returnMsg A pointer to the return message or NULL
+ *  on error. The client must free this message.
+ */
+Int RcmClient_waitUntilDone(
+        RcmClient_Handle        handle,
+        UInt16                  msgId,
+        RcmClient_Message **    returnMsg
+    );
+
+
+#if defined (__cplusplus)
+}
+#endif /* defined (__cplusplus) */
+
+/*@}*/
+
+#endif /* ti_grcm_RcmClient__include */
diff --git a/packages/ti/grcm/RcmClient.xdc b/packages/ti/grcm/RcmClient.xdc
new file mode 100644 (file)
index 0000000..674cb36
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmClient.xdc ========
+ *
+ */
+
+package ti.grcm;
+
+
+/*!
+ *  ======== RcmClient ========
+ *  Remote Command Message client module
+ *
+ *  This is the RTSC meta-only module documentation. Please see the links
+ *  below for the runtime documentation.
+ *
+ *  @a(See Also)
+ *  @p(dlist)
+ *  - {@link doxy(ti_grcm_RcmClient) RcmClient API Reference}
+ *  - {@link doxy(RcmClient.h) RcmClient File Reference}
+ *  - {@link doxy(ti_grcm) RCM Overview}
+ *  @p
+ */
+
+metaonly module RcmClient
+{
+
+}
diff --git a/packages/ti/grcm/RcmClient.xs b/packages/ti/grcm/RcmClient.xs
new file mode 100644 (file)
index 0000000..2120d38
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmClient.xs ========
+ *
+ */
+
+/*
+ *  ======== module$use ========
+ *  Use other modules required by this module
+ */
+function module$use()
+{
+    var Settings = xdc.module(this.$package.$name + '.Settings');
+
+    /* Settings.ipc config param cannot be undefined */
+    if (Settings.ipc == undefined) {
+        throw new Error("the " + Settings.$name + ".ipc config param"
+        + " is undefined, it must be assigned a value by"
+        + " the application config script.");
+    }
+
+    xdc.useModule('xdc.runtime.Diags');
+    xdc.useModule('xdc.runtime.Error');
+    xdc.useModule('xdc.runtime.Log');
+    xdc.useModule('xdc.runtime.Memory');
+    xdc.useModule('xdc.runtime.Startup');
+    xdc.useModule('xdc.runtime.knl.GateThread');
+    xdc.useModule('xdc.runtime.knl.Semaphore');
+    xdc.useModule('xdc.runtime.knl.SemThread');
+    xdc.useModule('xdc.runtime.knl.SyncSemThread');
+
+    if (Settings.IpcSupport_ti_sdo_ipc == Settings.ipc) {
+        xdc.useModule('ti.sdo.ipc.MessageQ');
+        xdc.useModule('ti.sdo.utils.List');
+    }
+    else if (Settings.IpcSupport_ti_syslink_ipc == Settings.ipc) {
+        xdc.loadPackage('ti.syslink');
+    }
+    else {
+        throw new Error("unknown value for " + Settings.$name
+        + ".ipc config param (" + Settings.ipc + ")");
+    }
+}
diff --git a/packages/ti/grcm/RcmServer.c b/packages/ti/grcm/RcmServer.c
new file mode 100644 (file)
index 0000000..27c2910
--- /dev/null
@@ -0,0 +1,2514 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  ======== RcmServer.c ========
+ *
+ */
+
+/* this define must precede inclusion of any xdc header file */
+#define Registry_CURDESC ti_grcm_RcmServer__Desc
+#define MODULE_NAME "ti.grcm.RcmServer"
+
+#define xdc_runtime_Memory__nolocalnames  /* short name clashes with SysLink */
+
+/* rtsc header files */
+#include <xdc/std.h>
+#include <xdc/runtime/Assert.h>
+#include <xdc/runtime/Diags.h>
+#include <xdc/runtime/Error.h>
+#include <xdc/runtime/IHeap.h>
+#include <xdc/runtime/Log.h>
+#include <xdc/runtime/Memory.h>
+#include <xdc/runtime/Registry.h>
+#include <xdc/runtime/Startup.h>
+#include <xdc/runtime/knl/GateThread.h>
+#include <xdc/runtime/knl/ISemaphore.h>
+#include <xdc/runtime/knl/Semaphore.h>
+#include <xdc/runtime/knl/SemThread.h>
+#include <xdc/runtime/knl/Thread.h>
+#include <xdc/runtime/System.h>
+
+#define MSGBUFFERSIZE    512   // Make global and move to MessageQCopy.h
+
+#if defined(RCM_ti_ipc)
+#include <ti/sdo/utils/List.h>
+#include <ti/ipc/MultiProc.h>
+
+#elif defined(RCM_ti_syslink)
+#include <ti/syslink/utils/List.h>
+#define List_Struct List_Object
+#define List_handle(exp) (exp)
+
+#else
+    #error "undefined ipc binding";
+#endif
+
+/* local header files */
+#include "RcmClient.h"
+#include "RcmTypes.h"
+#include "RcmServer.h"
+
+#if USE_MESSAGEQCOPY
+#include <ti/srvmgr/rpmsg_omx.h>
+#endif
+
+#define _RCM_KeyResetValue 0x07FF       // key reset value
+#define _RCM_KeyMask 0x7FF00000         // key mask in function index
+#define _RCM_KeyShift 20                // key bit position in function index
+
+#define RcmServer_MAX_TABLES 9          // max number of function tables
+#define RcmServer_POOL_MAP_LEN 4        // pool map length
+
+#define RcmServer_E_InvalidFxnIdx       (-101)
+#define RcmServer_E_JobIdNotFound       (-102)
+#define RcmServer_E_PoolIdNotFound      (-103)
+
+typedef struct {                        // function table element
+    String                      name;
+#if USE_MESSAGEQCOPY
+    union  {
+       RcmServer_MsgFxn         fxn;
+       RcmServer_MsgCreateFxn   createFxn;
+    }addr;
+#else
+    RcmServer_MsgFxn            addr;
+#endif
+    UInt16                      key;
+} RcmServer_FxnTabElem;
+
+typedef struct {
+    Int                         length;
+    RcmServer_FxnTabElem *      elem;
+} RcmServer_FxnTabElemAry;
+
+typedef struct {
+    String                      name;       // pool name
+    Int                         count;      // thread count (at create time)
+    Thread_Priority             priority;   // thread priority
+    Int                         osPriority;
+    SizeT                       stackSize;  // thread stack size
+    String                      stackSeg;   // thread stack placement
+    ISemaphore_Handle           sem;        // message semaphore (counting)
+    List_Struct                 threadList; // list of worker threads
+    List_Struct                 readyQueue; // queue of messages
+} RcmServer_ThreadPool;
+
+typedef struct RcmServer_Object_tag {
+    GateThread_Struct           gate;       // instance gate
+    Ptr                         run;        // run semaphore for the server
+#if USE_MESSAGEQCOPY
+    MessageQCopy_Handle         serverQue;  // inbound message queue
+    UInt32                      localAddr;  // inbound message queue address
+    UInt32                      replyAddr;  // Reply address (same per inst.)
+    UInt32                      dstProc;    // Reply processor.
+#else
+    MessageQ_Handle             serverQue;  // inbound message queue
+#endif
+    Thread_Handle               serverThread; // server thread object
+    RcmServer_FxnTabElemAry     fxnTabStatic; // static function table
+    RcmServer_FxnTabElem *      fxnTab[RcmServer_MAX_TABLES]; // base pointers
+    UInt16                      key;        // function index key
+    UInt16                      jobId;      // job id tracker
+    Bool                        shutdown;   // server shutdown flag
+    Int                         poolMap0Len;// length of static table
+    RcmServer_ThreadPool *      poolMap[RcmServer_POOL_MAP_LEN];
+    List_Handle                 jobList;    // list of job stream queues
+} RcmServer_Object;
+
+typedef struct {
+    List_Elem                   elem;
+    UInt16                      jobId;      // current job stream id
+    Thread_Handle               thread;     // server thread object
+    Bool                        terminate;  // thread terminate flag
+    RcmServer_ThreadPool*       pool;       // worker pool
+    RcmServer_Object *          server;     // server instance
+} RcmServer_WorkerThread;
+
+typedef struct {
+    List_Elem                   elem;
+    UInt16                      jobId;      // job stream id
+    Bool                        empty;      // true if no messages on server
+    List_Struct                 msgQue;     // queue of messages
+} RcmServer_JobStream;
+
+typedef struct RcmServer_Module_tag {
+    String              name;
+    IHeap_Handle        heap;
+} RcmServer_Module;
+
+
+/* private functions */
+static
+Int RcmServer_Instance_init_P(
+        RcmServer_Object *              obj,
+        String                          name,
+        const RcmServer_Params *        params
+    );
+
+static
+Int RcmServer_Instance_finalize_P(
+        RcmServer_Object *              obj
+    );
+
+static
+Int RcmServer_acqJobId_P(
+        RcmServer_Object *              obj,
+        UInt16 *                        jobIdPtr
+    );
+
+static
+Int RcmServer_dispatch_P(
+        RcmServer_Object *              obj,
+        RcmClient_Packet *              packet
+    );
+
+static
+Int RcmServer_execMsg_I(
+        RcmServer_Object *              obj,
+        RcmClient_Message *             msg
+    );
+
+static
+Int RcmServer_getFxnAddr_P(
+        RcmServer_Object *              obj,
+        UInt32                          fxnIdx,
+        RcmServer_MsgFxn *              addrPtr,
+        RcmServer_MsgCreateFxn *        createPtr
+    );
+
+static
+UInt16 RcmServer_getNextKey_P(
+        RcmServer_Object *              obj
+    );
+
+static
+Int RcmServer_getSymIdx_P(
+        RcmServer_Object *              obj,
+        String                          name,
+        UInt32 *                        index
+    );
+
+static
+Int RcmServer_getPool_P(
+        RcmServer_Object *              obj,
+        RcmClient_Packet *              packet,
+        RcmServer_ThreadPool **         poolP
+    );
+
+static
+Void RcmServer_process_P(
+        RcmServer_Object *              obj,
+        RcmClient_Packet *              packet
+    );
+
+static
+Int RcmServer_relJobId_P(
+        RcmServer_Object *              obj,
+        UInt16                          jobId
+    );
+
+static
+Void RcmServer_serverThrFxn_P(
+        IArg                            arg
+    );
+
+static inline
+Void RcmServer_setStatusCode_I(
+        RcmClient_Packet *              packet,
+        UInt16                          code
+    );
+
+static
+Void RcmServer_workerThrFxn_P(
+        IArg                            arg
+    );
+
+
+#define RcmServer_Module_heap() (RcmServer_Mod.heap)
+
+
+/* static objects */
+static Int curInit = 0;
+static Char ti_grcm_RcmServer_Name[] = {
+        't','i','.','s','d','o','.','r','c','m','.',
+        'R','c','m','S','e','r','v','e','r','\0'
+    };
+
+static RcmServer_Module RcmServer_Mod = {
+    MODULE_NAME,        /* name */
+    (IHeap_Handle)NULL  /* heap */
+};
+
+/* module diags mask */
+Registry_Desc Registry_CURDESC;
+
+
+/*
+ *  ======== RcmServer_init ========
+ *
+ *  This function must be serialized by the caller
+ */
+Void RcmServer_init(Void)
+{
+    Registry_Result result;
+
+
+    if (curInit++ != 0) {
+        return; /* module already initialized */
+    }
+
+    /* register with xdc.runtime to get a diags mask */
+//  result = Registry_addModule(&Registry_CURDESC, MODULE_NAME);
+    result = Registry_addModule(&Registry_CURDESC, ti_grcm_RcmServer_Name);
+    Assert_isTrue(result == Registry_SUCCESS, (Assert_Id)NULL);
+
+    /* the size of object and struct must be the same */
+    Assert_isTrue(sizeof(RcmServer_Object) == sizeof(RcmServer_Struct), NULL);
+}
+
+
+/*
+ *  ======== RcmServer_exit ========
+ *
+ *  This function must be serialized by the caller
+ */
+Void RcmServer_exit(Void)
+{
+//  Registry_Result result;
+
+
+    if (--curInit != 0) {
+        return; /* module still in use */
+    }
+
+    /* unregister from xdc.runtime */
+//  result = Registry_removeModule(MODULE_NAME);
+//  Assert_isTrue(result == Registry_SUCCESS, (Assert_Id)NULL);
+}
+
+
+/*
+ *  ======== RcmServer_Params_init ========
+ */
+Void RcmServer_Params_init(RcmServer_Params *params)
+{
+    /* server thread */
+    params->priority = Thread_Priority_HIGHEST;
+    params->osPriority = Thread_INVALID_OS_PRIORITY;
+    params->stackSize = 0;  // use system default
+    params->stackSeg = "";
+
+    /* default pool */
+    params->defaultPool.name = NULL;
+    params->defaultPool.count = 0;
+    params->defaultPool.priority = Thread_Priority_NORMAL;
+    params->defaultPool.osPriority = Thread_INVALID_OS_PRIORITY;
+    params->defaultPool.stackSize = 0;  // use system default
+    params->defaultPool.stackSeg = "";
+
+    /* worker pools */
+    params->workerPools.length = 0;
+    params->workerPools.elem = NULL;
+
+    /* function table */
+    params->fxns.length = 0;
+    params->fxns.elem = NULL;
+}
+
+
+/*
+ *  ======== RcmServer_create ========
+ */
+#define FXNN "RcmServer_create"
+Int RcmServer_create(String name, RcmServer_Params *params,
+        RcmServer_Handle *handle)
+{
+    RcmServer_Object *obj;
+    Error_Block eb;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY, "--> "FXNN": (name=0x%x, params=0x%x, hP=0x%x)",
+        (IArg)name, (IArg)params, (IArg)handle);
+
+    /* initialize the error block */
+    Error_init(&eb);
+    *handle = (RcmServer_Handle)NULL;
+
+    /* check for valid params */
+    if (NULL == params) {
+        Log_error0(FXNN": params ptr must not be NULL");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+    if (NULL == handle) {
+        Log_error0(FXNN": Invalid pointer");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+    if (NULL == name) {
+        Log_error0(FXNN": name passed is NULL!");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+    /* allocate the object */
+    obj = (RcmServer_Handle)xdc_runtime_Memory_calloc(RcmServer_Module_heap(),
+        sizeof(RcmServer_Object), sizeof(Int), &eb);
+
+    if (NULL == obj) {
+        Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+            (IArg)RcmServer_Module_heap(), sizeof(RcmServer_Object));
+        status = RcmServer_E_NOMEMORY;
+        goto leave;
+    }
+
+    Log_print1(Diags_LIFECYCLE, FXNN": instance create: 0x%x", (IArg)obj);
+
+    /* object-specific initialization */
+    status = RcmServer_Instance_init_P(obj, name, params);
+
+    if (status < 0) {
+        RcmServer_Instance_finalize_P(obj);
+        xdc_runtime_Memory_free(RcmServer_Module_heap(),
+            (Ptr)obj, sizeof(RcmServer_Object));
+        goto leave;
+    }
+
+    /* success, return opaque pointer */
+    *handle = (RcmServer_Handle)obj;
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_construct ========
+ */
+#define FXNN "RcmServer_construct"
+Int RcmServer_construct(RcmServer_Struct *structPtr, String name,
+    const RcmServer_Params *params)
+{
+    RcmServer_Object *obj = (RcmServer_Object*)structPtr;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (structPtr=0x%x)", (IArg)structPtr);
+    Log_print1(Diags_LIFECYCLE, FXNN": instance construct: 0x%x", (IArg)obj);
+
+    /* ensure the constructed object is zeroed */
+    _memset((Void *)obj, 0, sizeof(RcmServer_Object));
+
+    /* object-specific initialization */
+    status = RcmServer_Instance_init_P(obj, name, params);
+
+    if (status < 0) {
+        RcmServer_Instance_finalize_P(obj);
+        goto leave;
+    }
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_Instance_init_P ========
+ */
+#define FXNN "RcmServer_Instance_init_P"
+Int RcmServer_Instance_init_P(RcmServer_Object *obj, String name,
+        const RcmServer_Params *params)
+{
+    Error_Block eb;
+    List_Params listP;
+#if USE_MESSAGEQCOPY == 0
+    MessageQ_Params mqParams;
+#endif
+    Thread_Params threadP;
+    SemThread_Params semThreadP;
+    SemThread_Handle semThreadH;
+    Int i, j;
+    SizeT size;
+    Char *cp;
+    RcmServer_ThreadPool *poolAry;
+    RcmServer_WorkerThread *worker;
+    List_Handle listH;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (obj=0x%x)", (IArg)obj);
+
+    Error_init(&eb);
+
+    /* initialize instance state */
+    obj->shutdown = FALSE;
+    obj->key = 0;
+    obj->jobId = 0xFFFF;
+    obj->run = NULL;
+    obj->serverQue = NULL;
+    obj->serverThread = NULL;
+    obj->fxnTabStatic.length = 0;
+    obj->fxnTabStatic.elem = NULL;
+    obj->poolMap0Len = 0;
+    obj->jobList = NULL;
+
+
+    /* initialize the function table */
+    for (i = 0; i < RcmServer_MAX_TABLES; i++) {
+        obj->fxnTab[i] = NULL;
+    }
+
+    /* initialize the worker pool map */
+    for (i = 0; i < RcmServer_POOL_MAP_LEN; i++) {
+        obj->poolMap[i] = NULL;
+    }
+
+    /* create the instance gate */
+    GateThread_construct(&obj->gate, NULL, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create gate object");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+    /* create list for job objects */
+#if defined(RCM_ti_ipc)
+    List_Params_init(&listP);
+    obj->jobList = List_create(&listP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+#elif defined(RCM_ti_syslink)
+    List_Params_init(&listP);
+    obj->jobList = List_create(&listP, NULL);
+
+    if (obj->jobList == NULL) {
+        Log_error0(FXNN": could not create list object");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+#endif
+
+    /* create the static function table */
+    if (params->fxns.length > 0) {
+        obj->fxnTabStatic.length = params->fxns.length;
+
+        /* allocate static function table */
+        size = params->fxns.length * sizeof(RcmServer_FxnTabElem);
+        obj->fxnTabStatic.elem = xdc_runtime_Memory_alloc(
+            RcmServer_Module_heap(), size, sizeof(Ptr), &eb);
+
+        if (Error_check(&eb)) {
+            Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+                (IArg)RcmServer_Module_heap(), size);
+            status = RcmServer_E_NOMEMORY;
+            goto leave;
+        }
+        obj->fxnTabStatic.elem[0].name = NULL;
+
+        /* allocate a single block to store all name strings */
+        for (size = 0, i = 0; i < params->fxns.length; i++) {
+            size += _strlen(params->fxns.elem[i].name) + 1;
+        }
+        cp = xdc_runtime_Memory_alloc(
+            RcmServer_Module_heap(), size, sizeof(Ptr), &eb);
+
+        if (Error_check(&eb)) {
+            Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+                (IArg)RcmServer_Module_heap(), size);
+            status = RcmServer_E_NOMEMORY;
+            goto leave;
+        }
+
+        /* copy function table data into allocated memory blocks */
+        for (i = 0; i < params->fxns.length; i++) {
+            _strcpy(cp, params->fxns.elem[i].name);
+            obj->fxnTabStatic.elem[i].name = cp;
+            cp += (_strlen(params->fxns.elem[i].name) + 1);
+            obj->fxnTabStatic.elem[i].addr.fxn = params->fxns.elem[i].addr.fxn;
+            obj->fxnTabStatic.elem[i].key = 0;
+        }
+
+        /* hook up the static function table */
+        obj->fxnTab[0] = obj->fxnTabStatic.elem;
+    }
+
+    /* create static worker pools */
+    if ((params->workerPools.length + 1) > RcmServer_POOL_MAP_LEN) {
+        Log_error1(FXNN": Exceeded maximum number of worker pools =%d",
+            (IArg) (params->workerPools.length) );
+        status = RcmServer_E_NOMEMORY;
+        goto leave;
+    }
+    obj->poolMap0Len = params->workerPools.length + 1; /* workers + default */
+
+    /* allocate the static worker pool table */
+    size = obj->poolMap0Len * sizeof(RcmServer_ThreadPool);
+    obj->poolMap[0] = (RcmServer_ThreadPool *)xdc_runtime_Memory_alloc(
+        RcmServer_Module_heap(), size, sizeof(Ptr), &eb);
+
+    if (Error_check(&eb)) {
+        Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+            (IArg)RcmServer_Module_heap(), size);
+        status = RcmServer_E_NOMEMORY;
+        goto leave;
+    }
+
+    /* convenience alias */
+    poolAry = obj->poolMap[0];
+
+    /* allocate a single block to store all name strings         */
+    /* Buffer format is: [SIZE][DPN][\0][WPN1][\0][WPN2][\0].... */
+    /* DPN = Default Pool Name, WPN = Worker Pool Name           */
+    /* In case, DPN is NULL, format is: [SIZE][\0][WPN1][\0].... */
+    /* In case, WPN is NULL, format is: [SIZE][DPN][\0]          */
+    size = sizeof(SizeT) /* block size */
+        + (params->defaultPool.name == NULL ? 1 :
+        _strlen(params->defaultPool.name) + 1);
+
+    for (i = 0; i < params->workerPools.length; i++) {
+        size += (params->workerPools.elem[i].name == NULL ? 0 :
+            _strlen(params->workerPools.elem[i].name) + 1);
+    }
+    cp = xdc_runtime_Memory_alloc(
+        RcmServer_Module_heap(), size, sizeof(Ptr), &eb);
+
+    if (Error_check(&eb)) {
+        Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+            (IArg)RcmServer_Module_heap(), size);
+        status = RcmServer_E_NOMEMORY;
+        goto leave;
+    }
+
+    *(SizeT *)cp = size;
+    cp += sizeof(SizeT);
+
+    /* initialize the default worker pool, poolAry[0] */
+    if (params->defaultPool.name != NULL) {
+        _strcpy(cp, params->defaultPool.name);
+        poolAry[0].name = cp;
+        cp += (_strlen(params->defaultPool.name) + 1);
+    }
+    else {
+        poolAry[0].name = cp;
+        *cp++ = '\0';
+    }
+
+    poolAry[0].count = params->defaultPool.count;
+    poolAry[0].priority = params->defaultPool.priority;
+    poolAry[0].osPriority = params->defaultPool.osPriority;
+    poolAry[0].stackSize = params->defaultPool.stackSize;
+    poolAry[0].stackSeg = NULL;
+    poolAry[0].sem = NULL;
+
+    List_construct(&(poolAry[0].threadList), NULL);
+    List_construct(&(poolAry[0].readyQueue), NULL);
+
+    SemThread_Params_init(&semThreadP);
+    semThreadP.mode = SemThread_Mode_COUNTING;
+
+    semThreadH = SemThread_create(0, &semThreadP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create semaphore");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+    poolAry[0].sem = SemThread_Handle_upCast(semThreadH);
+
+    /* initialize the static worker pools, poolAry[1..(n-1)] */
+    for (i = 0; i < params->workerPools.length; i++) {
+        if (params->workerPools.elem[i].name != NULL) {
+            _strcpy(cp, params->workerPools.elem[i].name);
+            poolAry[i+1].name = cp;
+            cp += (_strlen(params->workerPools.elem[i].name) + 1);
+        }
+        else {
+            poolAry[i+1].name = NULL;
+        }
+
+        poolAry[i+1].count = params->workerPools.elem[i].count;
+        poolAry[i+1].priority = params->workerPools.elem[i].priority;
+        poolAry[i+1].osPriority =params->workerPools.elem[i].osPriority;
+        poolAry[i+1].stackSize = params->workerPools.elem[i].stackSize;
+        poolAry[i+1].stackSeg = NULL;
+
+        List_construct(&(poolAry[i+1].threadList), NULL);
+        List_construct(&(poolAry[i+1].readyQueue), NULL);
+
+        SemThread_Params_init(&semThreadP);
+        semThreadP.mode = SemThread_Mode_COUNTING;
+
+        semThreadH = SemThread_create(0, &semThreadP, &eb);
+
+        if (Error_check(&eb)) {
+            Log_error0(FXNN": could not create semaphore");
+            status = RcmServer_E_FAIL;
+            goto leave;
+        }
+
+        poolAry[i+1].sem = SemThread_Handle_upCast(semThreadH);
+    }
+
+    /* create the worker threads in each static pool */
+    for (i = 0; i < obj->poolMap0Len; i++) {
+        for (j = 0; j < poolAry[i].count; j++) {
+
+            /* allocate worker thread object */
+            size = sizeof(RcmServer_WorkerThread);
+            worker = (RcmServer_WorkerThread *)xdc_runtime_Memory_alloc(
+                RcmServer_Module_heap(), size, sizeof(Ptr), &eb);
+
+            if (Error_check(&eb)) {
+                Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+                    (IArg)RcmServer_Module_heap(), size);
+                status = RcmServer_E_NOMEMORY;
+                goto leave;
+            }
+
+            /* initialize worker thread object */
+            worker->jobId = RcmClient_DISCRETEJOBID;
+            worker->thread = NULL;
+            worker->terminate = FALSE;
+            worker->pool = &(poolAry[i]);
+            worker->server = obj;
+
+            /* add worker thread to worker pool */
+            listH = List_handle(&(poolAry[i].threadList));
+            List_putHead(listH, &(worker->elem));
+
+            /* create worker thread */
+            Thread_Params_init(&threadP);
+            threadP.arg = (IArg)worker;
+            threadP.priority = poolAry[i].priority;
+            threadP.osPriority = poolAry[i].osPriority;
+            threadP.stackSize = poolAry[i].stackSize;
+            threadP.instance->name = "RcmServer_workerThr";
+
+            worker->thread = Thread_create(
+                (Thread_RunFxn)(RcmServer_workerThrFxn_P), &threadP, &eb);
+
+            if (Error_check(&eb)) {
+                Log_error2(FXNN": could not create worker thread, "
+                    "pool=%d, thread=%d", (IArg)i, (IArg)j);
+                status = RcmServer_E_FAIL;
+                goto leave;
+            }
+        }
+    }
+
+    /* create the semaphore used to release the server thread */
+    SemThread_Params_init(&semThreadP);
+    semThreadP.mode = SemThread_Mode_COUNTING;
+
+    obj->run = SemThread_create(0, &semThreadP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create semaphore");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+    /* create the message queue for inbound messages */
+#if USE_MESSAGEQCOPY
+    obj->serverQue = MessageQCopy_create(MessageQCopy_ASSIGN_ANY, NULL, NULL,
+                                         &obj->localAddr);
+#ifdef BIOS_ONLY_TEST
+    obj->dstProc = MultiProc_self();
+#else
+    obj->dstProc = MultiProc_getId("HOST");
+#endif
+
+#else
+    MessageQ_Params_init(&mqParams);
+    obj->serverQue = MessageQ_create(name, &mqParams);
+#endif
+
+    if (NULL == obj->serverQue) {
+        Log_error0(FXNN": could not create server message queue");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+    /* create the server thread */
+    Thread_Params_init(&threadP);
+    threadP.arg = (IArg)obj;
+    threadP.priority = params->priority;
+    threadP.osPriority = params->osPriority;
+    threadP.stackSize = params->stackSize;
+    threadP.instance->name = "RcmServer_serverThr";
+
+    obj->serverThread = Thread_create(
+        (Thread_RunFxn)(RcmServer_serverThrFxn_P), &threadP, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": could not create server thread");
+        status = RcmServer_E_FAIL;
+        goto leave;
+    }
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_delete ========
+ */
+#define FXNN "RcmServer_delete"
+Int RcmServer_delete(RcmServer_Handle *handlePtr)
+{
+    RcmServer_Object *obj = (RcmServer_Object *)(*handlePtr);
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (handlePtr=0x%x)", (IArg)handlePtr);
+
+    /* finalize the object */
+    status = RcmServer_Instance_finalize_P(obj);
+
+    /* free the object memory */
+    Log_print1(Diags_LIFECYCLE, FXNN": instance delete: 0x%x", (IArg)obj);
+
+    xdc_runtime_Memory_free(RcmServer_Module_heap(),
+        (Ptr)obj, sizeof(RcmServer_Object));
+    *handlePtr = NULL;
+
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_destruct ========
+ */
+#define FXNN "RcmServer_destruct"
+Int RcmServer_destruct(RcmServer_Struct *structPtr)
+{
+    RcmServer_Object *obj = (RcmServer_Object *)(structPtr);
+    Int status = RcmClient_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (structPtr=0x%x)", (IArg)structPtr);
+    Log_print1(Diags_LIFECYCLE, FXNN": instance destruct: 0x%x", (IArg)obj);
+
+    /* finalize the object */
+    status = RcmServer_Instance_finalize_P(obj);
+
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_Instance_finalize_P ========
+ */
+#define FXNN "RcmServer_Instance_finalize_P"
+Int RcmServer_Instance_finalize_P(RcmServer_Object *obj)
+{
+    Int i, j;
+    Int size;
+    Char *cp;
+    UInt tabCount;
+    RcmServer_FxnTabElem *fdp;
+    Error_Block eb;
+    RcmServer_ThreadPool *poolAry;
+    RcmServer_WorkerThread *worker;
+    List_Elem *elem;
+    List_Handle listH;
+    List_Handle msgQueH;
+    RcmClient_Packet *packet;
+#if USE_MESSAGEQCOPY == 0
+    MessageQ_Msg msgqMsg;
+#endif
+    SemThread_Handle semThreadH;
+    RcmServer_JobStream *job;
+    Int rval;
+    Int status = RcmClient_S_SUCCESS;
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (obj=0x%x)", (IArg)obj);
+
+    /* must initialize the error block before using it */
+    Error_init(&eb);
+
+    /* block until server thread exits */
+    obj->shutdown = TRUE;
+
+    if (obj->serverThread != NULL) {
+#if USE_MESSAGEQCOPY
+        MessageQCopy_unblock(obj->serverQue);
+#else
+        MessageQ_unblock(obj->serverQue);
+#endif
+        Thread_join(obj->serverThread, &eb);
+
+        if (Error_check(&eb)) {
+            Log_error0(FXNN": server thread did not exit properly");
+            status = RcmServer_E_FAIL;
+            goto leave;
+        }
+    }
+
+    /* delete any remaining job objects (there should not be any) */
+    while ((elem = List_get(obj->jobList)) != NULL) {
+        job = (RcmServer_JobStream *)elem;
+
+        /* return any remaining messages (there should not be any) */
+        msgQueH = List_handle(&job->msgQue);
+
+        while ((elem = List_get(msgQueH)) != NULL) {
+            packet = (RcmClient_Packet *)elem;
+            Log_warning2(
+                FXNN": returning unprocessed message, jobId=0x%x, packet=0x%x",
+                (IArg)job->jobId, (IArg)packet);
+
+            RcmServer_setStatusCode_I(packet, RcmServer_Status_Unprocessed);
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            rval = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            msgqMsg = &packet->msgqHeader;
+            rval = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (rval < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)rval);
+            }
+        }
+
+        /* finalize the job stream object */
+        List_destruct(&job->msgQue);
+
+        xdc_runtime_Memory_free(RcmServer_Module_heap(),
+            (Ptr)job, sizeof(RcmServer_JobStream));
+    }
+    List_delete(&(obj->jobList));
+
+    /* convenience alias */
+    poolAry = obj->poolMap[0];
+
+    /* free all the static pool resources */
+    for (i = 0; i < obj->poolMap0Len; i++) {
+
+        /* free all the worker thread objects */
+        listH = List_handle(&(poolAry[i].threadList));
+
+        /* mark each worker thread for termination */
+        elem = NULL;
+        while ((elem = List_next(listH, elem)) != NULL) {
+            worker = (RcmServer_WorkerThread *)elem;
+            worker->terminate = TRUE;
+        }
+
+        /* unblock each worker thread so it can terminate */
+        elem = NULL;
+        while ((elem = List_next(listH, elem)) != NULL) {
+            Semaphore_post(poolAry[i].sem, &eb);
+
+            if (Error_check(&eb)) {
+                Log_error0(FXNN": post failed on thread");
+                status = RcmServer_E_FAIL;
+                goto leave;
+            }
+        }
+
+        /* wait for each worker thread to terminate */
+        elem = NULL;
+        while ((elem = List_get(listH)) != NULL) {
+            worker = (RcmServer_WorkerThread *)elem;
+
+            Thread_join(worker->thread, &eb);
+
+            if (Error_check(&eb)) {
+                Log_error1(
+                    FXNN": worker thread did not exit properly, thread=0x%x",
+                    (IArg)worker->thread);
+                status = RcmServer_E_FAIL;
+                goto leave;
+            }
+
+            Thread_delete(&worker->thread);
+
+            /* free the worker thread object */
+            xdc_runtime_Memory_free(RcmServer_Module_heap(), (Ptr)worker,
+                sizeof(RcmServer_WorkerThread));
+        }
+
+        /* free up pool resources */
+        semThreadH = SemThread_Handle_downCast(poolAry[i].sem);
+        SemThread_delete(&semThreadH);
+        List_destruct(&(poolAry[i].threadList));
+
+        /* return any remaining messages on the readyQueue */
+        msgQueH = List_handle(&poolAry[i].readyQueue);
+
+        while ((elem = List_get(msgQueH)) != NULL) {
+            packet = (RcmClient_Packet *)elem;
+            Log_warning2(
+                FXNN": returning unprocessed message, msgId=0x%x, packet=0x%x",
+                (IArg)packet->msgId, (IArg)packet);
+
+            RcmServer_setStatusCode_I(packet, RcmServer_Status_Unprocessed);
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            rval = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            msgqMsg = &packet->msgqHeader;
+            rval = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (rval < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)rval);
+            }
+        }
+
+        List_destruct(&(poolAry[i].readyQueue));
+    }
+
+    /* free the name block for the static pools */
+    if ((obj->poolMap[0] != NULL) && (obj->poolMap[0]->name != NULL)) {
+        cp = obj->poolMap[0]->name;
+        cp -= sizeof(SizeT);
+        xdc_runtime_Memory_free(RcmServer_Module_heap(), (Ptr)cp, *(SizeT *)cp);
+    }
+
+    /* free the static worker pool table */
+    if (obj->poolMap[0] != NULL) {
+        xdc_runtime_Memory_free(RcmServer_Module_heap(), (Ptr)(obj->poolMap[0]),
+            obj->poolMap0Len * sizeof(RcmServer_ThreadPool));
+        obj->poolMap[0] = NULL;
+    }
+
+#if 0
+    /* free all dynamic worker pools */
+    for (p = 1; p < RcmServer_POOL_MAP_LEN; p++) {
+        if ((poolAry = obj->poolMap[p]) == NULL) {
+            continue;
+        }
+    }
+#endif
+
+    /* free up the dynamic function tables and any leftover name strings */
+    for (i = 1; i < RcmServer_MAX_TABLES; i++) {
+        if (obj->fxnTab[i] != NULL) {
+            tabCount = (1 << (i + 4));
+            for (j = 0; j < tabCount; j++) {
+                if (((obj->fxnTab[i])+j)->name != NULL) {
+                    cp = ((obj->fxnTab[i])+j)->name;
+                    size = _strlen(cp) + 1;
+                    xdc_runtime_Memory_free(RcmServer_Module_heap(), cp, size);
+                }
+            }
+            fdp = obj->fxnTab[i];
+            size = tabCount * sizeof(RcmServer_FxnTabElem);
+            xdc_runtime_Memory_free(RcmServer_Module_heap(), fdp, size);
+            obj->fxnTab[i] = NULL;
+        }
+    }
+
+    if (NULL != obj->serverThread) {
+        Thread_delete(&obj->serverThread);
+    }
+
+    if (NULL != obj->serverQue) {
+#if USE_MESSAGEQCOPY
+        MessageQCopy_delete(&obj->serverQue);
+#else
+        MessageQ_delete(&obj->serverQue);
+#endif
+    }
+
+    if (NULL != obj->run) {
+        SemThread_delete((SemThread_Handle *)(&obj->run));
+    }
+
+    /* free the name block for the static function table */
+    if ((NULL != obj->fxnTabStatic.elem) &&
+        (NULL != obj->fxnTabStatic.elem[0].name)) {
+        for (size = 0, i = 0; i < obj->fxnTabStatic.length; i++) {
+            size += _strlen(obj->fxnTabStatic.elem[i].name) + 1;
+        }
+        xdc_runtime_Memory_free(
+            RcmServer_Module_heap(),
+            obj->fxnTabStatic.elem[0].name, size);
+    }
+
+    /* free the static function table */
+    if (NULL != obj->fxnTabStatic.elem) {
+        xdc_runtime_Memory_free(RcmServer_Module_heap(),
+            obj->fxnTabStatic.elem,
+            obj->fxnTabStatic.length * sizeof(RcmServer_FxnTabElem));
+    }
+
+    /* destruct the instance gate */
+    GateThread_destruct(&obj->gate);
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_addSymbol ========
+ */
+#define FXNN "RcmServer_addSymbol"
+Int RcmServer_addSymbol(RcmServer_Object *obj, String funcName,
+        RcmServer_MsgFxn addr, UInt32 *index)
+{
+    GateThread_Handle gateH;
+    IArg key;
+    Int len;
+    UInt i, j;
+    UInt tabCount;
+    SizeT tabSize;
+    UInt32 fxnIdx = 0xFFFF;
+    RcmServer_FxnTabElem *slot = NULL;
+    Error_Block eb;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, name=0x%x, addr=0x%x)",
+        (IArg)obj, (IArg)funcName, (IArg)addr);
+
+    Error_init(&eb);
+
+    /* protect the symbol table while changing it */
+    gateH = GateThread_handle(&obj->gate);
+    key = GateThread_enter(gateH);
+
+    /* look for an empty slot to use */
+    for (i = 1; i < RcmServer_MAX_TABLES; i++) {
+        if (obj->fxnTab[i] != NULL) {
+            for (j = 0; j < (1 << (i + 4)); j++) {
+                if (((obj->fxnTab[i])+j)->addr.fxn == 0) {
+                    slot = (obj->fxnTab[i]) + j;  // found empty slot
+                    break;
+                }
+            }
+        }
+        else {
+            /* all previous tables are full, allocate a new table */
+            tabCount = (1 << (i + 4));
+            tabSize = tabCount * sizeof(RcmServer_FxnTabElem);
+            obj->fxnTab[i] = (RcmServer_FxnTabElem *)xdc_runtime_Memory_alloc(
+                RcmServer_Module_heap(), tabSize, sizeof(Ptr), &eb);
+
+            if (Error_check(&eb)) {
+                Log_error0(FXNN": unable to allocate new function table");
+                obj->fxnTab[i] = NULL;
+                status = RcmServer_E_NOMEMORY;
+                goto leave;
+            }
+
+            /* initialize the new table */
+            for (j = 0; j < tabCount; j++) {
+                ((obj->fxnTab[i])+j)->addr.fxn = 0;
+                ((obj->fxnTab[i])+j)->name = NULL;
+                ((obj->fxnTab[i])+j)->key = 0;
+            }
+
+            /* use first slot in new table */
+            j = 0;
+            slot = (obj->fxnTab[i])+j;
+        }
+
+        /* if new slot found, break out of loop */
+        if (slot != NULL) {
+            break;
+        }
+    }
+
+    /* insert new symbol into slot */
+    if (slot != NULL) {
+        slot->addr.fxn = addr;
+        len = _strlen(funcName) + 1;
+        slot->name = (String)xdc_runtime_Memory_alloc(
+            RcmServer_Module_heap(), len, sizeof(Char *), &eb);
+
+        if (Error_check(&eb)) {
+            Log_error0(FXNN": unable to allocate function name");
+            slot->name = NULL;
+            status = RcmServer_E_NOMEMORY;
+            goto leave;
+        }
+
+        _strcpy(slot->name, funcName);
+        slot->key = RcmServer_getNextKey_P(obj);
+        fxnIdx = (slot->key << _RCM_KeyShift) | (i << 12) | j;
+    }
+
+    /* error, no more room to add new symbol */
+    else {
+        Log_error0(FXNN": cannot add symbol, table is full");
+        status = RcmServer_E_SYMBOLTABLEFULL;
+        goto leave;
+    }
+
+
+leave:
+    GateThread_leave(gateH, key);
+
+    /* on success, return new function index */
+    if (status >= 0) {
+        *index = fxnIdx;
+    }
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_removeSymbol ========
+ */
+#define FXNN "RcmServer_removeSymbol"
+Int RcmServer_removeSymbol(RcmServer_Object *obj, String name)
+{
+    GateThread_Handle gateH;
+    IArg key;
+    UInt32 fxnIdx;
+    UInt tabIdx, tabOff;
+    RcmServer_FxnTabElem *slot;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, name=0x%x)", (IArg)obj, (IArg)name);
+
+    /* protect the symbol table while changing it */
+    gateH = GateThread_handle(&obj->gate);
+    key = GateThread_enter(gateH);
+
+    /* find the symbol in the table */
+    status = RcmServer_getSymIdx_P(obj, name, &fxnIdx);
+
+    if (status < 0) {
+        Log_error0(FXNN": given symbol not found");
+        goto leave;
+    }
+
+    /* static symbols have bit-31 set, cannot remove these symbols */
+    if (fxnIdx & 0x80000000) {
+        Log_error0(FXNN": cannot remove static symbol");
+        status = RcmServer_E_SYMBOLSTATIC;
+        goto leave;
+    }
+
+    /* get slot pointer */
+    tabIdx = (fxnIdx & 0xF000) >> 12;
+    tabOff = (fxnIdx & 0xFFF);
+    slot = (obj->fxnTab[tabIdx]) + tabOff;
+
+    /* clear the table index */
+    slot->addr.fxn = 0;
+    if (slot->name != NULL) {
+        xdc_runtime_Memory_free(
+            RcmServer_Module_heap(), slot->name, _strlen(slot->name) + 1);
+        slot->name = NULL;
+    }
+    slot->key = 0;
+
+leave:
+    GateThread_leave(gateH, key);
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_start ========
+ */
+#define FXNN "RcmServer_start"
+Int RcmServer_start(RcmServer_Object *obj)
+{
+    Error_Block eb;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (obj=0x%x)", (IArg)obj);
+
+    Error_init(&eb);
+
+    /* unblock the server thread */
+    Semaphore_post(obj->run, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": semaphore post failed");
+        status = RcmServer_E_FAIL;
+    }
+
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_acqJobId_P ========
+ */
+#define FXNN "RcmServer_acqJobId_P"
+Int RcmServer_acqJobId_P(RcmServer_Object *obj, UInt16 *jobIdPtr)
+{
+    Error_Block eb;
+    GateThread_Handle gateH;
+    IArg key;
+    Int count;
+    UInt16 jobId;
+    List_Elem *elem;
+    RcmServer_JobStream *job;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, jobIdPtr=0x%x)", (IArg)obj, (IArg)jobIdPtr);
+
+    Error_init(&eb);
+    gateH = GateThread_handle(&obj->gate);
+
+    /* enter critical section */
+    key = GateThread_enter(gateH);
+
+    /* compute new job id */
+    for (count = 0xFFFF; count > 0; count--) {
+
+        /* generate a new job id */
+        jobId = (obj->jobId == 0xFFFF ? obj->jobId = 1 : ++(obj->jobId));
+
+        /* verify job id is not in use */
+        elem = NULL;
+        while ((elem = List_next(obj->jobList, elem)) != NULL) {
+            job = (RcmServer_JobStream *)elem;
+            if (jobId == job->jobId) {
+                jobId = RcmClient_DISCRETEJOBID;
+                break;
+            }
+        }
+
+        if (jobId != RcmClient_DISCRETEJOBID) {
+            break;
+        }
+    }
+
+    /* check if job id was acquired */
+    if (jobId == RcmClient_DISCRETEJOBID) {
+        *jobIdPtr = RcmClient_DISCRETEJOBID;
+        Log_error0(FXNN": no job id available");
+        status = RcmServer_E_FAIL;
+        GateThread_leave(gateH, key);
+        goto leave;
+    }
+
+    /* create a new job steam object */
+    job = xdc_runtime_Memory_alloc(RcmServer_Module_heap(),
+        sizeof(RcmServer_JobStream), sizeof(Ptr), &eb);
+
+    if (Error_check(&eb)) {
+        Log_error2(FXNN": out of memory: heap=0x%x, size=%u",
+            (IArg)RcmServer_Module_heap(), sizeof(RcmServer_JobStream));
+        status = RcmServer_E_NOMEMORY;
+        GateThread_leave(gateH, key);
+        goto leave;
+    }
+
+    /* initialize new job stream object */
+    job->jobId = jobId;
+    job->empty = TRUE;
+    List_construct(&(job->msgQue), NULL);
+
+    /* put new job stream object at end of server list */
+    List_put(obj->jobList, (List_Elem *)job);
+
+    /* leave critical section */
+    GateThread_leave(gateH, key);
+
+    /* return new job id */
+    *jobIdPtr = jobId;
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_dispatch_P ========
+ *
+ *  Return Value
+ *      < 0: error
+ *        0: success, job stream queue
+ *      > 0: success, ready queue
+ *
+ *  Pool id description
+ *
+ *  Static Worker Pools
+ *  --------------------------------------------------------------------
+ *  15      1 = static pool
+ *  14:8    reserved
+ *  7:0     offset: 0 - 255
+ *
+ *  Dynamic Worker Pools
+ *  --------------------------------------------------------------------
+ *  15      0 = dynamic pool
+ *  14:7    key: 0 - 255
+ *  6:5     index: 1 - 3
+ *  4:0     offset: 0 - [7, 15, 31]
+ */
+#define FXNN "RcmServer_dispatch_P"
+Int RcmServer_dispatch_P(RcmServer_Object *obj, RcmClient_Packet *packet)
+{
+    GateThread_Handle gateH;
+    IArg key;
+    List_Elem *elem;
+    List_Handle listH;
+    RcmServer_ThreadPool *pool;
+    UInt16 jobId;
+    RcmServer_JobStream *job;
+    Error_Block eb;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, packet=0x%x)", (IArg)obj, (IArg)packet);
+
+    Error_init(&eb);
+
+    /* get the target pool id from the message */
+    status = RcmServer_getPool_P(obj, packet, &pool);
+
+    if (status < 0) {
+        goto leave;
+    }
+
+    System_printf("Rcm dispatch: p:%d j:%d f:%d l:%d\n",
+                  packet->message.poolId, packet->message.jobId,
+                  packet->message.fxnIdx, packet->message.dataSize);
+
+    /* discrete jobs go on the end of the ready queue */
+    jobId = packet->message.jobId;
+
+    if (jobId == RcmClient_DISCRETEJOBID) {
+        listH = List_handle(&pool->readyQueue);
+        List_put(listH, (List_Elem *)packet);
+
+        /* dispatch a new worker thread */
+        Semaphore_post(pool->sem, &eb);
+
+        if (Error_check(&eb)) {
+            Log_error0(FXNN": semaphore post failed");
+        }
+    }
+
+    /* must be a job stream message */
+    else {
+        /* must protect job list while searching it */
+        gateH = GateThread_handle(&obj->gate);
+        key = GateThread_enter(gateH);
+
+        /* find the job stream object in the list */
+        elem = NULL;
+        while ((elem = List_next(obj->jobList, elem)) != NULL) {
+            job = (RcmServer_JobStream *)elem;
+            if (job->jobId == jobId) {
+                break;
+            }
+        }
+
+        if (elem == NULL) {
+            Log_error1(FXNN": failed to find jobId=%d", (IArg)jobId);
+            status = RcmServer_E_JobIdNotFound;
+        }
+
+        /* if job object is empty, place message directly on ready queue */
+        else if (job->empty) {
+            job->empty = FALSE;
+            listH = List_handle(&pool->readyQueue);
+            List_put(listH, (List_Elem *)packet);
+
+            /* dispatch a new worker thread */
+            Semaphore_post(pool->sem, &eb);
+
+            if (Error_check(&eb)) {
+                Log_error0(FXNN": semaphore post failed");
+            }
+        }
+
+        /* place message on job queue */
+        else {
+            listH = List_handle(&job->msgQue);
+            List_put(listH, (List_Elem *)packet);
+        }
+
+        GateThread_leave(gateH, key);
+    }
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_execMsg_I ========
+ */
+Int RcmServer_execMsg_I(RcmServer_Object *obj, RcmClient_Message *msg)
+{
+    RcmServer_MsgFxn fxn;
+#if USE_MESSAGEQCOPY
+    RcmServer_MsgCreateFxn createFxn = NULL;
+#endif
+    Int status;
+
+    status = RcmServer_getFxnAddr_P(obj, msg->fxnIdx, &fxn, &createFxn);
+
+    if (status >= 0) {
+#if 0
+        System_printf("RcmServer_execMsg_I: Calling fxnIdx: %d\n",
+                      (msg->fxnIdx & 0x0000FFFF));
+#endif
+#if USE_MESSAGEQCOPY
+        if (createFxn)  {
+            msg->result = (*createFxn)(obj, msg->dataSize, msg->data);
+        }
+        else {
+            msg->result = (*fxn)(msg->dataSize, msg->data);
+        }
+#else
+        msg->result = (*fxn)(msg->dataSize, msg->data);
+#endif
+    }
+
+    return(status);
+}
+
+
+/*
+ *  ======== RcmServer_getFxnAddr_P ========
+ *
+ *  The function index (fxnIdx) uses the following format. Note that the
+ *  format differs for static vs. dynamic functions. All static functions
+ *  are in fxnTab[0], all dynamic functions are in fxnTab[1 - 8].
+ *
+ *  Bits    Description
+ *
+ *  Static Function Index
+ *  --------------------------------------------------------------------
+ *  31      static/dynamic function flag
+ *              0 = dynamic function
+ *              1 = static function
+ *  30:20   reserved
+ *  19:16   reserved
+ *  15:0    offset: 0 - 65,535
+ *
+ *  Dynamic Function Index
+ *  --------------------------------------------------------------------
+ *  31      static/dynamic function flag
+ *              0 = dynamic function
+ *              1 = static function
+ *  30:20   key
+ *  19:16   reserved
+ *  15:12   index: 1 - 8
+ *  11:0    offset: 0 - [31, 63, 127, 255, 511, 1023, 2047, 4095]
+ */
+#define FXNN "RcmServer_getFxnAddr_P"
+Int RcmServer_getFxnAddr_P(RcmServer_Object *obj, UInt32 fxnIdx,
+        RcmServer_MsgFxn *addrPtr, RcmServer_MsgCreateFxn *createPtr)
+{
+    UInt i, j;
+    UInt16 key;
+    RcmServer_FxnTabElem *slot;
+    RcmServer_MsgFxn addr = NULL;
+    RcmServer_MsgCreateFxn createAddr = NULL;
+    Int status = RcmServer_S_SUCCESS;
+
+    /* static functions have bit-31 set */
+    if (fxnIdx & 0x80000000) {
+        j = (fxnIdx & 0x0000FFFF);
+        if (j < (obj->fxnTabStatic.length)) {
+
+            /* fetch the function address from the table */
+            slot = (obj->fxnTab[0])+j;
+            if (j == 0)  {
+                 createAddr = slot->addr.createFxn;
+            }
+            else {
+                 addr = slot->addr.fxn;
+            }
+        }
+        else {
+            Log_error1(FXNN": invalid function index 0x%x", (IArg)fxnIdx);
+            status = RcmServer_E_InvalidFxnIdx;
+            goto leave;
+        }
+    }
+    /* must be a dynamic function */
+    else {
+        /* extract the key from the function index */
+        key = (fxnIdx & _RCM_KeyMask) >> _RCM_KeyShift;
+
+        i = (fxnIdx & 0xF000) >> 12;
+        if ((i > 0) && (i < RcmServer_MAX_TABLES) && (obj->fxnTab[i] != NULL)) {
+
+            /* fetch the function address from the table */
+            j = (fxnIdx & 0x0FFF);
+            slot = (obj->fxnTab[i])+j;
+            addr = slot->addr.fxn;
+
+            /* validate the key */
+            if (key != slot->key) {
+                Log_error1(FXNN": invalid function index 0x%x", (IArg)fxnIdx);
+                status = RcmServer_E_InvalidFxnIdx;
+                goto leave;
+            }
+        }
+        else {
+            Log_error1(FXNN": invalid function index 0x%x", (IArg)fxnIdx);
+            status = RcmServer_E_InvalidFxnIdx;
+            goto leave;
+        }
+    }
+
+leave:
+    if (status >= 0) {
+       if (j == 0)  {
+           *createPtr = createAddr;
+       }
+       else {
+           *addrPtr = addr;
+       }
+    }
+    return(status);
+}
+#undef FXNN
+
+
+/* *  ======== RcmServer_getSymIdx_P ========
+ *
+ *  Must have table gate before calling this function.
+ */
+#define FXNN "RcmServer_getSymIdx_P"
+Int RcmServer_getSymIdx_P(RcmServer_Object *obj, String name, UInt32 *index)
+{
+    UInt i, j, len;
+    RcmServer_FxnTabElem *slot;
+    UInt32 fxnIdx = 0xFFFFFFFF;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print3(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, name=0x%x, index=0x%x)",
+        (IArg)obj, (IArg)name, (IArg)index);
+
+    /* search tables for given function name */
+    for (i = 0; i < RcmServer_MAX_TABLES; i++) {
+        if (obj->fxnTab[i] != NULL) {
+            len = (i == 0) ? obj->fxnTabStatic.length : (1 << (i + 4));
+            for (j = 0; j < len; j++) {
+                slot = (obj->fxnTab[i]) + j;
+                if ((((obj->fxnTab[i])+j)->name != NULL) &&
+                    (_strcmp(((obj->fxnTab[i])+j)->name, name) == 0)) {
+                    /* found function name */
+                    if (i == 0) {
+                        fxnIdx = 0x80000000 | j;
+                    } else {
+                        fxnIdx = (slot->key << _RCM_KeyShift) | (i << 12) | j;
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (0xFFFFFFFF != fxnIdx) {
+            break;
+        }
+    }
+
+    /* log an error if the symbol was not found */
+    if (fxnIdx == 0xFFFFFFFF) {
+        Log_error0(FXNN": given symbol not found");
+        status = RcmServer_E_SYMBOLNOTFOUND;
+    }
+
+    /* if success, return symbol index */
+    if (status >= 0) {
+        *index = fxnIdx;
+    }
+
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_getNextKey_P ========
+ */
+UInt16 RcmServer_getNextKey_P(RcmServer_Object *obj)
+{
+    GateThread_Handle gateH;
+    IArg gateKey;
+    UInt16 key;
+
+
+    gateH = GateThread_handle(&obj->gate);
+    gateKey = GateThread_enter(gateH);
+
+    if (obj->key <= 1) {
+        obj->key = _RCM_KeyResetValue;  /* don't use 0 as a key value */
+    }
+    else {
+        (obj->key)--;
+    }
+    key = obj->key;
+
+    GateThread_leave(gateH, gateKey);
+
+    return(key);
+}
+
+
+/*
+ *  ======== RcmServer_getPool_P ========
+ */
+#define FXNN "RcmServer_getPool_P"
+Int RcmServer_getPool_P(RcmServer_Object *obj,
+        RcmClient_Packet *packet, RcmServer_ThreadPool **poolP)
+{
+    UInt16 poolId;
+    UInt16 offset;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    poolId = packet->message.poolId;
+
+    /* static pools have bit-15 set */
+    if (poolId & 0x8000) {
+        offset = (poolId & 0x00FF);
+        if (offset < obj->poolMap0Len) {
+            *poolP = &(obj->poolMap[0])[offset];
+        }
+        else {
+            Log_error1(FXNN": pool id=0x%x not found", (IArg)poolId);
+            *poolP = NULL;
+            status = RcmServer_E_PoolIdNotFound;
+            goto leave;
+        }
+    }
+
+leave:
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_process_P ========
+ */
+#define FXNN "RcmServer_process_P"
+Void RcmServer_process_P(RcmServer_Object *obj, RcmClient_Packet *packet)
+{
+    String name;
+    UInt32 fxnIdx;
+    RcmServer_MsgFxn fxn;
+    RcmClient_Message *rcmMsg;
+#if USE_MESSAGEQCOPY
+    RcmServer_MsgCreateFxn createFxn = NULL;
+#endif
+#if USE_MESSAGEQCOPY == 0
+    MessageQ_Msg msgqMsg;
+#endif
+    UInt16 messageType;
+    Error_Block eb;
+    UInt16 jobId;
+    Int rval;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, packet=0x%x)", (IArg)obj, (IArg)packet);
+
+    Error_init(&eb);
+
+    /* decode the message */
+    rcmMsg = &packet->message;
+#if USE_MESSAGEQCOPY == 0
+    msgqMsg = &packet->msgqHeader;
+#endif
+    Log_print1(Diags_INFO, FXNN": message desc=0x%x", (IArg)packet->desc);
+
+    /* extract the message type from the packet descriptor field */
+    messageType = (RcmClient_Desc_TYPE_MASK & packet->desc) >>
+        RcmClient_Desc_TYPE_SHIFT;
+
+    /* process the given message */
+    switch (messageType) {
+
+        case RcmClient_Desc_RCM_MSG:
+            rval = RcmServer_execMsg_I(obj, rcmMsg);
+
+            if (rval < 0) {
+                switch (rval) {
+                    case RcmServer_E_InvalidFxnIdx:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_INVALID_FXN);
+                        break;
+                    default:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_Error);
+                        break;
+                }
+            }
+            else if (rcmMsg->result < 0) {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_MSG_FXN_ERR);
+            }
+            else {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_SUCCESS);
+            }
+
+#if USE_MESSAGEQCOPY
+#if 0
+            System_printf("RcmServer_process_P: Sending reply from: %d to: %d\n",
+                      obj->localAddr, obj->replyAddr);
+#endif
+
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (status < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+            }
+            break;
+
+        case RcmClient_Desc_CMD:
+            status = RcmServer_execMsg_I(obj, rcmMsg);
+
+            /* if all went well, free the message */
+            if ((status >= 0) && (rcmMsg->result >= 0)) {
+
+#if USE_MESSAGEQCOPY == 0
+                status = MessageQ_free(msgqMsg);
+#endif
+                if (status < 0) {
+                    Log_error1(
+                        FXNN": MessageQ_free returned error %d", (IArg)status);
+                }
+            }
+
+            /* an error occurred, must return message to client */
+            else {
+                if (status < 0) {
+                    /* error trying to process the message */
+                    switch (status) {
+                        case RcmServer_E_InvalidFxnIdx:
+                            RcmServer_setStatusCode_I(
+                                packet, RcmServer_Status_INVALID_FXN);
+                            break;
+                        default:
+                            RcmServer_setStatusCode_I(
+                                packet, RcmServer_Status_Error);
+                            break;
+                    }
+                }
+                else  {
+                    /* error in message function */
+                    RcmServer_setStatusCode_I(
+                        packet, RcmServer_Status_MSG_FXN_ERR);
+                }
+
+                /* send error message back to client */
+#if USE_MESSAGEQCOPY
+                packet->hdr.type = OMX_RAW_MSG;
+                packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+                status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+                status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+                if (status < 0) {
+                    Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+                }
+            }
+            break;
+
+        case RcmClient_Desc_DPC:
+            rval = RcmServer_getFxnAddr_P(obj, rcmMsg->fxnIdx, &fxn,
+                                          &createFxn);
+
+            if (rval < 0) {
+                RcmServer_setStatusCode_I(
+                    packet, RcmServer_Status_SYMBOL_NOT_FOUND);
+                Error_init(&eb);
+            }
+
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (status < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+            }
+
+            /* invoke the function with a null context */
+#if USE_MESSAGEQCOPY
+            if (createFxn)  {
+                 (*createFxn)(obj, 0, NULL);
+            }
+            else {
+                 (*fxn)(0, NULL);
+            }
+#else
+            (*fxn)(0, NULL);
+#endif
+            break;
+
+        case RcmClient_Desc_SYM_ADD:
+            break;
+
+        case RcmClient_Desc_SYM_IDX:
+            name = (String)rcmMsg->data;
+            rval = RcmServer_getSymIdx_P(obj, name, &fxnIdx);
+
+            if (rval < 0) {
+                RcmServer_setStatusCode_I(
+                    packet, RcmServer_Status_SYMBOL_NOT_FOUND);
+            }
+            else {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_SUCCESS);
+                rcmMsg->data[0] = fxnIdx;
+                rcmMsg->result = 0;
+            }
+
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (status < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+            }
+            break;
+
+        case RcmClient_Desc_JOB_ACQ:
+            rval = RcmServer_acqJobId_P(obj, &jobId);
+
+            if (rval < 0) {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_Error);
+            }
+            else {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_SUCCESS);
+                *(UInt16 *)(&rcmMsg->data[0]) = jobId;
+                rcmMsg->result = 0;
+            }
+
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (status < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+            }
+            break;
+
+        case RcmClient_Desc_JOB_REL:
+            jobId = (UInt16)(rcmMsg->data[0]);
+            rval = RcmServer_relJobId_P(obj, jobId);
+
+            if (rval < 0) {
+                switch (rval) {
+                    case RcmServer_E_JobIdNotFound:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_JobNotFound);
+                        break;
+                    default:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_Error);
+                        break;
+                }
+                rcmMsg->result = rval;
+            }
+            else {
+                RcmServer_setStatusCode_I(packet, RcmServer_Status_SUCCESS);
+                rcmMsg->result = 0;
+            }
+
+#if USE_MESSAGEQCOPY
+            packet->hdr.type = OMX_RAW_MSG;
+            packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+            status = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+            status = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+            if (status < 0) {
+                Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)status);
+            }
+            break;
+
+        default:
+            Log_error1(FXNN": unknown message type recieved, 0x%x",
+                (IArg)messageType);
+            break;
+    }
+
+    Log_print0(Diags_EXIT, "<-- "FXNN":");
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_relJobId_P ========
+ */
+#define FXNN "RcmServer_relJobId_P"
+Int RcmServer_relJobId_P(RcmServer_Object *obj, UInt16 jobId)
+{
+    GateThread_Handle gateH;
+    IArg key;
+    List_Elem *elem;
+    List_Handle msgQueH;
+    RcmClient_Packet *packet;
+    RcmServer_JobStream *job;
+#if USE_MESSAGEQCOPY == 0
+    MessageQ_Msg msgqMsg;
+#endif
+    Int rval;
+    Int status = RcmServer_S_SUCCESS;
+
+
+    Log_print2(Diags_ENTRY,
+        "--> "FXNN": (obj=0x%x, jobId=0x%x)", (IArg)obj, (IArg)jobId);
+
+
+    /* must protect job list while searching and modifying it */
+    gateH = GateThread_handle(&obj->gate);
+    key = GateThread_enter(gateH);
+
+    /* find the job stream object in the list */
+    elem = NULL;
+    while ((elem = List_next(obj->jobList, elem)) != NULL) {
+        job = (RcmServer_JobStream *)elem;
+
+        /* remove the job stream object from the list */
+        if (job->jobId == jobId) {
+            List_remove(obj->jobList, elem);
+            break;
+        }
+    }
+
+    GateThread_leave(gateH, key);
+
+    if (elem == NULL) {
+        status = RcmServer_E_JobIdNotFound;
+        Log_error1(FXNN": failed to find jobId=%d", (IArg)jobId);
+        goto leave;
+    }
+
+    /* return any pending messages on the message queue */
+    msgQueH = List_handle(&job->msgQue);
+
+    while ((elem = List_get(msgQueH)) != NULL) {
+        packet = (RcmClient_Packet *)elem;
+        Log_warning2(
+            FXNN": returning unprocessed message, jobId=0x%x, packet=0x%x",
+            (IArg)jobId, (IArg)packet);
+
+        RcmServer_setStatusCode_I(packet, RcmServer_Status_Unprocessed);
+
+#if USE_MESSAGEQCOPY
+        packet->hdr.type = OMX_RAW_MSG;
+        packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+        rval = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+        msgqMsg = &packet->msgqHeader;
+        rval = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+        if (rval < 0) {
+            Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)rval);
+        }
+    }
+
+    /* finalize the job stream object */
+    List_destruct(&job->msgQue);
+
+    xdc_runtime_Memory_free(RcmServer_Module_heap(),
+        (Ptr)job, sizeof(RcmServer_JobStream));
+
+
+leave:
+    Log_print1(Diags_EXIT, "<-- "FXNN": %d", (IArg)status);
+    return(status);
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_serverThrFxn_P ========
+ */
+#define FXNN "RcmServer_serverThrFxn_P"
+Void RcmServer_serverThrFxn_P(IArg arg)
+{
+    Error_Block eb;
+    RcmClient_Packet *packet;
+#if USE_MESSAGEQCOPY
+    Char         recvBuf[MSGBUFFERSIZE];
+    UInt16       len;
+#else
+    MessageQ_Msg msgqMsg = NULL;
+#endif
+    Int rval;
+    Bool running = TRUE;
+    RcmServer_Object *obj = (RcmServer_Object *)arg;
+    Int dataSize;
+
+#if USE_MESSAGEQCOPY
+    packet = (RcmClient_Packet *)&recvBuf[0];
+#endif
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (arg=0x%x)", arg);
+
+    Error_init(&eb);
+
+    /* wait until ready to run */
+    Semaphore_pend(obj->run, Semaphore_FOREVER, &eb);
+
+    if (Error_check(&eb)) {
+        Log_error0(FXNN": Semaphore_pend failure in server thread");
+    }
+
+    /* main processing loop */
+    while (running) {
+        Log_print1(Diags_INFO,
+            FXNN": waiting for message, thread=0x%x",
+            (IArg)(obj->serverThread));
+
+        /* block until message arrives */
+        do {
+#if USE_MESSAGEQCOPY
+            rval = MessageQCopy_recv(obj->serverQue, (Ptr)&packet->hdr, &len,
+                      &obj->replyAddr, MessageQCopy_FOREVER);
+#if 0
+            System_printf("RcmServer_serverThrFxn_P: Received msg of len %d "
+                          "from: %d\n",
+                         len, obj->replyAddr);
+
+            System_printf("hdr - t:%d f:%d l:%d\n", packet->hdr.type,
+                          packet->hdr.flags, packet->hdr.len);
+
+            System_printf("pkt - d:%d m:%d\n", packet->desc, packet->msgId);
+#endif
+            if (packet->hdr.type == OMX_DISC_REQ) {
+                System_printf("RcmServer_serverThrFxn_P: Got OMX_DISCONNECT\n");
+            }
+            Assert_isTrue((len <= MSGBUFFERSIZE), NULL);
+            Assert_isTrue((packet->hdr.type == OMX_RAW_MSG) ||
+                          (packet->hdr.type == OMX_DISC_REQ) , NULL);
+
+            if ((rval < 0) && (rval != MessageQCopy_E_UNBLOCKED)) {
+#else
+            rval = MessageQ_get(obj->serverQue, &msgqMsg, MessageQ_FOREVER);
+            if ((rval < 0) && (rval != MessageQ_E_UNBLOCKED)) {
+#endif
+                Log_error1(FXNN": ipc error 0x%x", (IArg)rval);
+                /* keep running and hope for the best */
+            }
+#if USE_MESSAGEQCOPY
+        } while (FALSE);
+#else
+        } while ((msgqMsg == NULL) && !obj->shutdown);
+#endif
+
+        /* if shutdown, exit this thread */
+#if USE_MESSAGEQCOPY
+        if (obj->shutdown || packet->hdr.type == OMX_DISC_REQ) {
+            running = FALSE;
+            Log_print1(Diags_INFO,
+                FXNN": terminating, thread=0x%x", (IArg)(obj->serverThread));
+            continue;
+        }
+#else
+        if (obj->shutdown) {
+            running = FALSE;
+            Log_print1(Diags_INFO,
+                FXNN": terminating, thread=0x%x", (IArg)(obj->serverThread));
+            if (msgqMsg == NULL ) {
+                continue;
+            }
+        }
+#endif
+
+#if USE_MESSAGEQCOPY == 0
+        packet = (RcmClient_Packet *)msgqMsg;
+#endif
+
+        Log_print2(Diags_INFO,
+            FXNN": message received, thread=0x%x packet=0x%x",
+            (IArg)(obj->serverThread), (IArg)packet);
+
+        if ((packet->message.poolId == RcmClient_DEFAULTPOOLID)
+            && ((obj->poolMap[0])[0].count == 0)) {
+
+            /* in-band (server thread) message processing */
+            RcmServer_process_P(obj, packet);
+        }
+        else {
+            /* out-of-band (worker thread) message processing */
+            rval = RcmServer_dispatch_P(obj, packet);
+
+            /* if error, message was not dispatched; must return to client */
+            if (rval < 0) {
+                switch (rval) {
+                    case RcmServer_E_JobIdNotFound:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_JobNotFound);
+                        break;
+
+                    case RcmServer_E_PoolIdNotFound:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_PoolNotFound);
+                        break;
+
+                    default:
+                        RcmServer_setStatusCode_I(
+                            packet, RcmServer_Status_Error);
+                        break;
+                }
+                packet->message.result = rval;
+
+                /* return the message to the client */
+#if USE_MESSAGEQCOPY
+#if 0
+                System_printf("RcmServer_serverThrFxn_P: "
+                              "Sending response from: %d to: %d\n",
+                              obj->localAddr, obj->replyAddr);
+                System_printf("sending: %d + %d\n", PACKET_HDR_SIZE,
+                              packet->message.dataSize);
+#endif
+                packet->hdr.type = OMX_RAW_MSG;
+                if (rval < 0) {
+                    packet->hdr.len = sizeof(UInt32);
+                    packet->desc = 0x4142;
+                    packet->msgId = 0x0044;
+                    dataSize = sizeof(struct rpmsg_omx_hdr) + sizeof(UInt32);
+                }
+                else {
+                    packet->hdr.len = PACKET_DATA_SIZE +
+                        packet->message.dataSize;
+                    dataSize = PACKET_HDR_SIZE + packet->message.dataSize;
+                }
+                rval = MessageQCopy_send(obj->dstProc, obj->replyAddr,
+                                 obj->localAddr, (Ptr)&packet->hdr, dataSize);
+#else
+                rval = MessageQ_put(MessageQ_getReplyQueue(msgqMsg), msgqMsg);
+#endif
+                if (rval < 0) {
+                    Log_error1(FXNN": unknown ipc error, 0x%x", (IArg)rval);
+                }
+            }
+        }
+    }
+
+    System_printf("RcmServer_serverThrFxn_P: Exiting thread.\n");
+
+    Log_print0(Diags_EXIT, "<-- "FXNN":");
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_setStatusCode_I ========
+ */
+Void RcmServer_setStatusCode_I(RcmClient_Packet *packet, UInt16 code)
+{
+
+    /* code must be 0 - 15, it has to fit in a 4-bit field */
+    Assert_isTrue((code < 16), NULL);
+
+    packet->desc &= ~(RcmClient_Desc_TYPE_MASK);
+    packet->desc |= ((code << RcmClient_Desc_TYPE_SHIFT)
+        & RcmClient_Desc_TYPE_MASK);
+}
+
+
+/*
+ *  ======== RcmServer_workerThrFxn_P ========
+ */
+#define FXNN "RcmServer_workerThrFxn_P"
+Void RcmServer_workerThrFxn_P(IArg arg)
+{
+    Error_Block eb;
+    RcmClient_Packet *packet;
+    List_Elem *elem;
+    List_Handle listH;
+    List_Handle readyQueueH;
+    UInt16 jobId;
+    GateThread_Handle gateH;
+    IArg key;
+    RcmServer_ThreadPool *pool;
+    RcmServer_JobStream *job;
+    RcmServer_WorkerThread *obj;
+    Bool running;
+    Int rval;
+
+
+    Log_print1(Diags_ENTRY, "--> "FXNN": (arg=0x%x)", arg);
+
+    Error_init(&eb);
+    obj = (RcmServer_WorkerThread *)arg;
+    readyQueueH = List_handle(&obj->pool->readyQueue);
+    packet = NULL;
+    running = TRUE;
+
+    /* main processing loop */
+    while (running) {
+        Log_print1(Diags_INFO,
+            FXNN": waiting for job, thread=0x%x", (IArg)(obj->thread));
+
+        /* if no current message, wait until signaled to run */
+        if (packet == NULL) {
+            Semaphore_pend(obj->pool->sem, Semaphore_FOREVER, &eb);
+
+            if (Error_check(&eb)) {
+                Log_error0(FXNN": semaphore pend failed");
+            }
+        }
+
+        /* check if thread should terminate */
+        if (obj->terminate) {
+            running = FALSE;
+            Log_print1(Diags_INFO,
+                FXNN": terminating, thread=0x%x", (IArg)(obj->thread));
+            continue;
+        }
+
+        /* get next message from ready queue */
+        if (packet == NULL) {
+            packet = (RcmClient_Packet *)List_get(readyQueueH);
+        }
+
+        if (packet == NULL) {
+            Log_error1(FXNN": ready queue is empty, thread=0x%x",
+                (IArg)(obj->thread));
+            continue;
+        }
+
+        Log_print2(Diags_INFO, FXNN": job received, thread=0x%x packet=0x%x",
+            (IArg)obj->thread, (IArg)packet);
+
+        /* remember the message job id */
+        jobId = packet->message.jobId;
+
+        /* process the message */
+        RcmServer_process_P(obj->server, packet);
+        packet = NULL;
+
+        /* If this worker thread just finished processing a job message,
+         * queue up the next message for this job id. As an optimization,
+         * if the message is addressed to this worker's pool, then don't
+         * signal the semaphore, just get the next message from the queue
+         * and processes it. This keeps the current thread running instead
+         * of switching to another thread.
+         */
+        if (jobId != RcmClient_DISCRETEJOBID) {
+
+            /* must protect job list while searching it */
+            gateH = GateThread_handle(&obj->server->gate);
+            key = GateThread_enter(gateH);
+
+            /* find the job object in the list */
+            elem = NULL;
+            while ((elem = List_next(obj->server->jobList, elem)) != NULL) {
+                job = (RcmServer_JobStream *)elem;
+                if (job->jobId == jobId) {
+                    break;
+                }
+            }
+
+            /* if job object not found, it is not an error */
+            if (elem == NULL) {
+                GateThread_leave(gateH, key);
+                continue;
+            }
+
+            /* found the job object */
+            listH = List_handle(&job->msgQue);
+
+            /* get next job message and either process it or queue it */
+            do {
+                elem = List_get(listH);
+
+                if (elem == NULL) {
+                    job->empty = TRUE;  /* no more messages */
+                    break;
+                }
+                else {
+                    /* get target pool id */
+                    packet = (RcmClient_Packet *)elem;
+                    rval = RcmServer_getPool_P(obj->server, packet, &pool);
+
+                    /* if error, return the message to the client */
+                    if (rval < 0) {
+                        switch (rval) {
+                            case RcmServer_E_PoolIdNotFound:
+                                RcmServer_setStatusCode_I(
+                                    packet, RcmServer_Status_PoolNotFound);
+                                break;
+
+                            default:
+                                RcmServer_setStatusCode_I(
+                                    packet, RcmServer_Status_Error);
+                                break;
+                        }
+                        packet->message.result = rval;
+
+#if USE_MESSAGEQCOPY
+                        packet->hdr.type = OMX_RAW_MSG;
+                        packet->hdr.len = PACKET_DATA_SIZE + packet->message.dataSize;
+                        rval = MessageQCopy_send(
+                                 (obj->server)->dstProc,
+                                 (obj->server)->replyAddr,
+                                 (obj->server)->localAddr, (Ptr)&packet->hdr,
+                                 PACKET_HDR_SIZE + packet->message.dataSize);
+#else
+                        rval = MessageQ_put(
+                            MessageQ_getReplyQueue(&packet->msgqHeader),
+                            &packet->msgqHeader);
+#endif
+                        if (rval < 0) {
+                            Log_error1(
+                                FXNN": unknown ipc error, 0x%x", (IArg)rval);
+                        }
+                    }
+                    /* packet is valid, queue it in the corresponding pool's
+                     * ready queue */
+                    else {
+                        listH = List_handle(&pool->readyQueue);
+                        List_put(listH, elem);
+                        packet = NULL;
+                        Semaphore_post(pool->sem, &eb);
+
+                        if (Error_check(&eb)) {
+                            Log_error0(FXNN": semaphore post failed");
+                        }
+                    }
+
+                    /* loop around and wait to be run again */
+                }
+
+            } while (rval < 0);
+
+            GateThread_leave(gateH, key);
+        }
+    }  /* while (running) */
+
+    Log_print0(Diags_EXIT, "<-- "FXNN":");
+}
+#undef FXNN
+
+
+/*
+ *  ======== RcmServer_getLocalAddress ========
+ */
+UInt32 RcmServer_getLocalAddress(RcmServer_Object *obj)
+{
+    return(obj->localAddr);
+}
+
+
+/*
+ *  ======== RcmServer_getRemoteAddress ========
+ */
+UInt32 RcmServer_getRemoteAddress(RcmServer_Object *obj)
+{
+    return(obj->replyAddr);
+}
+
+
+
+/*
+ *  ======== RcmServer_getRemoteProc ========
+ */
+UInt16  RcmServer_getRemoteProc(RcmServer_Object *obj)
+{
+    return(obj->dstProc);
+}
diff --git a/packages/ti/grcm/RcmServer.h b/packages/ti/grcm/RcmServer.h
new file mode 100644 (file)
index 0000000..bc8f08e
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmServer.h ========
+ *
+ */
+
+/*!
+ *  @file ti/grcm/RcmServer.h
+ *
+ *  @brief Remote Command Message Server Module. An RcmServer processes
+ *  inbound messages received from an RcmClient.
+ *
+ *  The RcmServer processes inbound messages received from an RcmClient.
+ *  After processing a message, the server will return the message to
+ *  the client.
+ *
+ *  @sa RcmClient.h <br>
+ *  @ref ti_grcm "RCM Overview"
+ */
+
+/*!
+ *  @defgroup ti_grcm_RcmServer RcmServer
+ *
+ *  @brief Remote Command Message Server Module. An RcmServer processes
+ *  inbound messages received from an RcmClient.
+ *
+ *  The RcmServer module is used to create an server instance. RcmClients
+ *  send their messages to only one RcmServer instance for processing. The
+ *  server instance can be created with a function dispatch table and
+ *  additional tables can be added as requested by the clients.
+ *
+ *  Diagnostics
+ *
+ *  Diags_INFO - full detail log events
+ *  Diags_USER1 - message processing
+ *
+ *  @sa ti_grcm_RcmClient <br>
+ *  @ref ti_grcm "RCM Overview"
+ */
+
+#ifndef ti_grcm_RcmServer__include
+#define ti_grcm_RcmServer__include
+
+#include <xdc/runtime/knl/GateThread.h>
+#include <xdc/runtime/knl/Thread.h>
+
+
+/** @ingroup ti_grcm_RcmServer */
+/*@{*/
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+// -------- success and failure codes --------
+
+/*!
+ *  @brief Success return code
+ */
+#define RcmServer_S_SUCCESS (0)
+
+/*!
+ *  @brief General failure return code
+ */
+#define RcmServer_E_FAIL (-1)
+
+/*!
+ *  @brief The was insufficient memory left on the heap
+ */
+#define RcmServer_E_NOMEMORY (-2)
+
+/*!
+ *  @brief The given symbol was not found in the server's symbol table
+ *
+ *  This error could occur if the symbol spelling is incorrect or
+ *  if the RcmServer is still loading its symbol table.
+ */
+#define RcmServer_E_SYMBOLNOTFOUND (-3)
+
+/*!
+ *  @brief The given symbols is in the static table, it cannot be removed
+ *
+ *  All symbols installed at instance create time are added to the
+ *  static symbol table. They cannot be removed. The statis symbol
+ *  table must remain intact for the lifespan of the server instance.
+ */
+#define RcmServer_E_SYMBOLSTATIC (-4)
+
+/*!
+ *  @brief The server's symbol table is full
+ *
+ *  The symbol table is full. You must remove some symbols before
+ *  any new symbols can be added.
+ */
+#define RcmServer_E_SYMBOLTABLEFULL (-5)
+
+
+// -------- constants and types --------
+
+/*!
+ *  @brief Remote function type
+ *
+ *  All functions executed by the RcmServer must be of this
+ *  type. Typically, these functions are simply wrappers to the vendor
+ *  function. The server invokes this remote function by passing in
+ *  the RcmClient_Message.dataSize field and the address of the
+ *  RcmClient_Message.data array.
+ *
+ *  @code
+ *  RcmServer_MsgFxn fxn = ...;
+ *  RcmClient_Message *msg = ...;
+ *  msg->result = (*fxn)(msg->dataSize, msg->data);
+ *  @endcode
+ */
+
+typedef Int32 (*RcmServer_MsgFxn)(UInt32, UInt32 *);
+
+#if USE_MESSAGEQCOPY
+/* This is a special function which gets the RcmServer handle as first parameter
+ * so that OMX_GetHandle() or other creation functions can store the RcmServer
+ * handle in their own context.  This is needed to allow functions to send
+ * asynchrounous callbacks back to the RcmServer client.
+ */
+typedef Int32 (*RcmServer_MsgCreateFxn)(Void *, UInt32, UInt32 *);
+#endif
+
+
+
+/*!
+ *  @brief Function descriptor
+ *
+ *  This function descriptor is used internally in the server. Its
+ *  values are defined either at config time by the server's
+ *  RcmServer_Params.fxns create parameter or at runtime through a call to
+ *  RcmClient_addSymbol().
+ */
+typedef struct {
+    /*!
+     *  @brief The name of the function
+     *
+     *  The name is used for table lookup, it does not search the
+     *  actual symbol table. You can provide any string as long as it
+     *  is unique and the client uses the same name for lookup.
+     */
+    String name;
+
+    /*!
+     *  @brief The function address in the server's address space.
+     *
+     *  The server will ultimately branch to this address.
+     */
+#if USE_MESSAGEQCOPY
+    union  {
+       RcmServer_MsgFxn         fxn;
+       RcmServer_MsgCreateFxn   createFxn;
+    }addr;
+#else
+    RcmServer_MsgFxn addr;
+#endif
+
+} RcmServer_FxnDesc;
+
+/*!
+ *  @brief Function descriptor array
+ */
+typedef struct {
+    /*!
+     *  @brief The length of the array
+     */
+    Int length;
+
+    /*!
+     *  @brief Pointer to the array
+     */
+    RcmServer_FxnDesc *elem;
+
+} RcmServer_FxnDescAry;
+
+/*!
+ *  @brief Worker pool descriptor
+ *
+ *  Use this data structure to define a worker pool to be created either
+ *  at the server create time or dynamically at runtime.
+ */
+typedef struct {
+    /*!
+     *  @brief The name of the worker pool.
+     */
+    String name;
+
+    /*!
+     *  @brief The number of worker threads in the pool.
+     */
+    UInt count;
+
+    /*!
+     *  @brief The priority of all threads in the worker pool.
+     *
+     *  This value is Operating System independent. It determines the
+     *  execution priority of all the worker threads in the pool.
+     */
+    Thread_Priority priority;
+
+    /*!
+     *  @brief The priority (OS-specific) of all threads in the worker pool
+     *
+     *  This value is Operating System specific. It determines the execution
+     *  priority of all the worker threads in the pool. If this property is
+     *  set, it takes precedence over the priority property above.
+     */
+    Int osPriority;
+
+    /*!
+     *  @brief The stack size in bytes of a worker thread.
+     */
+    SizeT stackSize;
+
+    /*!
+     *  @brief The worker thread stack placement.
+     */
+    String stackSeg;
+
+} RcmServer_ThreadPoolDesc;
+
+/*!
+ *  @brief Worker pool descriptor array
+ */
+typedef struct {
+    /*!
+     *  @brief The length of the array
+     */
+    Int length;
+
+    /*!
+     *  @brief Pointer to the array
+     */
+    RcmServer_ThreadPoolDesc *elem;
+
+} RcmServer_ThreadPoolDescAry;
+
+
+/*!
+ *  @brief RcmServer instance object handle
+ */
+typedef struct RcmServer_Object_tag *RcmServer_Handle;
+
+/*!
+ *  @brief RcmServer Instance create parameters
+ */
+typedef struct {
+    /*!
+     *  @brief Server thread priority.
+     *
+     *  This value is Operating System independent. It determines the execution
+     *  priority of the server thread. The server thread reads the incoming
+     *  message and then either executes the message function (in-band
+     *  execution) or dispatches the message to a thread pool (out-of-band
+     *  execution). The server thread then wait on the next message.
+     */
+    Thread_Priority priority;
+
+    /*!
+     *  @brief Server thread priority (OS-specific).
+     *
+     *  This value is Operating System specific. It determines the execution
+     *  priority of the server thread. If this attribute is set, it takes
+     *  precedence over the priority attribute below. The server thread reads
+     *  the incoming message and then either executes the message function
+     *  (in-band execution) or dispatches the message to a thread pool
+     *  (out-of-band execution). The server thread then wait on the next
+     *  message.
+     */
+    Int osPriority;
+
+    /*!
+     *  @brief The stack size in bytes of the server thread.
+     */
+    SizeT stackSize;
+
+    /*!
+     *  @brief The server thread stack placement.
+     */
+    String stackSeg;
+
+    /*!
+     *  @brief The default thread pool used for anonymous messages.
+     */
+    RcmServer_ThreadPoolDesc defaultPool;
+
+    /*!
+     *  @brief Array of thread pool descriptors
+     *
+     *  The worker pools declared with this instance parameter are statically
+     *  bound to the server, they persist for the life of the server. They
+     *  cannot be removed with a call to RcmServer_deletePool(). However,
+     *  worker threads may be created or deleted at runtime.
+     *
+     */
+    RcmServer_ThreadPoolDescAry workerPools;
+
+    /*!
+     *  @brief Array of function names to install into the server
+     *
+     *  The functions declared with this instance parameter are statically
+     *  bound to the server, they persist for the life of the server. They
+     *  cannot be removed with a call to RcmServer_removeSymbol().
+     *
+     *  To specify a function address, use the & character in the string
+     *  as in the following example.
+     *
+     *  @code
+     *  RcmServer_FxnDesc serverFxnAry[] = {
+     *      { "LED_on",         LED_on  },
+     *      { "LED_off",        LED_off }
+     *  };
+     *
+     *  #define serverFxnAryLen (sizeof serverFxnAry / sizeof serverFxnAry[0])
+     *
+     *  RcmServer_FxnDescAry Server_fxnTab = {
+     *      serverFxnAryLen,
+     *      serverFxnAry
+     *  };
+     *
+     *  RcmServer_Params rcmServerP;
+     *  RcmServer_Params_init(&rcmServerP);
+     *  rcmServerP.fxns.length = Server_fxnTab.length;
+     *  rcmServerP.fxns.elem = Server_fxnTab.elem;
+     *
+     *  RcmServer_Handle rcmServerH;
+     *  rval = RcmServer_create("ServerA", &rcmServerP, &(rcmServerH));
+     *  @endcode
+     */
+    RcmServer_FxnDescAry fxns;
+
+} RcmServer_Params;
+
+/*!
+ *  @brief Opaque client structure large enough to hold an instance object
+ *
+ *  Use this structure to define an embedded RcmServer object.
+ *
+ *  @sa RcmServer_construct
+ */
+typedef struct {
+    GateThread_Struct   _f1;
+    Ptr                 _f2;
+#if USE_MESSAGEQCOPY
+    Ptr                 _f3a;
+    UInt32              _f3b;
+    UInt32              _f3c;
+    UInt32              _f3d;
+#else
+    Ptr                 _f3;
+#endif
+    Ptr                 _f4;
+    struct {
+        Int     _f1;
+        Ptr     _f2;
+    }                   _f5;
+    Ptr                 _f6[9];
+    UInt16              _f7;
+    UInt16              _f8;
+    Bool                _f9;
+    Int                 _f10;
+    Ptr                 _f11[4];
+    Ptr                 _f12;
+} RcmServer_Struct;
+
+
+// -------- functions --------
+
+/*
+ *  ======== RcmServer_addSymbol ========
+ */
+/*!
+ *  @brief Add a symbol to the server's function table
+ *
+ *  This function adds a new symbol to the server's function table.
+ *  This is useful for supporting Dynamic Load Libraries (DLLs).
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @param[in] name The function's name.
+ *
+ *  @param[in] addr The function's address in the server's address space.
+ *
+ *  @param[out] index The function's index value to be used in the
+ *  RcmClient_Message.fxnIdx field.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmServer_E_NOMEMORY
+ *  @retval RcmServer_E_SYMBOLTABLEFULL
+ */
+Int RcmServer_addSymbol(
+        RcmServer_Handle        handle,
+        String                  name,
+        RcmServer_MsgFxn        addr,
+        UInt32 *                index
+    );
+
+/*
+ *  ======== RcmServer_construct ========
+ */
+/*!
+ *  @brief Initialize a new instance object inside the provided structure
+ *
+ *  This function is the same as RcmServer_create() except that it does not
+ *  allocate memory for the instance object. The instance object is
+ *  constructed inside the provided structure. Call RcmServer_destruct()
+ *  to finalize a constructed instance object.
+ *
+ *  @param[in] structPtr A pointer to an allocated structure.
+ *
+ *  @param[in] name The name of the server. The RcmClient will
+ *  locate a server instance using this name. It must be unique to
+ *  the system.
+ *
+ *  @param[in] params The create params used to customize the instance object.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmServer_E_FAIL
+ *  @retval RcmServer_E_NOMEMORY
+ *
+ *  @sa RcmServer_create
+ */
+Int RcmServer_construct(
+        RcmServer_Struct *      structPtr,
+        String                  name,
+        const RcmServer_Params *params
+    );
+
+/*
+ *  ======== RcmServer_create ========
+ */
+/*!
+ *  @brief Create an RcmServer instance
+ *
+ *  A server instance is used to execute functions on behalf of an
+ *  RcmClient instance. There can be multiple server instances
+ *  on any given CPU. The servers typically reside on a remote CPU
+ *  from the RcmClient instance.
+ *
+ *  @param[in] name The name of the server. The RcmClient will
+ *  locate a server instance using this name. It must be unique to
+ *  the system.
+ *
+ *  @param[in] params The create params used to customize the instance object.
+ *
+ *  @param[out] handle An opaque handle to the created instance object.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmServer_E_FAIL
+ *  @retval RcmServer_E_NOMEMORY
+ */
+Int RcmServer_create(
+        String                  name,
+        RcmServer_Params *      params,
+        RcmServer_Handle *      handle
+    );
+
+/*
+ *  ======== RcmServer_delete ========
+ */
+/*!
+ *  @brief Delete an RcmServer instance
+ *
+ *  @param[in,out] handlePtr Handle to the instance object to delete.
+ */
+Int RcmServer_delete(
+        RcmServer_Handle *      handlePtr
+    );
+
+/*
+ *  ======== RcmServer_destruct ========
+ */
+/*!
+ *  @brief Finalize the instance object inside the provided structure
+ *
+ *  @param[in] structPtr A pointer to the structure containing the
+ *  instance object to finalize.
+ */
+Int RcmServer_destruct(
+        RcmServer_Struct *      structPtr
+    );
+
+/*
+ *  ======== RcmServer_exit ========
+ */
+/*!
+ *  @brief Finalize the RcmServer module
+ *
+ *  This function is used to finalize the RcmServer module. Any resources
+ *  acquired by RcmServer_init() will be released. Do not call any RcmServer
+ *  functions after calling RcmServer_exit().
+ *
+ *  This function must be serialized by the caller.
+ */
+Void RcmServer_exit(Void);
+
+/*
+ *  ======== RcmServer_init ========
+ */
+/*!
+ *  @brief Initialize the RcmServer module
+ *
+ *  This function is used to initialize the RcmServer module. Call this
+ *  function before calling any other RcmServer function.
+ *
+ *  This function must be serialized by the caller
+ */
+Void RcmServer_init(Void);
+
+/*
+ *  ======== RcmServer_Params_init ========
+ */
+/*!
+ *  @brief Initialize the instance create params structure
+ */
+Void RcmServer_Params_init(
+        RcmServer_Params *      params
+    );
+
+/*
+ *  ======== RcmServer_removeSymbol ========
+ */
+/*!
+ *  @brief Remove a symbol and from the server's function table
+ *
+ *  Useful when unloading a DLL from the server.
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @param[in] name The function's name.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmServer_E_SYMBOLNOTFOUND
+ *  @retval RcmServer_E_SYMBOLSTATIC
+ */
+Int RcmServer_removeSymbol(
+        RcmServer_Handle        handle,
+        String                  name
+    );
+
+/*
+ *  ======== RcmServer_start ========
+ */
+/*!
+ *  @brief Start the server
+ *
+ *  The server is created in stop mode. It will not start
+ *  processing messages until it has been started.
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @retval RcmClient_S_SUCCESS
+ *  @retval RcmServer_E_FAIL
+ */
+Int RcmServer_start(
+        RcmServer_Handle        handle
+    );
+
+
+#if USE_MESSAGEQCOPY
+/*
+ *  ======== RcmServer_getLocalAddress ========
+ */
+/*!
+ *  @brief Get the messageQ endpoint created for this server.
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @retval 32 bit address.
+ */
+UInt32 RcmServer_getLocalAddress(
+       RcmServer_Handle        handle
+    );
+
+/*
+ *  ======== RcmServer_getRemoteAddress ========
+ */
+/*!
+ *  @brief Get the remote messageQ endpoint for the client of this server.
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @retval 32 bit address.
+ */
+UInt32 RcmServer_getRemoteAddress(
+       RcmServer_Handle        handle
+    );
+
+/*
+ *  ======== RcmServer_getRemoteProc ========
+ */
+/*!
+ *  @brief Get the remote procId for the client of this server.
+ *
+ *  @param[in] handle Handle to an instance object.
+ *
+ *  @retval 32 bit address.
+ */
+UInt16  RcmServer_getRemoteProc(
+       RcmServer_Handle        handle
+    );
+
+
+#endif
+
+
+#if defined (__cplusplus)
+}
+#endif /* defined (__cplusplus) */
+
+/*@}*/
+#endif /* ti_grcm_RcmServer__include */
diff --git a/packages/ti/grcm/RcmServer.xdc b/packages/ti/grcm/RcmServer.xdc
new file mode 100644 (file)
index 0000000..e6c1cd4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmServer.xdc ========
+ *
+ */
+
+package ti.grcm;
+
+
+/*!
+ *  ======== RcmServer ========
+ *  Remote Command Message Server module
+ *
+ *  This is the RTSC meta-only module documentation. Please see the links
+ *  below for the runtime documentation.
+ *
+ *  @a(See Also)
+ *  @p(dlist)
+ *  - {@link doxy(ti_grcm_RcmServer) RcmServer API Reference}
+ *  - {@link doxy(RcmServer.h) RcmServer File Reference}
+ *  - {@link doxy(ti_grcm) RCM Overview}
+ *  @p
+ */
+
+metaonly module RcmServer
+{
+
+}
diff --git a/packages/ti/grcm/RcmServer.xs b/packages/ti/grcm/RcmServer.xs
new file mode 100644 (file)
index 0000000..fd62853
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmServer.xs ========
+ *
+ */
+
+/*
+ *  ======== module$use ========
+ *  Use other modules required by this module
+ */
+function module$use()
+{
+    var Settings = xdc.module(this.$package.$name + '.Settings');
+
+    /* Settings.ipc config param cannot be undefined */
+    if (Settings.ipc == undefined) {
+        throw new Error("the " + Settings.$name + ".ipc config param"
+        + " is undefined, it must be assigned a value by"
+        + " the application config script.");
+    }
+
+    xdc.useModule('xdc.runtime.Assert');
+    xdc.useModule('xdc.runtime.Diags');
+    xdc.useModule('xdc.runtime.Error');
+    xdc.useModule('xdc.runtime.Log');
+    xdc.useModule('xdc.runtime.Memory');
+    xdc.useModule('xdc.runtime.Startup');
+    xdc.useModule('xdc.runtime.knl.GateThread');
+    xdc.useModule('xdc.runtime.knl.Semaphore');
+    xdc.useModule('xdc.runtime.knl.Sync');
+    xdc.useModule('xdc.runtime.knl.SyncSemThread');
+    xdc.useModule('xdc.runtime.knl.Thread');
+
+    if (Settings.IpcSupport_ti_sdo_ipc == Settings.ipc) {
+        xdc.useModule('ti.sdo.utils.List');
+    }
+    else if (Settings.IpcSupport_ti_syslink_ipc == Settings.ipc) {
+        throw new Error("unsupported value for " + Settings.$name
+        + ".ipc config param (" + Settings.ipc + ")");
+    }
+    else {
+        throw new Error("unknown value for " + Settings.$name
+        + ".ipc config param (" + Settings.ipc + ")");
+    }
+}
diff --git a/packages/ti/grcm/RcmTypes.h b/packages/ti/grcm/RcmTypes.h
new file mode 100644 (file)
index 0000000..523e63a
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmTypes.h ========
+ *
+ */
+
+#ifndef ti_grcm_RcmTypes_h
+#define ti_grcm_RcmTypes_h
+
+/*
+ * Force use of the MessageQCopy instead of MessageQ API for SysLink 3 IPC.
+ * This is temporary to get a protoype working.
+ * Ideally, MessageQCopy should not be needed.
+ */
+#define USE_MESSAGEQCOPY   1
+
+#if USE_MESSAGEQCOPY
+#include <ti/ipc/rpmsg/MessageQCopy.h>
+#else
+#include <ti/ipc/MessageQ.h>
+#endif
+
+#include <ti/grcm/RcmClient.h>
+
+
+/*
+ *  ======== RcmClient_Packet ========
+ *
+ *  RcmClient_Packet.desc: the package descriptor field. Note that the
+ *  format is different for out-bound and in-bound messages.
+ *
+ *  out-bound message descriptor
+ *
+ *  Bits    Description
+ *  --------------------------------------------------------------------
+ *  [15:12] reserved
+ *  [11:8]  message type
+ *  [7:0]   client protocol version
+ *
+ *
+ *  in-bound message descriptor
+ *
+ *  Bits    Description
+ *  --------------------------------------------------------------------
+ *  [15:12] reserved
+ *  [11:8]  server status code
+ *  [7:0]   server protocol version
+ */
+
+/* message type values */
+#define RcmClient_Desc_RCM_MSG    0x1       // client exec message
+#define RcmClient_Desc_DPC        0x2       // deferred procedure call
+#define RcmClient_Desc_SYM_ADD    0x3       // symbol add message
+#define RcmClient_Desc_SYM_IDX    0x4       // query symbox index
+#define RcmClient_Desc_CMD        0x5       // cmd message (one-way)
+#define RcmClient_Desc_JOB_ACQ    0x6       // acquire a job id
+#define RcmClient_Desc_JOB_REL    0x7       // release a job id
+#define RcmClient_Desc_TYPE_MASK  0x0F00    // field mask
+#define RcmClient_Desc_TYPE_SHIFT 8         // field shift width
+
+/* server status codes must be 0 - 15, it has to fit in a 4-bit field */
+#define RcmServer_Status_SUCCESS          ((UInt16)0) // success
+#define RcmServer_Status_INVALID_FXN      ((UInt16)1) // invalid fxn index
+#define RcmServer_Status_SYMBOL_NOT_FOUND ((UInt16)2) // symbol not found
+#define RcmServer_Status_INVALID_MSG_TYPE ((UInt16)3) // invalid msg type
+#define RcmServer_Status_MSG_FXN_ERR      ((UInt16)4) // msg function error
+#define RcmServer_Status_Error            ((UInt16)5) // general failure
+#define RcmServer_Status_Unprocessed      ((UInt16)6) // unprocessed message
+#define RcmServer_Status_JobNotFound      ((UInt16)7) // job id not found
+#define RcmServer_Status_PoolNotFound     ((UInt16)8) // pool id not found
+
+/* the packet structure (actual message send to server) */
+
+#if USE_MESSAGEQCOPY
+/* Need to deal with this structure, as Linux side rpmsg_omx driver needs it: */
+struct rpmsg_omx_hdr {
+    UInt32 type;
+    UInt32 flags;
+    UInt32 len;
+};
+
+// Warning: This packet cannot be placed on RCMServer job queues, so can't use
+// that capability for now.
+typedef struct {
+    Bits32             reserved0; // reserved for List.elem->next
+    Bits32             reserved1; // reserved for List.elem->prev
+    struct rpmsg_omx_hdr hdr;
+    UInt16             desc;      // protocol, descriptor, status
+    UInt16             msgId;     // message id
+    RcmClient_Message  message;   // client message body (5 words + payload)
+} RcmClient_Packet;
+
+/*
+ * Defined to equal packed structure size received on the host.
+ * Strips off the first two ListElem fields and the .data[1] field in .message
+ */
+#define PACKET_HDR_SIZE  (sizeof(RcmClient_Packet) - 3 * sizeof(UInt32))
+#define PACKET_DATA_SIZE (PACKET_HDR_SIZE - sizeof(struct rpmsg_omx_hdr))
+
+/* To test on BIOS side only, uncomment and rebuild anything that
+ * calls MessageQCopy()
+ */
+//#define  BIOS_ONLY_TEST
+
+#else
+typedef struct {
+    MessageQ_MsgHeader msgqHeader;  // MessageQ header (8 words)
+    UInt16 desc;                    // protocol, descriptor, status
+    UInt16 msgId;                   // message id
+    RcmClient_Message message;      // client message body (5 words + payload)
+} RcmClient_Packet;
+
+#endif
+
+/* string functions */
+Void *_memset(Void *s, Int c, Int n);
+Int _strcmp(Char *s, Char *t);
+Void _strcpy(Char *s, Char *t);
+Int _strlen(const Char *s);
+
+#endif /* ti_grcm_RcmTypes_h */
diff --git a/packages/ti/grcm/RcmUtils.c b/packages/ti/grcm/RcmUtils.c
new file mode 100644 (file)
index 0000000..79a25a5
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== RcmUtils.c ========
+ *
+ */
+
+#include <xdc/std.h>
+#include "RcmTypes.h"
+
+
+/*
+ *  ======== memset ========
+ */
+Void *_memset(Void *s, Int c, Int n)
+{
+    UChar *p = (UChar *)s;
+
+    while (n-- > 0) {
+        *p++ = (UChar)c;
+    }
+
+    return(s);
+}
+
+
+/*
+ *  ======== _strcpy ========
+ *  Copy t to s, including null character.
+ */
+Void _strcpy(Char *s, Char *t)
+{
+    while ((*s++ = *t++))
+        ;
+}
+
+
+/*
+ *  ======== _strcmp ========
+ *  Return <0 if s<t, 0 if s==t, >0 if s>t
+ */
+Int _strcmp(Char *s, Char *t)
+{
+    for ( ; *s == *t; s++, t++) {
+        if (*s == '\0') {
+            return(0);
+        }
+    }
+    return(*s - *t);
+}
+
+
+/*
+ *  ======== _strlen ========
+ *  Return length of s
+ */
+Int _strlen(const Char *s)
+{
+    Int n;
+
+    for (n = 0; *s != '\0'; s++) {
+        n++;
+    }
+    return(n);
+}
diff --git a/packages/ti/grcm/Settings.xdc b/packages/ti/grcm/Settings.xdc
new file mode 100644 (file)
index 0000000..d162d29
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== Settings.xdc ========
+ *
+ */
+
+
+package ti.grcm;
+
+
+/*!
+ *  ======== Settings ========
+ *  Global configuration settings for the ti.grcm package
+ *
+ *  This is a RTSC meta-only module. When building your executable with
+ *  XDCtools, use this module to configure this package.
+ *
+ *  @a(See Also)
+ *  @p(dlist)
+ *  - {@link doxy(ti_grcm) RCM Overview}
+ *  - {@link doxy(RcmClient.h) RcmClient File Reference}
+ *  - {@link doxy(RcmServer.h) RcmServer File Reference}
+ *  @p
+ */
+
+metaonly module Settings
+{
+
+    // -------- Module Constants --------
+
+    // -------- Module Types --------
+
+    /*!
+     *  IPC Support enumeration type
+     *
+     *  The IPC support is provided by one of the following types.
+     */
+    enum IpcSupport {
+        IpcSupport_ti_sdo_ipc,          //! DSP/BIOS IPC Support
+        IpcSupport_ti_syslink_ipc       //! SysLink IPC Support
+    };
+
+
+    // -------- Module Parameters --------
+
+    /*!
+     *  Specifies which IPC support to link into the executable
+     *
+     *  This config param must be set in the application config script.
+     *  It has no default value.
+     */
+    config IpcSupport ipc = IpcSupport_ti_sdo_ipc;
+
+    /*!
+     *  Controls the loading of string constants to the target
+     *
+     *  By default, all string constants are loaded to the target. If the
+     *  program is using a logger which does not process the strings, then
+     *  setting this config param to false will reduce the program's data
+     *  footprint because the string constants will not be loaded.
+     */
+    config Bool loadStrings = true;
+}
diff --git a/packages/ti/grcm/Settings.xs b/packages/ti/grcm/Settings.xs
new file mode 100644 (file)
index 0000000..67231ef
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== Settings.xs ========
+ *
+ */
+
+
+/*
+ *  ======== module$validate ========
+ *  Validate the module's state
+ */
+function module$validate()
+{
+    /* ipc config param cannot be undefined */
+    if (this.ipc == undefined) {
+        throw new Error("ipc config param is undefined, it must be"
+        + " assigned a value by the application config script.");
+    }
+    else if (this.ipc == this.IpcSupport_ti_syslink_ipc) {
+        throw new Error("ipc config param cannot be set to "
+        + "IpcSupport_ti_syslink_ipc, it is only supported with "
+        + "IpcSupport_ti_sdo_ipc");
+    }
+}
diff --git a/packages/ti/grcm/doxygen.txt b/packages/ti/grcm/doxygen.txt
new file mode 100644 (file)
index 0000000..b35bca2
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This is a little header file which doxygen parses to generate the main
+ * documentation page for the ti.rcm package.
+ */
+
+/*!
+ * @page ti_rcm Remote Command Message Overview
+ *
+ * @section modules Modules
+ *
+ *  Remote Command Message - message based remote function execution
+ *
+ *  The Remote Command Message (RCM) package provides a client/server
+ *  implementation for executing functions on a remote processor. The
+ *  package contains the following modules.
+ *     - @ref ti_rcm_RcmClient "RcmClient" - Client Module
+ *     - @ref ti_rcm_RcmServer "RcmServer" - Server Module
+ *
+ *  This package provides modules for a client/server based implementation
+ *  for executing functions on a remote processor. The IPC layer is based
+ *  on messages. The application uses the RcmClient module to allocate a
+ *  message, specify the remote function and its arguments, and then send
+ *  the message to the server for execution. When the message returns, it
+ *  contains the remote function's return values. The server is typically
+ *  on a remote processor, but local server instances (on the same processor
+ *  as the client) are also supported.
+ *
+ *  The following image provides an overview of a typical use case. An
+ *  application running on the local cpu creates an RcmClient instance.
+ *  Using the RcmClient instance handle, the application has access to all
+ *  the necessary operations for executing a message on the remote server.
+ *  The application must fill in the message with the remote function
+ *  index, as supplied by the server, and the context needed by the remote
+ *  function to execute. For higher level operations such as RPC, see the
+ *  <tt>link ti.rpc.gen</tt> package which provides support for generating
+ *  the stub and skeleton functions.
+ *
+ *  @image html ti/rcm/doc-files/Overview.png "Diagram 1: RCM Overview"
+ *
+ *  The RcmClient module is used to create instance objects. Each instance
+ *  can send messages only to the server specified at create time. You
+ *  create an instance for each server you want to send messages to. At
+ *  create time the heap must be specified. The heap is used by the instance
+ *  for allocating messages.
+ *
+ *  There are four types of execute commands:
+ *  - synchronous blocking
+ *  - synchronous non-blocking
+ *  - synchronous deferred
+ *  - asynchronous non-blocking
+ *
+ *  Here is an overview of the exec commands. See the
+ *  @ref ti_rcm_RcmClient "RcmClient" module for more details on each
+ *  function.
+ *
+ *  - RcmClient_exec() - synchronous blocking
+ *    This function sends a message to the server and waits for the server
+ *    to execute the message and to send the return message back to the
+ *    client.
+ *
+ *  - RcmClient_execNoWait() - synchronous non-blocking
+ *    This function sends a message to the server but does not wait for the
+ *    return message. Control returns to the caller as soon as the message
+ *    has been delivered to the underlying transport. The server will
+ *    execute the message and send the return message back to the client
+ *    where it is placed in a mailbox. The client collects the return message
+ *    with a call to RcmClient_waitUntilDone() which is a blocking call.
+ *    This is useful when the client has more work to do while the remote
+ *    function is executing. It is also efficient because it does not require
+ *    a local callback thread.
+ *
+ *  - RcmClient_execDpc() - synchronous deferred
+ *    This function sends a message to the server and waits for the return
+ *    message. When the server receives the message, it does not immediately
+ *    execute it. Instead, it copies the message context into a local buffer
+ *    and sends the message back to the client. Only after the message has
+ *    been sent to the client, does the server execute the function. This is
+ *    useful for server shutdown. This allows the client to regain ownership
+ *    of the message and to return it to the heap and allows the server to
+ *    shutdown without owning any resources allocated by the client.
+ *
+ *  - RcmClient_execAsync() - asynchronous non-blocking
+ *    This function sends a message to the server but does not wait for the
+ *    return message. Control returns to the caller as in the synchronous
+ *    non-blocking case above. The server will execute the message and send
+ *    the return message back to the client for delivery to a callback
+ *    thread. When the return message arrives, the callback thread will
+ *    invoke an application callback to notify the application that the
+ *    return message has arrived. This is the only asynchronous part of the
+ *    sequence as the application will be preempted by the callback thread.
+ *    It is the application's responsibility to periodically monitor a flag
+ *    (set by the callback) to complete the message delivery.
+ *
+ *  <h2>RTSC Configuration</h2>
+ *
+ *  When using XDCtools to build your executable, use the following module
+ *  to define the build time configuration options.
+ *
+ *  @rtsc(ti.rcm.Settings RCM Settings Module)
+ */
diff --git a/packages/ti/grcm/link.xdt b/packages/ti/grcm/link.xdt
new file mode 100644 (file)
index 0000000..c891e9a
--- /dev/null
@@ -0,0 +1,38 @@
+%%{
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%%}
+
+%var suffix = Program.build.target.findSuffix(this);
+SECTIONS {
+    grcm.noload: { grcm.a`suffix`(.const:.string) }, load > 0, type = COPY
+}
diff --git a/packages/ti/grcm/package.bld b/packages/ti/grcm/package.bld
new file mode 100644 (file)
index 0000000..493b231
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  ======== package.bld ========
+ *
+ */
+
+/* explicit references to global objects */
+var Build = xdc.useModule('xdc.bld.BuildEnvironment');
+var Pkg = xdc.useModule('xdc.bld.PackageContents');
+var smpBuild = java.lang.System.getenv("BUILD_SMP");
+
+/* clean lib folder */
+Pkg.generatedFiles.$add("lib/");
+Pkg.generatedFiles.$add("nocfg/");
+Pkg.generatedFiles.$add("nocfg.mak");
+Pkg.libDir = "package/";
+
+/* add custom makefiles to build model */
+Pkg.makePrologue =
+    "-include prologue.mak\n" +
+    "-include docs.mak\n";
+
+/* add custom files to all releases */
+Pkg.attrs.exportSrc = false;
+Pkg.attrs.exportCfg = true;
+Pkg.otherFiles = [
+    "RcmClient.h",
+    "RcmServer.h",
+    "RcmTypes.h"
+];
+
+/* list of libraries to build */
+var libArray = new Array();
+if (smpBuild == "1") {
+    /* grcm with ti.ipc for IPU SMP target */
+    libArray.push(
+        {
+            name: "ti.grcm_smp",
+            sources: [
+                "RcmServer.c",
+                "RcmUtils.c"
+            ],
+            libAttrs: {
+                defs: "-DRCM_ti_ipc"
+            }
+        }
+    );
+}
+else {
+    /* grcm with ti.ipc for regular targets */
+    libArray.push(
+        {
+            name: "ti.grcm",
+            sources: [
+                "RcmServer.c",
+                "RcmUtils.c"
+            ],
+            libAttrs: {
+                defs: "-DRCM_ti_ipc"
+            }
+        }
+    );
+}
+
+/* generate the package libraries */
+/* check if profile specified in XDCARGS */
+/* XDCARGS="... profile=debug ..." */
+var cmdlProf = (" " + arguments.join(" ") + " ").match(/ profile=([^ ]+) /);
+cmdlProf = cmdlProf != null ? cmdlProf[1] : null;
+
+/* ==== loop over array of libraries ==== */
+for (var i = 0; i < libArray.length; i++) {
+    var lib = libArray[i];
+
+    /* ==== loop over all targets in build array ==== */
+    for (var j = 0; j < Build.targets.length; j++) {
+        var targ = Build.targets[j];
+
+        /* invoke user supplied target predicate function */
+        if (this.skipTarget != undefined)  {
+            continue;
+        }
+
+        /* skip target if not compatible with source code */
+        if ("icw" in lib) {
+            var skipTarget = true;
+            var targIsaChain = "/" + targ.getISAChain().join("/") + "/";
+            for (var k = 0; k < lib.icw.length; k++) {
+                if (targIsaChain.match("/" + lib.icw[k] + "/")) {
+                    skipTarget = false;
+                    break;
+                }
+            }
+            if (skipTarget) continue;
+        }
+
+        /* skip target if it does not generate code for the given isa */
+        if ("isas" in lib) {
+            var skipTarget = true;
+            var list = "/" + lib.isas.join("/") + "/";
+            if (list.match("/" + targ.isa + "/")) {
+                skipTarget = false;
+            }
+            if (skipTarget) continue;
+        }
+
+        /* ==== loop over all profiles ==== */
+        for (var profile in targ.profiles) {
+
+            /* skip profile if different than specified on command line */
+            if ((cmdlProf != null) && (profile != cmdlProf)) {
+                continue;
+            }
+
+            /* name = lib/profile/name.a+suffix */
+            var name = "lib/" + profile + "/" + lib.name;
+
+            /* pass along library attributes specified in library array */
+            var libAttrs = "libAttrs" in lib ? lib.libAttrs : {};
+
+            /* must set profile explicitly */
+            libAttrs.profile = profile;
+
+            /* build the library */
+            var library = Pkg.addLibrary(name, targ, libAttrs);
+
+            /* add the source files */
+            library.addObjects(lib.sources);
+        }
+    }
+}
diff --git a/packages/ti/grcm/package.xdc b/packages/ti/grcm/package.xdc
new file mode 100644 (file)
index 0000000..f9e9f8c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ *  ======== package.xdc ========
+ *
+ */
+
+
+/*!
+ *  ======== ti.grcm ========
+ *  Remote Command Message Package
+ *
+ *  The Remote Command Message (RCM) package provides a client/server
+ *  implementation for executing functions on a remote processor. See
+ *  documentation links below for more information.
+ *
+ *  @a(See Also)
+ *  @p(dlist)
+ *  - {@link doxy(ti_grcm) RCM Overview}
+ *  - {@link doxy(RcmClient.h) RcmClient File Reference}
+ *  - {@link doxy(RcmServer.h) RcmServer File Reference}
+ *  @p
+ *
+ */
+package ti.grcm [2,1,0] {
+    module RcmServer;
+    module Settings;
+}
diff --git a/packages/ti/grcm/package.xs b/packages/ti/grcm/package.xs
new file mode 100644 (file)
index 0000000..7bce1b6
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * *  Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * *  Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * *  Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  ======== package.xs ========
+ *
+ */
+
+/*
+ *  ======== getLibs ========
+ */
+function getLibs(prog)
+{
+    var suffix;
+    var file;
+    var libAry = [];
+    var profile = this.profile;
+    var smp = "";
+
+    suffix = prog.build.target.findSuffix(this);
+    if (suffix == null) {
+        return "";  /* nothing to contribute */
+    }
+
+    if (prog.platformName.match(/ipu/)) {
+        smp = "_smp";
+    }
+
+    /* make sure the library exists, else fallback to a built library */
+    file = "lib/" + profile + "/ti.grcm" + smp + ".a" + suffix;
+    if (java.io.File(this.packageBase + file).exists()) {
+        libAry.push(file);
+    }
+    else {
+        file = "lib/release/ti.grcm" + smp + ".a" + suffix;
+        if (java.io.File(this.packageBase + file).exists()) {
+            libAry.push(file);
+        }
+        else {
+            /* fallback to a compatible library built by this package */
+            for (var p in this.build.libDesc) {
+                if (suffix == this.build.libDesc[p].suffix) {
+                    libAry.push(p);
+                    break;
+                }
+            }
+        }
+    }
+
+    return libAry.join(";");
+}
+
+/*
+ *  ======== getSects ========
+ */
+function getSects()
+{
+    var Settings = this.Settings;
+
+    if (!Settings.loadStrings) {
+        return "ti/grcm/link.xdt";
+    }
+    else {
+        return null;
+    }
+}
diff --git a/packages/ti/grcm/prologue.mak b/packages/ti/grcm/prologue.mak
new file mode 100644 (file)
index 0000000..eb91d0c
--- /dev/null
@@ -0,0 +1,46 @@
+#
+#  Copyright (c) 2011-2013, Texas Instruments Incorporated
+#  All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#
+#  *  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#
+#  *  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+#  *  Neither the name of Texas Instruments Incorporated nor the names of
+#     its contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+#  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+.PRECIOUS: nocfg.mak
+# all: package/.nocfg
+
+package/.nocfg: nocfg.mak RcmClient.c RcmServer.c RcmUtils.c
+       -$(RM) $@
+       @$(ECHO) "#"
+       @$(ECHO) "# Building nocfg ..."
+       @$(MAKE) -f nocfg.mak all
+       $(TOUCH) $@
+
+nocfg.mak: .interfaces
+       @$(ECHO) "#"
+       @$(ECHO) "# Generating nocfg ..."
+       @$(XDCROOT)/xs nocfg.utils.gen ti.grcm