⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ext_comm.c

📁 simulink real-time workshop for dragon12 development board from
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright 1994-2001 The MathWorks, Inc.
 *
 * File: ext_comm.c     $Revision: 1.26 $
 *
 * Abstract:
 *  Host-side, transport-independent external-mode functions.  Calls to these
 *  functions originate from Simulink and are dispatched through ext_main.c
 *  Functions are included to:
 *      o set (send) messages to the target
 *      o get (receive) messages from the target
 *      o get (receive) upload data (signals) from the target
 *      o open connection with target
 *      o close connection with target
 *      o etc
 *
 *  Transport specific code (e.g., TCPIP code) resides in ext_transport.c.
 *  Modify that file to customize external mode to various transport
 *  mechanisms (e.g., shared memory, serial line, etc).
 */

/*****************
 * Include files *
 *****************/

/*ANSI C headers*/
#include <stdio.h>
#include <string.h>
#include <windows.h>			/* PurgeComm */

/*Real Time Workshop headers*/
#include "tmwtypes.h"
#include "mex.h"
#include "extsim.h"
#include "ext_convert.h"
#include "extutil.h"
#include "ext_transport232.h"
#include "ext_share.h"


/* set verbosity of debugging messages (0, 1, 2, 3 or 4 -> set this to 0 in the release version) */
#define DEBUG_MSG_LVL	0




// ----------------------------------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------------------------------

// maximum number of user data communication channels
#define MAX_UCOM_CHANNELS	10			/* maximum number of user communication channels */
#define MAX_BUF_SIZE		100			/* currently limited to 250 data bytes (FW-12-02) */


// global admin variables of the instance-local communication buffers (dynamically allocated in S-Function 'S0_txd')
typedef struct	myUsrBuf_tag {
					int_T	buffer_full;
					uint_T	access_count;
					uint_T	buf_size;
					uint8_T	*buf;
				} myUsrBuf;

myUsrBuf	*userTelBuf[MAX_UCOM_CHANNELS];		/* pointer to the data buffer admin structures of all user telegrams */
int_T		 user_txd_queue[MAX_UCOM_CHANNELS];	/* queue of txd channels to be scanned by Process_UserDownload() */
int_T		 num_user_channels_active;			/* number of active user data channels to be serviced */	
int_T		 next_user_channel_index;			/* index of the next channel to be scanned for (txd queue) */
int_T		 user_comm_enable = 0;				/* global flag controlling user downloads (Process_UserDownload) */

// counter of unsuccessful data upload attempts
#ifdef MODELSTUCK
uint_T	 NoDataPending;
uint_T	 alarmCounter;
uint_T	 ModelIsRunning;
#endif


/* keep requesting data every 10 idle transmission loops */
static unsigned int noRequestDataCounter = 0;


// ----------------------------------------------------------------------------------------------------
// local methods
// ----------------------------------------------------------------------------------------------------

/* Function: Init_ComVars ===============================================
 * Abstract:
 *  Initialise the communication variables (buffer pointers, buffer flags) --
 *  these variables are defined as globals in 's0_usertel_rxd.c'; run-time addresses 
 *  can be established via the workspace variable BufferAdminVar.
 *  Variable BufferAdminVar is created and initialised in module s0_usertel_rxd,
 */
