]> rtime.felk.cvut.cz Git - ert_linux.git/commitdiff
Add debuging version of ext_svr.c
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 11 Jul 2013 19:11:06 +0000 (21:11 +0200)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 11 Jul 2013 19:35:44 +0000 (21:35 +0200)
ert_linux/ert_linux.tlc
ert_linux/ert_linux_genfiles.tlc [new file with mode: 0644]
ert_linux/ext_svr.c [new file with mode: 0644]

index 67353b9101e4c581ba6ba786bfdefaefe6239b55..3a0d73f8da61762be880d2b4990def39a826a192 100644 (file)
@@ -32,6 +32,7 @@
 %include "commontargetlib.tlc"
 
 %include "codegenentry.tlc"
+%include "ert_linux_genfiles.tlc"
 
 /%
   BEGIN_RTW_OPTIONS
diff --git a/ert_linux/ert_linux_genfiles.tlc b/ert_linux/ert_linux_genfiles.tlc
new file mode 100644 (file)
index 0000000..6fe15cb
--- /dev/null
@@ -0,0 +1,6 @@
+/% Copy my custom version of ext_svr (for debugging) %/
+%openfile ext_svr="ext_svr.c"
+%selectfile ext_svr
+/* Ahoj */
+%include "ext_svr.c"
+%closefile ext_svr
diff --git a/ert_linux/ext_svr.c b/ert_linux/ext_svr.c
new file mode 100644 (file)
index 0000000..30a7384
--- /dev/null
@@ -0,0 +1,1411 @@
+/*
+ * Copyright 1994-2012 The MathWorks, Inc.
+ *
+ * File: ext_svr.c     
+ *
+ * Abstract:
+ *  External mode server interface (TCPIP example).  Provides functions
+ *  that get called by main routine (model-name.c):
+ *    o ExtParseArgsAndInitUD:  parse args and create UserData
+ *    o ExtWaitForStartPkt:     return true if waiting for host to start
+ *    o rt_ExtModeInit:         external mode initialization
+ *    o rt_ExtModeSleep:        pause the process
+ *    o rt_PktServerWork:       server for setting/getting packets from host
+ *    o rt_PktServer:           server dispatcher - for multi-tasking targets
+ *    o rt_UploadServerWork:    server for setting data upload packets on host
+ *    o rt_UploadServer:        server dispatcher - for multi-tasking targets
+ *    o rt_ExtModeShutdown:     external mode termination
+ *
+ *  Parameter downloading and data uploading supported for single and
+ *  multi-tasking targets.
+ */
+
+/*****************
+ * Include files *
+ *****************/
+
+/*ANSI C headers*/
+#ifndef EXTMODE_DISABLEPRINTF  
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(VXWORKS)
+ /*VxWorks headers*/
+# include <selectLib.h>
+# include <sockLib.h>
+# include <inetLib.h>
+# include <ioLib.h>
+# include <taskLib.h>
+#endif
+
+/*Real Time Workshop headers*/
+#include "rtwtypes.h"
+#include "rtw_extmode.h"
+
+#include "ext_types.h"
+#include "ext_share.h"
+#include "ext_test.h"
+#include "ext_svr_transport.h"
+#include "updown.h"
+#include "updown_util.h"
+#include "dt_info.h"
+
+/*Uncomment to test 4 byte reals*/
+/*#define real_T float*/
+
+/**********************
+ * External Variables *
+ **********************/
+extern int_T           volatile startModel;
+extern TargetSimStatus volatile modelStatus;
+#ifdef VXWORKS
+extern SEM_ID uploadSem;
+extern SEM_ID pktSem;
+#endif
+extern boolean_T host_upstatus_is_uploading;
+
+/********************
+ * Global Variables *
+ ********************/
+
+/*
+ * Flags.
+ */
+PRIVATE boolean_T   connected       = FALSE;
+PRIVATE boolean_T   commInitialized = FALSE;
+
+/*
+ * Pointer to opaque user data (defined by ext_svr_transport.c).
+ */
+PRIVATE ExtUserData *extUD          = NULL;
+
+/*
+ * Buffer used to receive packets.
+ */
+PRIVATE int_T pktBufSize = 0;
+PRIVATE char  *pktBuf    = NULL;
+
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+#ifndef EXTMODE_DISABLEPRINTF 
+PRIVATE char ERRMSG_PROCESSSELECTSIGNAL[] = 
+            "\nError in UploadLogInfoInit(). Most likely a memory\n"
+            "allocation error or an attempt to re-initialize the\n"
+            "signal selection during the data logging process\n"
+            "(i.e., multiple EXT_SELECT_SIGNAL packets were received\n"
+            "before the logging session terminated or an\n"
+            "EXT_CANCEL_LOGGING packet was received)\n";
+
+PRIVATE char ERRMSG_PROCESSSELECTTRIGGER[] = 
+            "\nError in UploadInitTrigger(). Most likely a memory\n"
+            "allocation error or an attempt to re-initialize the\n"
+            "trigger selection during the data logging process\n"
+            "(i.e., multiple EXT_SELECT_TRIGGER packets were received\n"
+            "before the logging session terminated or an\n"
+            "EXT_CANCEL_LOGGING packet was received)\n";
+#else
+PRIVATE char ERRMSG_PROCESSSELECTSIGNAL[] = "";
+PRIVATE char ERRMSG_PROCESSSELECTTRIGGER[] = "";
+#endif
+#endif
+
+/*******************
+ * Local Functions *
+ *******************/
+
+/* Function: GrowRecvBufIfNeeded ===============================================
+ * Abstract:
+ *  Allocate or increase the size of buffer for receiving packets from target.
+ */
+PRIVATE boolean_T GrowRecvBufIfNeeded(const int pktSize)
+{
+    if (pktSize > pktBufSize) {
+        if (pktBuf != NULL) {
+            free(pktBuf);
+            pktBufSize = 0;
+        }
+
+        pktBuf = (char *)malloc(pktSize);
+        if (pktBuf == NULL) return(EXT_ERROR);
+
+        pktBufSize = pktSize;
+    }
+    return(EXT_NO_ERROR);
+} /* end GrowRecvBufIfNeeded */
+
+
+/* Function: GetPktHdr =========================================================
+ * Abstract:
+ *  Attempts to retrieve a packet header from the host.  If a header is in 
+ *  fact retrieved, the reference arg, 'hdrAvail' will be returned as true.
+ *
+ *  EXT_NO_ERROR is returned on success, EXT_ERROR is returned on failure.
+ *
+ * NOTES:
+ *  o It is not necessarily an error for 'hdrAvail' to be returned as false.
+ *    It typically means that we were polling for packets and none were
+ *    available.
+ */
+PRIVATE boolean_T GetPktHdr(PktHeader *pktHdr, boolean_T *hdrAvail)
+{
+    int_T     nGot      = 0; /* assume */
+    int_T     nGotTotal = 0;
+    int_T     pktSize   = sizeof(PktHeader);
+    boolean_T error     = EXT_NO_ERROR;
+    
+    /* Get the header. */
+    while(nGotTotal < pktSize) {
+        error = ExtGetHostPkt(extUD,
+            pktSize - nGotTotal, &nGot, (char_T *)((char_T *)pktHdr + nGotTotal));
+        if (error) goto EXIT_POINT;
+
+       nGotTotal += nGot;
+
+        if (nGotTotal == 0) break;
+    }
+    assert((nGot == 0) || (nGotTotal == pktSize));
+
+EXIT_POINT:
+    *hdrAvail = (boolean_T)(nGot > 0);
+    return(error);
+} /* end GetPktHdr */
+
+
+/* Function: ClearPkt ==========================================================
+ * Abstract:
+ *  Remove the data from the communication line one byte at a time.  This
+ *  function is called when there was not enough memory to receive an entire
+ *  packet.  Since the data was never received, it must be discarded so that
+ *  other packets can be sent.
+ */
+PRIVATE void ClearPkt(const int pktSize)
+{
+    int_T     nGot;
+    boolean_T error     = EXT_NO_ERROR;
+    int_T     nGotTotal = 0;
+    static    char buffer;
+
+    /* Get and discard the data one char at a time. */
+    while(nGotTotal < pktSize) {
+        error = ExtGetHostPkt(extUD, 1, &nGot, (char_T *)&buffer);
+        if (error) {
+#ifndef EXTMODE_DISABLEPRINTF            
+           fprintf(stderr,"ExtGetHostPkt() failed.\n");
+#endif
+            goto EXIT_POINT;
+       }
+
+       nGotTotal += nGot;
+    }
+
+EXIT_POINT:
+    return;
+
+} /* end ClearPkt */
+
+
+/* Function: GetPkt ============================================================
+ * Abstract:
+ *  Receive nBytes from the host.  Return a buffer containing the bytes or
+ *  NULL if an error occurs.  Note that the pointer returned is that of the
+ *  global pktBuf.  If the buf needs to be grown to accommodate the package,
+ *  it is realloc'd.  This function will try to get the requested number
+ *  of bytes indefinitely - it is assumed that the data is either already there,
+ *  or will show up in a "reasonable" amount of time.
+ */
+PRIVATE const char *GetPkt(const int pktSize)
+{
+    int_T     nGot;
+    boolean_T error     = EXT_NO_ERROR;
+    int_T     nGotTotal = 0;
+
+    error = GrowRecvBufIfNeeded(pktSize);
+    if (error != EXT_NO_ERROR) {
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,"Previous pkt from host thrown away due to lack of memory.\n");
+#endif
+        ClearPkt(pktSize);
+        goto EXIT_POINT;
+    }
+    
+    /* Get the data. */
+    while(nGotTotal < pktSize) {
+        error = ExtGetHostPkt(extUD,
+            pktSize - nGotTotal, &nGot, (char_T *)(pktBuf + nGotTotal));
+        if (error) {
+#ifndef EXTMODE_DISABLEPRINTF                
+           fprintf(stderr,"ExtGetHostPkt() failed.\n");
+#endif
+            goto EXIT_POINT;
+       }
+
+       nGotTotal += nGot;
+    }
+
+EXIT_POINT:
+    return((error == EXT_NO_ERROR) ? pktBuf : NULL);
+} /* end GetPkt */
+
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Forward declaration */
+void UploadServerWork(int32_T, int_T numSampTimes);
+#endif
+
+/* Function: DisconnectFromHost ================================================
+ * Abstract:
+ *  Disconnect from the host.
+ */
+PRIVATE void DisconnectFromHost(int_T numSampTimes)
+{
+    int i;
+
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadPrepareForFinalFlush(i);
+
+#if defined(VXWORKS)
+        /*
+         * UploadPrepareForFinalFlush() has already called semGive(uploadSem)
+         * two times.  Now the server thread will wait until the upload thread
+         * has processed all of the data in the buffers for the final upload
+         * and exhausted the uploadSem semaphores.  If the server thread
+         * attempts to call UploadServerWork() while the upload thread is in
+         * the middle of processing the buffers, the target code may crash
+         * with a NULL pointer exception (the buffers are destroyed after
+         * calling UploadLogInfoTerm).
+         */
+        while(semTake(uploadSem, NO_WAIT) != ERROR) {
+            semGive(uploadSem);
+            taskDelay(1000);
+        }
+#else
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+        if (host_upstatus_is_uploading) {
+            UploadServerWork(i, numSampTimes);
+        }
+#endif
+#endif
+
+        UploadLogInfoTerm(i, numSampTimes);
+    }
+    
+    connected       = FALSE;
+    commInitialized = FALSE;
+    
+    ExtCloseConnection(extUD);
+} /* end DisconnectFromHost */
+
+
+/* Function: ForceDisconnectFromHost ===========================================
+ * Abstract:
+ *  Force a disconnect from the host.  This is not a graceful shutdown and
+ *  should only be used when the integrity of the external mode connection
+ *  is in question.  To shutdown the connection gracefully, use
+ *  DisconnectFromHost().
+ */
+PRIVATE void ForceDisconnectFromHost(int_T numSampTimes)
+{
+    int i;
+    connected       = FALSE;
+    commInitialized = FALSE;
+
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadEndLoggingSession(i, numSampTimes);
+    }
+
+    ExtForceDisconnect(extUD);
+} /* end ForceDisconnectFromHost */
+
+
+/* Function: ProcessConnectPkt =================================================
+ * Abstract:
+ *  Process the EXT_CONNECT packet and send response to host.
+ */
+PRIVATE boolean_T ProcessConnectPkt(RTWExtModeInfo *ei)
+{
+    int_T                   nSet;
+    PktHeader               pktHdr;
+    int_T                   tmpBufSize;
+    uint32_T                *tmpBuf = NULL;
+    boolean_T               error   = EXT_NO_ERROR;
+    
+    const DataTypeTransInfo *dtInfo    = rteiGetModelMappingInfo(ei);
+    uint_T                  *dtSizes   = dtGetDataTypeSizes(dtInfo);
+    int_T                   nDataTypes = dtGetNumDataTypes(dtInfo);
+
+    assert(connected);
+    assert(!comminitialized);
+
+    /*
+     * Send the 1st of two EXT_CONNECT_RESPONSE packets to the host. 
+     * The packet consists purely of the pktHeader.  In this special
+     * case the pktSize actually contains the number of bits per byte
+     * (not always 8 - see TI compiler for C30 and C40).
+     */
+    pktHdr.type = (uint32_T)EXT_CONNECT_RESPONSE;
+    pktHdr.size = (uint32_T)8; /* 8 bits per byte */
+
+    error = ExtSetHostPkt(extUD,sizeof(pktHdr),(char_T *)&pktHdr,&nSet);
+    if (error || (nSet != sizeof(pktHdr))) {
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,
+            "ExtSetHostPkt() failed for 1st EXT_CONNECT_RESPONSE.\n");
+#endif
+        goto EXIT_POINT;
+    }
+
+    /* Send 2nd EXT_CONNECT_RESPONSE packet containing the following 
+     * fields:
+     *
+     * CS1 - checksum 1 (uint32_T)
+     * CS2 - checksum 2 (uint32_T)
+     * CS3 - checksum 3 (uint32_T)
+     * CS4 - checksum 4 (uint32_T)
+     *
+     * intCodeOnly   - flag indicating if target is integer only (uint32_T)
+     * 
+     * MWChunkSize   - multiword data type chunk size on target (uint32_T)
+     * 
+     * targetStatus  - the status of the target (uint32_T)
+     *
+     * nDataTypes    - # of data types        (uint32_T)
+     * dataTypeSizes - 1 per nDataTypes       (uint32_T[])
+     */
+
+    {
+        int nPktEls    = 4 +                        /* checkSums       */
+                         1 +                        /* intCodeOnly     */
+                         1 +                        /* MW chunk size   */
+                         1 +                        /* targetStatus    */
+                         1 +                        /* nDataTypes      */
+                         dtGetNumDataTypes(dtInfo); /* data type sizes */
+
+        tmpBufSize = nPktEls * sizeof(uint32_T);
+        tmpBuf     = (uint32_T *)malloc(tmpBufSize);
+        if (tmpBuf == NULL) {
+            error = EXT_ERROR; goto EXIT_POINT;
+        }
+    }
+    
+    /* Send packet header. */
+    pktHdr.type = EXT_CONNECT_RESPONSE;
+    pktHdr.size = tmpBufSize;
+
+    error = ExtSetHostPkt(extUD,sizeof(pktHdr),(char_T *)&pktHdr,&nSet);
+    if (error || (nSet != sizeof(pktHdr))) {
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,
+            "ExtSetHostPkt() failed for 2nd EXT_CONNECT_RESPONSE.\n");
+#endif
+        goto EXIT_POINT;
+    }
+   
+    /* Checksums, target status & SL_DOUBLESize. */
+    tmpBuf[0] = rteiGetChecksum0(ei);
+    tmpBuf[1] = rteiGetChecksum1(ei);
+    tmpBuf[2] = rteiGetChecksum2(ei);
+    tmpBuf[3] = rteiGetChecksum3(ei);
+
+#if INTEGER_CODE == 0
+    tmpBuf[4] = (uint32_T)0;
+#else
+    tmpBuf[4] = (uint32_T)1;
+#endif
+
+    tmpBuf[5] = (uint32_T)sizeof(uchunk_T);
+    
+    tmpBuf[6] = (uint32_T)modelStatus;
+
+    /* nDataTypes and dataTypeSizes */
+    {        
+        int i;
+        tmpBuf[7] = (uint32_T)nDataTypes;
+        for (i=0; i<nDataTypes; i++) {
+            tmpBuf[8+i] = (uint32_T)dtSizes[i];
+        }
+    }
+    
+    /* Send the packet. */
+    error = ExtSetHostPkt(extUD,tmpBufSize,(char_T *)tmpBuf,&nSet);
+    if (error || (nSet != tmpBufSize)) {
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,
+            "ExtSetHostPkt() failed.\n");
+#endif
+        goto EXIT_POINT;
+    }
+
+    commInitialized = TRUE;
+
+EXIT_POINT:
+    free(tmpBuf);
+    return(error);
+} /* end ProcessConnectPkt */
+
+
+/* Function: SendPktHdrToHost ==================================================
+ * Abstract:
+ *  Send a packet header to the host.
+ */
+PRIVATE boolean_T SendPktHdrToHost(
+    const ExtModeAction action,
+    const int           size)  /* # of bytes to follow pkt header */
+{
+    int_T     nSet;
+    PktHeader pktHdr;
+    boolean_T error = EXT_NO_ERROR;
+
+    pktHdr.type = (uint32_T)action;
+    pktHdr.size = size;
+
+    error = ExtSetHostPkt(extUD,sizeof(pktHdr),(char_T *)&pktHdr,&nSet);
+    if (error || (nSet != sizeof(pktHdr))) {
+        error = EXT_ERROR;
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,"ExtSetHostPkt() failed.\n");
+#endif
+        goto EXIT_POINT;
+    }
+
+EXIT_POINT:
+    return(error);
+} /* end SendPktHdrToHost */
+
+
+/* Function: SendPktDataToHost =================================================
+ * Abstract:
+ *  Send packet data to host. You are responsible for sending a header
+ *  prior to sending the header.
+ */
+PRIVATE boolean_T SendPktDataToHost(const char *data, const int size)
+{
+    int_T     nSet;
+    boolean_T error = EXT_NO_ERROR;
+
+    error = ExtSetHostPkt(extUD,size,data,&nSet);
+    if (error || (nSet != size)) {
+        error = EXT_ERROR;
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,"ExtSetHostPkt() failed.\n");
+#endif
+        goto EXIT_POINT;
+    }
+
+EXIT_POINT:
+    return(error);
+} /* end SendPktDataToHost */
+
+
+/* Function: SendPktToHost =====================================================
+ * Abstract:
+ *  Send a packet to the host.  Packets can be of two forms:
+ *      o packet header only
+ *          the type is used as a flag to notify Simulink of an event
+ *          that has taken place on the target (event == action == type)
+ *      o pkt header, followed by data
+ */
+PUBLIC boolean_T SendPktToHost(
+    const ExtModeAction action,
+    const int           size,  /* # of bytes to follow pkt header */
+    const char          *data)
+{
+    boolean_T error = EXT_NO_ERROR;
+    
+#ifdef VXWORKS
+    semTake(pktSem, WAIT_FOREVER);
+#endif
+
+    error = SendPktHdrToHost(action,size);
+    if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+    if (data != NULL) {
+        error = SendPktDataToHost(data, size);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+    } else {
+        assert(size == 0);
+    }
+
+EXIT_POINT:
+#ifdef VXWORKS
+    semGive(pktSem);
+#endif
+    return(error);
+} /* end SendPktToHost */
+
+
+/* Function:  SendResponseStatus ===============================================
+ *  
+ */
+PRIVATE boolean_T SendResponseStatus(const ExtModeAction  response,
+                                     const ResponseStatus status,
+                                     int32_T upInfoIdx)
+{
+    int32_T   msg[2];
+    boolean_T error = EXT_NO_ERROR;
+
+    msg[0] = (int32_T)status;
+    msg[1] = upInfoIdx;
+
+    error = SendPktToHost(response,2*sizeof(int32_T),(char_T *)&msg);
+    return(error);
+
+} /* end SendResponseStatus */
+
+
+#ifndef EXTMODE_DISABLEPARAMETERTUNING
+/* Function: ProcessSetParamPkt ================================================
+ * Receive and process the EXT_SETPARAM packet.
+ */
+PRIVATE boolean_T ProcessSetParamPkt(RTWExtModeInfo *ei,
+                                     const int pktSize)
+{
+    int32_T    msg;
+    const char *pkt;
+    boolean_T  error = EXT_NO_ERROR;
+
+    /*
+     * Receive packet and set parameters.
+     */
+    pkt = GetPkt(pktSize);
+    if (pkt == NULL) {
+        msg = (int32_T)NOT_ENOUGH_MEMORY;
+        SendPktToHost(EXT_SETPARAM_RESPONSE,sizeof(int32_T),(char_T *)&msg);
+        error = EXT_ERROR;
+        goto EXIT_POINT;
+    }
+    SetParam(ei, pkt);
+
+    msg = (int32_T)STATUS_OK;
+    error = SendPktToHost(EXT_SETPARAM_RESPONSE,sizeof(int32_T),(char_T *)&msg);
+    if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+EXIT_POINT:
+    return(error);
+} /* end ProcessSetParamPkt */
+#endif /* ifndef EXTMODE_DISABLEPARAMETERTUNING */
+
+#ifndef EXTMODE_DISABLEPARAMETERTUNING 
+/* Function: ProcessGetParamsPkt ===============================================
+ *  Respond to the hosts request for the parameters by gathering up all the
+ *  params and sending them to the host.
+ */
+PRIVATE boolean_T ProcessGetParamsPkt(RTWExtModeInfo *ei)
+{
+    int_T                         i;
+    int_T                         nBytesTotal;
+    boolean_T                     error    = EXT_NO_ERROR;
+    const DataTypeTransInfo       *dtInfo  = rteiGetModelMappingInfo(ei);
+    const DataTypeTransitionTable *dtTable = dtGetParamDataTypeTrans(dtInfo);
+
+    if (dtTable != NULL) {
+        /*
+         * We've got some params in the model.  Send their values to the
+         * host.
+         */
+        int_T        nTrans   = dtGetNumTransitions(dtTable);
+        const uint_T *dtSizes = dtGetDataTypeSizes(dtInfo);
+
+ #ifdef VERBOSE
+    #ifndef EXTMODE_DISABLEPRINTF             
+        printf("\nUploading initial parameters....\n");
+ #endif
+#endif 
+
+        /*
+         * Take pass 1 through the transitions to figure out how many
+         * bytes we're going to send.
+         */
+        nBytesTotal = 0;
+        for (i=0; i<nTrans; i++) {
+            int_T dt     = dtTransGetDataType(dtTable, i);
+            int_T dtSize = dtSizes[dt];
+            int_T nEls   = dtTransNEls(dtTable, i); /* complexity accounted for in trans tbl num of els */
+            int_T nBytes = dtSize * nEls;
+
+            nBytesTotal += nBytes;
+        }
+
+        /*
+         * Send the packet header.
+         */
+        error = SendPktHdrToHost(EXT_GETPARAMS_RESPONSE,nBytesTotal);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+        /*
+         * Take pass 2 through the transitions and send the parameters.
+         */
+        for (i=0; i<nTrans; i++) {
+            char_T *tranAddress  = dtTransGetAddress(dtTable, i);
+            int_T  dt            = dtTransGetDataType(dtTable, i);
+            int_T  dtSize        = dtSizes[dt];
+            int_T  nEls          = dtTransNEls(dtTable, i); /* complexity accounted for in trans tbl num of els */
+            int_T  nBytes        = dtSize * nEls;
+
+            error = SendPktDataToHost(tranAddress, nBytes);
+            if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        }
+    } else {
+        /*
+         * We've got no params in the model.
+         */
+        error = SendPktHdrToHost(EXT_GETPARAMS_RESPONSE,0);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+    }
+
+EXIT_POINT:
+    return(error);
+} /* end ProcessGetParamsPkt */
+#endif /* ifndef EXTMODE_DISABLEPARAMETERTUNING */
+
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Function: ProcessSelectTriggerSignalPkt ===========================================
+ * Receive and process the EXT_SELECT_TRIGGER or EXT_SELECT_SIGNALS packet.
+ */
+PRIVATE boolean_T ProcessSelectTriggerSignalPkt(const ExtModeAction ACTION_ID, 
+                                                RTWExtModeInfo *ei,
+                                                const int pktSize,
+                                                int_T numSampTimes,
+                                                char* errMsg)
+{
+    const char *pkt;
+    int32_T    upInfoIdx;
+    boolean_T  error = EXT_NO_ERROR;
+
+    pkt = GetPkt(pktSize);
+    if (pkt == NULL) {
+        SendResponseStatus(ACTION_ID, NOT_ENOUGH_MEMORY, -1);
+        return(EXT_ERROR);
+    }
+
+    (void)memcpy(&upInfoIdx, pkt, sizeof(int32_T)); /* Extract upInfoIdx */
+    switch(ACTION_ID) {
+    case EXT_SELECT_TRIGGER_RESPONSE:
+#ifndef EXTMODE_DISABLEPRINTF  
+        PRINT_VERBOSE(
+                    ("got EXT_SELECT_TRIGGER packet for upInfoIdx : %d\n", upInfoIdx));
+#endif
+        error = UploadInitTrigger(ei, pkt+sizeof(int32_T), upInfoIdx);
+        break;
+    case EXT_SELECT_SIGNALS_RESPONSE:
+#ifndef EXTMODE_DISABLEPRINTF  
+        PRINT_VERBOSE(
+                    ("got EXT_SELECT_SIGNALS packet for upInfoIdx : %d\n", upInfoIdx));
+#endif
+        error = UploadLogInfoInit(ei, numSampTimes, pkt+sizeof(int32_T), upInfoIdx);
+        break;
+    default:
+        break;
+    }
+
+    if (error != EXT_NO_ERROR) {
+        SendResponseStatus(ACTION_ID, NOT_ENOUGH_MEMORY, upInfoIdx);
+#ifndef EXTMODE_DISABLEPRINTF            
+        printf("%s\n", errMsg);
+#endif
+        return(error);
+    }
+
+    error = SendResponseStatus(ACTION_ID, STATUS_OK, upInfoIdx);
+    return(error); /* Can be EXT_NO_ERROR */
+} /* end ProcessSelectTriggerSignalPkt */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Function: ProcessCancelLoggingArmTriggerPkt ===========================================
+ * Receive and process the EXT_CANCEL_LOGGING or EXT_ARM_TRIGGER packet.
+ */
+PRIVATE boolean_T ProcessCancelLoggingArmTriggerPkt(const ExtModeAction ACTION_ID, 
+                                               const int pktSize, 
+                                               int_T numSampTimes)
+{
+    const char *pkt;
+    int32_T    upInfoIdx;
+    boolean_T  error = EXT_NO_ERROR;
+
+    pkt = GetPkt(pktSize);
+    if (pkt == NULL) {
+        SendResponseStatus(ACTION_ID, NOT_ENOUGH_MEMORY, -1);
+        return(EXT_ERROR);
+    }
+            
+    (void)memcpy(&upInfoIdx, pkt, sizeof(int32_T)); /* Extract upInfoIdx */
+        
+    switch(ACTION_ID) {
+    case EXT_CANCEL_LOGGING_RESPONSE:
+#ifndef EXTMODE_DISABLEPRINTF   
+        PRINT_VERBOSE(
+                ("got EXT_CANCEL_LOGGING packet for upInfoIdx : %d\n", upInfoIdx));
+#endif
+        UploadCancelLogging(upInfoIdx);
+        break;
+    case EXT_ARM_TRIGGER_RESPONSE:
+#ifndef EXTMODE_DISABLEPRINTF
+        PRINT_VERBOSE(
+                ("got EXT_ARM_TRIGGER packet for upInfoIdx : %d\n", upInfoIdx));
+#endif
+        UploadArmTrigger(upInfoIdx, numSampTimes);
+        break;
+    default:
+        break;
+    }
+
+    error = SendResponseStatus(ACTION_ID, STATUS_OK, upInfoIdx);
+    return(error); /* Can be EXT_NO_ERROR */
+} /* end ProcessCancelLoggingArmTriggerPkt */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+
+
+#ifdef EXTMODE_DISABLEPARAMETERTUNING
+PRIVATE boolean_T AcknowledgeSetParamPkt(const int pktSize)
+{
+    int32_T    msg;
+    const char *pkt;
+    boolean_T  error = EXT_NO_ERROR;
+
+    pkt = GetPkt(pktSize);
+    msg = (int32_T)STATUS_OK;
+    error = SendPktToHost(EXT_SETPARAM_RESPONSE, sizeof(int32_T), (char_T *)&msg);
+    return(error);
+}
+#endif /* ifdef EXTMODE_DISABLEPARAMETERTUNING */
+
+#ifdef EXTMODE_DISABLESIGNALMONITORING
+PRIVATE boolean_T AcknowledgeSignalActionPkt(const int pktSize, const ExtModeAction ACTION_ID)
+{
+    const char *pkt;
+    int32_T    upInfoIdx;
+    boolean_T  error = EXT_NO_ERROR;
+
+    pkt = GetPkt(pktSize);
+    (void)memcpy(&upInfoIdx, pkt, sizeof(int32_T));
+    error = SendResponseStatus(ACTION_ID, STATUS_OK, upInfoIdx);
+    return(error);
+} 
+#endif /* ifdef EXTMODE_DISABLESIGNALMONITORING */
+
+/*********************
+ * Visible Functions *
+ *********************/
+
+
+/* Function: ExtParseArgsAndInitUD =============================================
+ * Abstract:
+ *  Pass remaining arguments (main program should have NULL'ed out any args
+ *  that it processed) to external mode.
+ *  
+ *  The actual, transport-specific parsing routine (implemented in
+ *  ext_svr_transport.c) MUST NULL out all entries of argv that it processes.
+ *  The main program depends on this in order to determine if any unhandled
+ *  command line options were specified (i.e., if the main program detects
+ *  any non-null fields after the parse, it throws an error).
+ *
+ *  Returns an error string on failure, NULL on success.
+ *
+ * NOTES:
+ *  The external mode UserData is created here so that the specified command-
+ *  line options can be stored.
+ */
+PUBLIC const char_T *ExtParseArgsAndInitUD(const int_T  argc,
+                                           const char_T *argv[])
+{
+    const char_T *error = NULL;
+    
+    /*
+     * Create the user data.
+     */
+    extUD = ExtUserDataCreate();
+    if (extUD == NULL) {
+        error = "Could not create external mode user data.  Out of memory.\n";
+        goto EXIT_POINT;
+    }
+
+    /*
+     * Parse the transport-specific args.
+     */
+    error = ExtProcessArgs(extUD,argc,argv);
+    if (error != NULL) goto EXIT_POINT;
+        
+EXIT_POINT:
+    if (error != NULL) {
+        ExtUserDataDestroy(extUD);
+        extUD = NULL;
+    }
+    return(error);
+} /* end ExtParseArgsAndInitUD */
+
+
+/* Function: ExtWaitForStartPkt ================================================
+ * Abstract:
+ *  Return true if waiting for host to tell us when to start.
+ */
+PUBLIC boolean_T ExtWaitForStartPkt(void)
+{
+    return(ExtWaitForStartPktFromHost(extUD));
+} /* end ExtWaitForStartPkt */
+
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Function: UploadServerWork =================================================
+ * Abstract:
+ *  Upload model signals to host for a single upInfo.
+ */
+void UploadServerWork(int32_T upInfoIdx, int_T numSampTimes)
+{
+    int_T         i;
+    ExtBufMemList upList;
+    boolean_T     error = EXT_NO_ERROR;
+
+#ifdef VXWORKS
+    /*
+     * Don't spin the CPU unless we've got data to upload.
+     * The upload.c/UploadBufAddTimePoint function gives the sem
+     * each time that data is added.
+     */
+taskUnsafe();
+    semTake(uploadSem, WAIT_FOREVER);
+taskSafe();
+#endif
+
+    if (!connected) goto EXIT_POINT;
+    
+    UploadBufGetData(&upList, upInfoIdx, numSampTimes);
+    while(upList.nActiveBufs > 0) {
+        for (i=0; i<upList.nActiveBufs; i++) {
+            const BufMem *bufMem = &upList.bufs[i];
+
+            /*
+             * We call SendPktDataToHost() instead of SendPktToHost() because
+             * the packet header is combined with packet payload.  We do this
+             * to avoid the overhead of making two calls for each upload
+             * packet - one for the head and one for the payload.
+             */
+            error = SendPktDataToHost(
+                bufMem->section1,
+                bufMem->nBytes1);
+            if (error != EXT_NO_ERROR) {
+#ifndef EXTMODE_DISABLEPRINTF                    
+                fprintf(stderr,"SendPktDataToHost() failed on data upload.\n");
+#endif
+                goto EXIT_POINT;
+            }
+            
+            if (bufMem->nBytes2 > 0) {
+
+                error = SendPktDataToHost(
+                    bufMem->section2,
+                    bufMem->nBytes2);
+                if (error != EXT_NO_ERROR) {
+#ifndef EXTMODE_DISABLEPRINTF                        
+                    fprintf(stderr,"SendPktDataToHost() failed on data upload.\n");
+#endif
+                    goto EXIT_POINT;
+                }
+            }
+            /* confirm that the data was sent */
+            UploadBufDataSent(upList.tids[i], upInfoIdx);
+        }
+        UploadBufGetData(&upList, upInfoIdx, numSampTimes);
+    }
+    
+EXIT_POINT:
+    if (error != EXT_NO_ERROR) {
+        /* An error in this function is caused by a physical failure in the
+         * external mode connection.  We assume this failure caused the host
+         * to disconnect.  The target must be disconnected and returned to a
+         * state where it is running and can be re-connected to by the host.
+         */
+        ForceDisconnectFromHost(numSampTimes);
+    }
+}
+/* end UploadServerWork */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Function: rt_UploadServerWork ===============================================
+ * Abstract:
+ *  Wrapper function that calls UploadServerWork once for each upInfo
+ */
+PUBLIC void rt_UploadServerWork(int_T numSampTimes)
+{
+    int i;
+    
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadServerWork(i, numSampTimes);
+    }
+} /* end rt_UploadServerWork */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+
+/* Function: rt_ExtModeInit ====================================================
+ * Abstract:
+ *  Called once at program startup to do any initialization related to external
+ *  mode. 
+ */
+PUBLIC boolean_T rt_ExtModeInit(void)
+{
+    int i;
+    boolean_T error = EXT_NO_ERROR;
+
+#ifdef TMW_EXTMODE_TESTING_REQ
+#  ifndef TMW_EXTMODE_TESTING
+#ifndef EXTMODE_DISABLEPRINTF 
+    fprintf(stderr,"Error: External mode tests should use the external mode test harness.\n");
+#endif
+    error = EXT_ERROR;
+#  endif
+#endif
+    if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+    error = ExtInit(extUD);
+    if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadLogInfoReset(i);
+    }
+
+    rtExtModeTestingInit();
+
+EXIT_POINT:
+    return(error);
+} /* end rt_ExtModeInit */
+
+
+/* Function: rt_ExtModeSleep ===================================================
+ * Abstract:
+ *  Called by grt_main, ert_main, and grt_malloc_main  to "pause".  It attempts
+ *  to do this in a way that does not hog the processor.
+ */
+#ifndef VXWORKS
+PUBLIC void rt_ExtModeSleep(
+    long sec,  /* number of seconds to wait       */
+    long usec) /* number of micro seconds to wait */
+{
+    ExtModeSleep(extUD,sec,usec);
+} /* end rt_ExtModeSleep */
+#endif
+
+
+/* Function: rt_PktServerWork ==================================================
+ * Abstract:
+ *  If not connected, establish communication of the packet line and the
+ *  data upload line.  If connected, send/receive packets and parameters
+ *  on the packet line.
+ */
+PUBLIC void rt_PktServerWork(RTWExtModeInfo *ei,
+                             int_T          numSampTimes,
+                             boolean_T      *stopReq)
+{
+    PktHeader  pktHdr;
+    boolean_T  hdrAvail;
+    boolean_T  error             = EXT_NO_ERROR;
+    boolean_T  disconnectOnError = FALSE;
+    
+    /*
+     * If not connected, attempt to make connection to host.
+     */
+    if (!connected) {
+        rtExtModeTestingKillIfOrphaned(FALSE);
+
+        error = ExtOpenConnection(extUD,&connected);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+    }
+
+    /*
+     * If ExtOpenConnection is not blocking and there are no pending
+     * requests to open a connection, we'll still be unconnected.
+     */
+    if (!connected) goto EXIT_POINT; /* nothing to do */
+    
+    /*
+     * Process packets.
+     */
+
+    /* Wait for a packet. */
+    error = GetPktHdr(&pktHdr, &hdrAvail);
+    if (error != EXT_NO_ERROR) {
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr, "\nError occurred getting packet header.\n");
+#endif
+        disconnectOnError = TRUE;
+        goto EXIT_POINT;
+    }
+    rtExtModeTestingKillIfOrphaned(hdrAvail);
+    
+    if (!hdrAvail) goto EXIT_POINT; /* nothing to do */
+
+    /*
+     * This is the first packet.  Should contain the string:
+     * 'ext-mode'.  Its contents are not important to us.
+     * It is used as a flag to start the handshaking process.
+     */
+    if (!commInitialized) {
+        pktHdr.type = EXT_CONNECT;
+    }
+
+    /* 
+     * At this point we know that we have a packet: process it.
+     */
+#ifdef VXWORKS
+    taskSafe();
+#endif
+    switch(pktHdr.type) {
+
+    case EXT_GET_TIME:
+    {
+        /* Skip verbosity print out - we get too many of these */
+        PRINT_VERBOSE(("got EXT_GET_TIME packet.\n"));
+        time_T t = rteiGetT(ei);
+        
+        error = SendPktToHost(
+            EXT_GET_TIME_RESPONSE,sizeof(time_T),
+            (char_T *)&t);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        break;
+    }
+
+    case EXT_ARM_TRIGGER:
+    {
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+        error = ProcessCancelLoggingArmTriggerPkt(EXT_ARM_TRIGGER_RESPONSE, pktHdr.size, numSampTimes);
+       if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#else
+        error = AcknowledgeSignalActionPkt(pktHdr.size, EXT_ARM_TRIGGER_RESPONSE);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    case EXT_SELECT_SIGNALS:
+    {
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+        error = ProcessSelectTriggerSignalPkt(EXT_SELECT_SIGNALS_RESPONSE, ei, pktHdr.size, numSampTimes, ERRMSG_PROCESSSELECTSIGNAL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#else
+        error = AcknowledgeSignalActionPkt(pktHdr.size, EXT_SELECT_SIGNALS_RESPONSE);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    case EXT_SELECT_TRIGGER: 
+    {
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+        error = ProcessSelectTriggerSignalPkt(EXT_SELECT_TRIGGER_RESPONSE, ei, pktHdr.size, -1, ERRMSG_PROCESSSELECTTRIGGER);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#else
+        error = AcknowledgeSignalActionPkt(pktHdr.size, EXT_SELECT_TRIGGER_RESPONSE);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    case EXT_CONNECT:
+    {
+        PRINT_VERBOSE(("got EXT_CONNECT packet.\n"));
+        error = ProcessConnectPkt(ei);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        break;
+    }
+
+    case EXT_SETPARAM:
+    {
+#ifndef EXTMODE_DISABLEPARAMETERTUNING
+        PRINT_VERBOSE(("got EXT_SETPARAM packet.\n"));
+        error = ProcessSetParamPkt(ei, pktHdr.size);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#else
+        PRINT_VERBOSE(("discard EXT_SETPARAM packet.\n"));
+        error = AcknowledgeSetParamPkt(pktHdr.size);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    case EXT_GETPARAMS:
+    {
+#ifndef EXTMODE_DISABLEPARAMETERTUNING
+        PRINT_VERBOSE(("got EXT_GETPARAMS packet.\n"));
+        error = ProcessGetParamsPkt(ei);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    case EXT_DISCONNECT_REQUEST:
+    {
+        PRINT_VERBOSE(("got EXT_DISCONNECT_REQUEST packet.\n"));
+        
+        /*
+         * Note that from the target's point of view this is
+         * more a "notify" than a "request".  The host needs to
+         * have this acknowledged before it can begin closing
+         * the connection.
+         */
+        error = SendPktToHost(EXT_DISCONNECT_REQUEST_RESPONSE, 0, NULL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+
+        DisconnectFromHost(numSampTimes);
+
+        break;
+    }
+
+    case EXT_DISCONNECT_REQUEST_NO_FINAL_UPLOAD:
+    {
+        PRINT_VERBOSE(("got EXT_DISCONNECT_REQUEST_NO_FINAL_UPLOAD packet.\n"));
+        
+        /*
+         * The target receives this packet when the host is
+         * immediately terminating the extmode communication due
+         * to some error.  The target should not send back a
+         * response or a final upload of data because the host is
+         * expecting neither.  The target must be disconnected and
+         * returned to a state where it is running and can be
+         * re-connected to by the host.
+         */
+        ForceDisconnectFromHost(numSampTimes);
+
+        break;
+    }
+
+    case EXT_MODEL_START:
+        PRINT_VERBOSE(("got EXT_MODEL_START packet.\n"));
+#ifdef VXWORKS
+        {
+            extern SEM_ID startStopSem;
+            semGive(startStopSem);
+        }
+#endif
+        startModel = TRUE;
+        error = SendPktToHost(EXT_MODEL_START_RESPONSE, 0, NULL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        break;
+
+    case EXT_MODEL_STOP:
+        PRINT_VERBOSE(("got EXT_MODEL_STOP packet.\n"));
+        *stopReq = TRUE;
+        break;
+#ifndef EXTMODE_DISABLETESTING
+    case EXT_MODEL_PAUSE:
+        PRINT_VERBOSE(("got EXT_MODEL_PAUSE packet.\n"));
+        modelStatus = TARGET_STATUS_PAUSED;
+        startModel  = FALSE;
+
+        error = SendPktToHost(EXT_MODEL_PAUSE_RESPONSE, 0, NULL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        break;
+    case EXT_MODEL_STEP:
+        PRINT_VERBOSE(("got EXT_MODEL_STEP packet.\n"));
+        if ((modelStatus == TARGET_STATUS_PAUSED) && !startModel) {
+            startModel = TRUE;
+        }
+        
+        error = SendPktToHost(EXT_MODEL_STEP_RESPONSE, 0, NULL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+        break;
+    case EXT_MODEL_CONTINUE:
+        PRINT_VERBOSE(("got EXT_MODEL_CONTINUE packet.\n"));
+        if (modelStatus == TARGET_STATUS_PAUSED) {
+            modelStatus = TARGET_STATUS_RUNNING;
+            startModel  = FALSE;
+        }
+        
+        error = SendPktToHost(EXT_MODEL_CONTINUE_RESPONSE, 0, NULL);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+
+    case EXT_CANCEL_LOGGING:
+    {
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+        error = ProcessCancelLoggingArmTriggerPkt(EXT_CANCEL_LOGGING_RESPONSE, pktHdr.size, numSampTimes);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#else
+        error = AcknowledgeSignalActionPkt(pktHdr.size, EXT_CANCEL_LOGGING_RESPONSE);
+        if (error != EXT_NO_ERROR) goto EXIT_POINT;
+#endif
+        break;
+    }
+
+    default:
+#ifndef EXTMODE_DISABLEPRINTF            
+        fprintf(stderr,"received invalid packet.\n");
+#endif
+        break;
+    } /* end switch */
+
+EXIT_POINT:
+    if (error != EXT_NO_ERROR) {
+        if (disconnectOnError) {
+#ifndef EXTMODE_DISABLEPRINTF                
+            fprintf(stderr,
+                "Error occurred in rt_PktServerWork.\n"
+                "Disconnecting from host!\n");
+#endif
+            /* An error in this function which causes disconnectOnError to be
+             * set to true is caused by a physical failure in the external mode
+             * connection.  We assume this failure caused the host to disconnect.
+             * The target must be disconnected and returned to a state
+             * where it is running and can be re-connected to by the host.
+             */
+            ForceDisconnectFromHost(numSampTimes);
+        }
+    }
+#ifdef VXWORKS
+    taskUnsafe();
+#endif
+} /* end rt_PktServerWork */
+
+
+/* Function: rt_PktServer ======================================================
+ * Abstract:
+ *  Call rt_PktServerWork forever.   Used only for RTOS (e.g., Tornado/VxWorks
+ *  when running as a low priority task.
+ */
+#ifdef VXWORKS
+PUBLIC void rt_PktServer(RTWExtModeInfo *ei,
+                         int_T          numSampTimes,
+                         boolean_T      *stopReq)
+{
+    for(;;) {
+        rt_PktServerWork(ei,numSampTimes,stopReq); 
+    }
+}
+#endif
+
+
+/* Function: rt_UploadServer ===================================================
+ * Abstract:
+ *  Call rt_UploadServerWork forever.   Used only for RTOS (e.g.,
+ *  Tornado/VxWorks when running as a low priority task.
+ */
+#ifdef VXWORKS
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+PUBLIC void rt_UploadServer(int_T numSampTimes)
+{
+    for(;;) {
+        rt_UploadServerWork(numSampTimes);
+    }
+} /* end rt_UploadServer */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+#endif
+
+
+/* Function: rt_SetPortInExtUD =================================================
+ * Abstract:
+ *  Set the port in the external mode user data structure.
+ */
+#ifdef VXWORKS
+PUBLIC void rt_SetPortInExtUD(const int_T port)
+{
+    ExtUserDataSetPort(extUD, port);
+} /* end rt_SetPortInExtUD */
+#endif
+
+/* Function: ExtModeShutdown ==================================================
+ * Abstract:
+ *  Called when target program terminates to enable cleanup of external 
+ *  mode for a given upInfo.
+ */
+PRIVATE void ExtModeShutdown(int32_T upInfoIdx, int_T numSampTimes)
+{
+    /*
+     * Make sure buffers are flushed so that the final points get to
+     * host (this is important for the case of the target reaching tfinal
+     * while data uploading is in progress).
+     */
+    UploadPrepareForFinalFlush(upInfoIdx);
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+    UploadServerWork(upInfoIdx, numSampTimes);
+#endif
+
+    UploadLogInfoTerm(upInfoIdx, numSampTimes);
+
+    if (pktBuf != NULL) {
+        free(pktBuf);
+        pktBuf = NULL;
+    }
+
+} /* end ExtModeShutdown */
+
+/* Function: rt_ExtModeShutdown ================================================
+ * Abstract:
+ *  Called when target program terminates to enable cleanup of external 
+ *  mode.
+ */
+PUBLIC boolean_T rt_ExtModeShutdown(int_T numSampTimes)
+{
+    int i;
+    boolean_T error = EXT_NO_ERROR;
+
+    for (i=0; i<NUM_UPINFOS; i++) {
+        ExtModeShutdown(i, numSampTimes);
+    }
+
+    if (commInitialized) {
+        error = SendPktToHost(EXT_MODEL_SHUTDOWN, 0, NULL);
+        if (error != EXT_NO_ERROR) {
+#ifndef EXTMODE_DISABLEPRINTF                
+            fprintf(stderr,
+                "\nError sending EXT_MODEL_SHUTDOWN packet to host.\n");
+#endif
+        }
+        commInitialized = FALSE;
+    }
+    if (connected) {
+        connected = FALSE;
+        modelStatus = TARGET_STATUS_WAITING_TO_START;        
+    }
+
+    ExtShutDown(extUD);
+    ExtUserDataDestroy(extUD);
+    
+    rtExtModeTestingRemoveBatMarker();
+    
+    return(error);
+} /* end rt_ExtModeShutdown */
+
+#ifndef EXTMODE_DISABLESIGNALMONITORING
+/* Function: rt_UploadCheckTrigger =============================================
+ * Abstract:
+ *  Wrapper function that calls UploadCheckTrigger once for each upInfo
+ */
+PUBLIC void rt_UploadCheckTrigger(int_T numSampTimes)
+{
+    int i;
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadCheckTrigger(i, numSampTimes);
+    }
+} /* end rt_UploadCheckTrigger */
+
+/* Function: rt_UploadCheckEndTrigger ==========================================
+ * Abstract:
+ *  Wrapper function that calls UploadCheckTrigger once for each upInfo
+ */
+PUBLIC void rt_UploadCheckEndTrigger(void)
+{
+    int i;
+    
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadCheckEndTrigger(i);
+    }
+} /* end rt_UploadCheckEndTrigger */
+
+/* Function: rt_UploadBufAddTimePoint ==========================================
+ * Abstract:
+ *  Wrapper function that calls UploadBufAddTimePoint once for each upInfo
+ */
+PUBLIC void rt_UploadBufAddTimePoint(int_T tid, real_T taskTime)
+{
+    int i;
+    
+    for (i=0; i<NUM_UPINFOS; i++) {
+        UploadBufAddTimePoint(tid, taskTime, i);
+    }
+} /* end rt_UploadBufAddTimePoint */
+#endif /* ifndef EXTMODE_DISABLESIGNALMONITORING */
+
+/* [EOF] ext_svr.c */