PRIVATE void Init_ComVars(void) {

	mxArray		*BufferAdminVar;
	uint32_T	*BufPtrArray;
	uint_T		i;


	/* block diagram analysis : find out if there are any user data download blocks */
	{
		mxArray		*TxDc;
		uint_T		n, channel;
		real_T		*myChannels;

		/* analyse 'external' mode block diagram -- ensure that there's only ever one at any one time... */
		mexEvalString("myBlocks = find_system(find_system('SimulationMode','external'), 'LookUnderMasks', 'all');");
		mexEvalString("TxD = [];for(i = 1:length(myBlocks)), TxD = [TxD ~isempty(findstr(myBlocks{i},'RECEIVE_USR_DATA'))]; end, TxD = find(TxD);");
		mexEvalString("TxDc = [];for(i = 1:length(TxD)), TxDc = [TxDc str2num(get_param(get_param(myBlocks{TxD(i)}, 'Parent'), 'channel'))]; end");

		
		/* evaluate variable 'TxDc'  -- this variable controls the download to the target (host-TxD) */
		if((TxDc = mexGetVariable("caller", "TxDc")) == NULL) {

			mexErrMsgTxt("Variable TxDc not found.\n");

		}

		/* found TxDc -> evaluate */
		n			= mxGetN(TxDc);
		myChannels	= mxGetPr(TxDc);

				
		/* preset user_txd_queue (user_txd_queue: list of channels to be scanned for user data download) */
		memset(user_txd_queue, 0, MAX_UCOM_CHANNELS);
				
		/* initialise the txd_queue and set the correct buffer size for every TxD channel that is actually used */
		for(i=0; i<n; i++) {

			channel  = (uint_T)myChannels[i];

			/* store channel in the list of channels to be serviced (user_txd_queue) */
			user_txd_queue[i] = channel;

		}

		/* set number of upload channels to be serviced */
		num_user_channels_active = n;

		/* select index of the first channel to be serviced */
		next_user_channel_index = 0;

		/* remove variables from caller workspace */
		mexEvalString("clear myBlocks TxD TxDc i;");
	
	} /* context {block diagram analysis} */



	/* communicate the addresses of the buffer pointer array as well as the flag array (via the workspace) */
	if((BufferAdminVar = mexGetVariable("base", "BufferAdminVar")) != NULL) {

		/* BufferAdminVar exists -> copy the pointers (even if they are all NULL...) */
		BufPtrArray = (uint32_T *)mxGetPr(BufferAdminVar);
			
		/* set pointers to all TxD buffers and their respective buffer flags */
		for(i=0; i<MAX_UCOM_CHANNELS; i++) {

			/* initialise array of global buffer pointers with the values found in the workspace variable */
			userTelBuf[i]  = (myUsrBuf *)BufPtrArray[i];

			#if DEBUG_MSG_LVL >= 2
			mexPrintf("ext_comm: Initialised communication channel %d.\n", i);
			mexPrintf("ext_comm: Using buffer pointer %ld.\n", userTelBuf[i]);
			#endif

		}

	} /* if(BufferAdminVar...) */

} /* end Init_ComVars */



/* Function: Process_UserDownload ===============================================
 * Abstract:
 *  Find out if a download of user data to the target is pending, initiate download.
 */
PRIVATE void Process_UserDownload(ExternalSim *ES) {


	/* get number of the next channel to be downloaded */
	int_T	req_channel = user_txd_queue[next_user_channel_index++];

	/* reset next_user_channel_index if required */
	if(next_user_channel_index == num_user_channels_active) next_user_channel_index = 0;

	/* check if the contents of the selected buffer have changed */
	if(userTelBuf[req_channel]->buffer_full == 1) {

		/* yes */
		#if DEBUG_MSG_LVL >= 2
		mexPrintf("Process_UserDownload: New data available for channel %d. Initiating download to the target.\n", req_channel);
		#endif


		/* buffer contents have changed -> initiate download */
		{
		    int				nSet;
			MsgHeader		msgHdr;
			int				msgSize;
			boolean_T		error	= EXT_NO_ERROR;
			uint8_T			*buf	= userTelBuf[req_channel]->buf;

			
			/* determine the size of the user data telgram (stored in buf[0]) */
			/* adjust msgSize to ensure the telegram length is a multiple of 4 bytes */
			msgSize = (int)(buf[0] + ((4 - (buf[0] & 0x03)) & 0x03));
				
			#if DEBUG_MSG_LVL >= 2
			{
				int_T		i;

				mexPrintf("Process_UserDownload: Downloading %d bytes on channel %d.\n", msgSize, req_channel);
				mexPrintf("Process_UserDownload: Using data buffer address %ld.\n", (uint32_T)buf);
				mexPrintf("Process_UserDownload: Data  ");

				for(i=0; i<msgSize; i++)
					mexPrintf(" :%d", (uint_T)buf[i]);

				mexPrintf(":\n");
			}
			#endif

	
			/*
			 * Instruct target to receive parameters.
			 */
		    msgHdr.type = (uint32_T)EXT_RECEIVE_USER_DATA;
			msgHdr.size = (uint32_T)(msgSize/esGetHostBytesPerTargetByte(ES));
    
			Copy32BitsToTarget(ES, (char *)&msgHdr, (uint32_T *)&msgHdr, NUM_HDR_ELS);
			if (!esIsErrorClear(ES)) goto EXIT_POINT;

			error = ExtSetTargetMsg(ES,sizeof(msgHdr),(char *)&msgHdr,&nSet);
			if (error || (nSet != sizeof(msgHdr))) {
				esSetError(ES,"ExtSetTargetMsg() call failed for ExtSetUserData() .\n"
								  "Ensure target is still running\n");
				goto EXIT_POINT;
			}

			#if DEBUG_MSG_LVL >= 1
			printf("Process_UserDownload: Message header sent type %d size %d\n", msgHdr.type, msgHdr.size);
			#endif

			/*
			 * Send user data...
			 */
			if (msgSize > 0) {

				/* reverse order of the first 4 data bytes (size, channel, reserved, reserved)  ->  9S12, fw-03-05 */
				{
					char_T  dat;

	                dat    = buf[3];
					buf[3] = buf[0];
					buf[0] = dat;
			        dat    = buf[2];
					buf[2] = buf[1];
					buf[1] = dat;

					#if DEBUG_MSG_LVL >= 1
					mexPrintf("Process_UserDownload: First four bytes re-ordered (9S12)\n");
					#endif

				}

				#if DEBUG_MSG_LVL >= 1
				mexPrintf("Process_UserDownload: Checking data type length: %d\n", buf[1]);
				#endif

				/* reverse order of the remaining data bytes, provided this is of type 'xint8', 'xint16' or 'boolean' ... 9S12, fw-03-05 */
				/* data type byte has just been moved from buf[2] to buf[1], the length byte is now in buf[3] */
				if(buf[1] < 4) {
					
					char_T  dat;
					int_T	i;

					for(i=4; i<msgSize; i+=4) {

						#if DEBUG_MSG_LVL >= 1
						mexPrintf("i = %d/%d\n", i, msgSize);
						#endif

		                dat      = buf[i+3];
						buf[i+3] = buf[i+0];
						buf[i+0] = dat;
		                dat      = buf[i+2];
						buf[i+2] = buf[i+1];
						buf[i+1] = dat;

					}

					#if DEBUG_MSG_LVL >= 1
					mexPrintf("Process_UserDownload: Remaining %d data bytes reordered (9S12, data type length < 4)\n", msgSize-4);
					#endif
				}

				error = ExtSetTargetMsg(ES, msgSize, buf, &nSet);
				if (error || (nSet != msgSize)) {
			
					mexPrintf("Process_UserDownload: Download data (%d bytes) exceeds current buffer size (%d bytes)\n", msgSize, nSet);
					
					{
						DWORD err = GetLastError();
						mexPrintf("Error code: %ld\n", err);
					}
            
					esSetError(ES, "ExtSetTargetMsg() call failed for ExtSetUserData().\n"
								   "Ensure target is still running\n");
					goto EXIT_POINT;
		        }

				#if DEBUG_MSG_LVL >= 1
				mexPrintf("Process_UserDownload: Message data sent (%d bytes)\n", nSet);
				#endif
			
				/* restore order of the remaining data bytes, provided this is of type 'xint8', 'xint16' or 'boolean' ... 9S12, fw-03-05 */
				/* data type byte is still in buf[1], the length byte is still in buf[3] */
				if(buf[1] < 4) {
					
					char_T  dat;
					int_T	i;

					for(i=4; i<msgSize; i+=4) {

		                dat      = buf[i+3];
						buf[i+3] = buf[i+0];
						buf[i+0] = dat;
		                dat      = buf[i+2];
						buf[i+2] = buf[i+1];
						buf[i+1] = dat;

					}

					#if DEBUG_MSG_LVL >= 1
					mexPrintf("Process_UserDownload: Order of %d data bytes restored (9S12, data type length < 4)\n", msgSize-4);
					#endif
				}

				/* restore order of the first 4 data bytes (size, channel, reserved, reserved)  ->  9S12, fw-03-05 */
				{
					char_T  dat;

	                dat    = buf[3];
					buf[3] = buf[0];
					buf[0] = dat;
			        dat    = buf[2];
					buf[2] = buf[1];
					buf[1] = dat;

					#if DEBUG_MSG_LVL >= 1
					mexPrintf("Process_UserDownload: Order of first four bytes restored (9S12)\n");
					#endif

				}
			
			}

		} /* context : ExtSetUserData */

			
		/* clear buffer full flag */
		userTelBuf[req_channel]->buffer_full = 0;
			
		#if DEBUG_MSG_LVL >= 2
		mexPrintf("Process_UserDownload: userTelBuf[%d]->buffer_full = 0\n", req_channel);
		#endif
				
	} /* new data available */

EXIT_POINT:

	return;

} /* end Process_UserDownload */	
									
				
/* Function: RequestDataTelegram ===============================================
 * Abstract:
 *  Trigger upload of one data telegram from the target (sets target flag TXactive)
 */
PRIVATE void RequestDataTelegram(ExternalSim *ES)
{

    UserData  *userData		= (UserData *)esGetUserData(ES);
	MsgHeader msgHdr;
	int_T     nSet;
    boolean_T error			= EXT_NO_ERROR;


	/*
	 * Send the EXT_DATA_UPLD_NOACK_REQUEST msg to the target.  This message triggers
	 * the upload of exactly one data telegram (host driven flow control, FW-10-02)
	 */
				
	#if DEBUG_MSG_LVL >= 2
	mexPrintf("RequestDataTelegram: Requesting upload of a data telegram (EXT_DATA_UPLD_NOACK_REQUEST).\n");
	#endif

	//#if DEBUG_MSG_LVL >= 2
	//mexPrintf("RequestDataTelegram: Pre-transmission delay... (EXT_DATA_UPLD_NOACK_REQUEST).\n");
	//#endif
	//Sleep(10);


	msgHdr.size = 0;
	msgHdr.type = EXT_DATA_UPLD_NOACK_REQUEST;

	Copy32BitsToTarget(ES,(char *)&msgHdr,(uint32_T *)&msgHdr,NUM_HDR_ELS);
	if (!esIsErrorClear(ES)) {
		esSetError(ES, "Copy32BitsToTarget() call failed while requesting new data telegram\n");
		goto EXIT_POINT;
	}

	error = ExtSetTargetMsg(ES,sizeof(msgHdr),(char *)&msgHdr,&nSet);
	if (error || (nSet != sizeof(msgHdr))) {
		esSetError(ES, "ExtSetTargetMsg() call failed on EXT_DATA_UPLD_NOACK_REQUEST.\n");
		mexPrintf("RequestDataTelegram: (no_ack) ExtSetTargetMsg claims to have sent %d bytes\n", nSet);
		goto EXIT_POINT;
	}

	//#if DEBUG_MSG_LVL >= 2
	//mexPrintf("RequestDataTelegram: Post-transmission delay... (EXT_DATA_UPLD_NOACK_REQUEST).\n");
	//#endif
	//Sleep(10);

EXIT_POINT:
	return;

}  /* end RequestDataTelegram */


/* Function: FreeAndNullUserData ===============================================
 * Abstract:
 *  Free user data and null it out in the external sim struct.
 */
PRIVATE void FreeAndNullUserData(ExternalSim *ES)
{
	#if DEBUG_MSG_LVL >= 2
	mexPrintf("FreeAndNullUserData called: IN\n");
	#endif

	ExtUserDataDestroy(esGetUserData(ES));
    esSetUserData(ES, NULL);

	#if DEBUG_MSG_LVL >= 2
	mexPrintf("FreeAndNullUserData called: OUT\n");
	#endif
} /* end FreeAndNullUserData */





// foreward declarations
PRIVATE void ExtConnect(ExternalSim *ES, int_T nrhs, const mxArray *prhs[]);
PRIVATE void ExtDisconnectRequest(ExternalSim *ES, int_T nrhs, const mxArray *prhs[]);


/* Function: ExtRecvIncomingMsg ================================================
 * Abstract:
 *  Check for messages (poll) from target on the 'message port'.  If a message
 *  is pending, set the incoming message pending flag to true and set the
 *  incoming message type.  Otherwise, do nothing.
 */
PRIVATE void ExtRecvIncomingMsg(
    ExternalSim    *ES,
    int_T          nrhs,
    const mxArray  *prhs[])
{
    boolean_T pending;
    char      *bufPtr;
    int       nGot;
    boolean_T error        = EXT_NO_ERROR;
    char      *buf         = esGetIncomingMsgDataBuf(ES);
    int32_T   nBytesNeeded = esGetIncomingMsgDataNBytesNeeded(ES);
    int       nBytes       = esGetIncomingMsgDataNBytesInBuf(ES);
    UserData  *userData	   = (UserData *)esGetUserData(ES);


    (void)nrhs; /* unused */
    (void)prhs; /* unused */

	#if DEBUG_MSG_LVL >= 3
	mexPrintf("\n----------------------\n");
	mexPrintf("ExtRecvIncomingMsg: IN\n");
	#endif

	
	/*
     * Start recv'ing a message.
     */
    if (nBytesNeeded == UNKNOWN_BYTES_NEEDED) {
        assert(nBytes == 0);

		/* carry out download of user telegrams to the target -- if any */
		if(user_comm_enable && num_user_channels_active > 0) {
			
			#if DEBUG_MSG_LVL >= 3
			mexPrintf("ExtRecvIncomingMsg: Calling the Process_UserDownload() service hook...\n", (uint_T)userData->TelType);
			#endif
			Process_UserDownload(ES);

		}


		/*
         *  Check for pending telegrams.
         */
		#if DEBUG_MSG_LVL >= 3
		mexPrintf("ExtRecvIncomingMsg: userData->TelType = %d\n", (uint_T)userData->TelType);
		#endif

		if(userData->TelType == 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -