Click here to Skip to main content
15,886,518 members
Articles / Desktop Programming / Win32

Visual Modeling of Complex Reactive Systems with Harel UML StateCharts

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
8 Sep 2009LGPL310 min read 43.6K   692   35  
This article presents a commercial-grade cross-platform Harel UML StateChart Open-Source application framework named StateWizard for concurrent, distributed, and real-time reactive system development with simplicity, efficiency, and scalability.
/* 
 The external event generator works as a plug-in of the StateWizard engine. Users may customize the external event generator 
 based on the working environment of the user program.
*/

#include "sme_ext_event.h"
#include "sme_cross_platform.h"
#include <memory.h>
#include <stdio.h>


typedef struct tagEXTMSG
{
	SME_EVENT_ID_T nMsgID; // 0: stand for empty entity
	unsigned char nDataFormat ; /* Flag for this event. SME_EVENT_DATA_FORMAT_INT=0, SME_EVENT_DATA_FORMAT_PTR*/
	unsigned char nCategory ; /* Category of this event. */
	union SME_EVENT_DATA_T Data;
	SME_OBJ_T *pDestObj;
	unsigned long nSequenceNum;
	SME_THREAD_CONTEXT_T* pDestThread;
}	X_EXT_MSG_T;


/* Note: Each thread has an independent message pool, an event/condition and a Mutex. 
When a new external event post, set the event/condition signaled.
The Mutex for a thread pool is to synchronize the message pool access between the event sending thread and the receiving thread.

*/
#define MSG_BUF_SIZE  100
typedef struct tagEXTMSGPOOL
{
	int nMsgBufHdr;
	int nMsgBufRear;
	X_EXT_MSG_T MsgBuf[MSG_BUF_SIZE];
	XEVENT EventToThread;
	XMUTEX MutexForPool;
} X_EXT_MSG_POOL_T;

///////////////////////////////////////////////////////////////////////////////////////////
//   nMsgBufHdr  (Get from the head) <============== (Append to the rear) nMsgBufRear
///////////////////////////////////////////////////////////////////////////////////////////
/* Initialize the external event buffer at the current thread. */
BOOL XInitMsgBuf(void)
{
	SME_THREAD_CONTEXT_T* pThreadContext = XGetThreadContext();
	X_EXT_MSG_POOL_T *pMsgPool;
	
	if (NULL!=pThreadContext->pExtEventPool) /* Prevent from creating more than once. */
		return FALSE;

	pThreadContext->pExtEventPool = (void*)malloc(sizeof(X_EXT_MSG_POOL_T));
	pMsgPool =(X_EXT_MSG_POOL_T*)(pThreadContext->pExtEventPool);
	if (NULL==pMsgPool) 
		return FALSE;
	memset(pMsgPool, 0, sizeof(X_EXT_MSG_POOL_T));

	XCreateMutex(&(pMsgPool->MutexForPool));
	XCreateEvent(&(pMsgPool->EventToThread));

	return TRUE;
}

/* Free the external event buffer at the current thread. */
BOOL XFreeMsgBuf(void)
{
	SME_THREAD_CONTEXT_T* pThreadContext = XGetThreadContext();

	if (NULL!=pThreadContext && NULL!=pThreadContext->pExtEventPool)
	{
		free(pThreadContext->pExtEventPool);
		pThreadContext->pExtEventPool= NULL;
		return TRUE;
	}

	return FALSE;
}

/* Is message available at the current thread event pool?*/
static BOOL XIsMsgAvailable(void *pArg)
{
	SME_THREAD_CONTEXT_T* p = XGetThreadContext();
	X_EXT_MSG_POOL_T *pMsgPool;
	if (NULL==p ||  NULL== p->pExtEventPool)
		return FALSE;

	SME_UNUSED_VOIDP_PARAM(pArg);

	pMsgPool = (X_EXT_MSG_POOL_T*)p->pExtEventPool;

	if (pMsgPool->nMsgBufHdr==pMsgPool->nMsgBufRear)
		return FALSE; // empty buffer.

	return TRUE;
}


/* Thread-safe action to append an external event to the rear of the queue at the destination thread.
 Timer event overflow prevention.
*/
static void XAppendMsgToBuf(void *pArg)
{
	X_EXT_MSG_T *pMsg = (X_EXT_MSG_T*)pArg;
	int nHdr;
	X_EXT_MSG_POOL_T *pMsgPool;
	if (NULL==pMsg || NULL==pMsg->pDestThread || NULL==pMsg->pDestThread->pExtEventPool)
		return;

	pMsgPool = (X_EXT_MSG_POOL_T*)(pMsg->pDestThread->pExtEventPool);
	
	if (((pMsgPool->nMsgBufRear+1) % MSG_BUF_SIZE) == pMsgPool->nMsgBufHdr)
		return; // buffer full.

	// Prevent duplicate SME_EVENT_TIMER event triggered by a timer in the queue.
	nHdr = pMsgPool->nMsgBufHdr;
	if (SME_EVENT_TIMER == pMsg->nMsgID)
	{
		while (nHdr != pMsgPool->nMsgBufRear)
		{
			if (SME_EVENT_TIMER == pMsgPool->MsgBuf[nHdr].nMsgID
			&& pMsg->nSequenceNum == pMsgPool->MsgBuf[nHdr].nSequenceNum)
				return; 
			nHdr = (nHdr+1) % MSG_BUF_SIZE;
		}
	}

	memcpy(&(pMsgPool->MsgBuf[pMsgPool->nMsgBufRear]),pMsg,sizeof(X_EXT_MSG_T));

	pMsgPool->nMsgBufRear = (pMsgPool->nMsgBufRear+1)%MSG_BUF_SIZE;
}

/* Thread-safe action to remove an external event from the current thread event pool.*/
static void XGetMsgFromBuf(void *pArg)
{
	X_EXT_MSG_T *pMsg = (X_EXT_MSG_T*)pArg;
	SME_THREAD_CONTEXT_T* p = XGetThreadContext();
	X_EXT_MSG_POOL_T *pMsgPool;
	if (NULL==pMsg || NULL==p || NULL==p->pExtEventPool)
		return;

	pMsgPool = (X_EXT_MSG_POOL_T*)(p->pExtEventPool);

	if (pMsgPool->nMsgBufHdr==pMsgPool->nMsgBufRear)
		return; // empty buffer.

	memcpy(pMsg,&(pMsgPool->MsgBuf[pMsgPool->nMsgBufHdr]),sizeof(X_EXT_MSG_T));

	pMsgPool->MsgBuf[pMsgPool->nMsgBufHdr].nMsgID =0;

	pMsgPool->nMsgBufHdr = (pMsgPool->nMsgBufHdr+1)%MSG_BUF_SIZE;

}

int XPostThreadExtIntEvent(SME_THREAD_CONTEXT_T* pDestThreadContext, int nMsgID, int Param1, int Param2, 
						   SME_OBJ_T *pDestObj, unsigned long nSequenceNum,unsigned char nCategory)
{
	X_EXT_MSG_T Msg;
	X_EXT_MSG_POOL_T *pMsgPool;
	if (nMsgID==0 || NULL== pDestThreadContext || NULL==pDestThreadContext->pExtEventPool)
		return -1;

	Msg.nMsgID = nMsgID;
	Msg.pDestObj = pDestObj;
	Msg.pDestThread = pDestThreadContext;
	Msg.nSequenceNum = nSequenceNum;

	Msg.nDataFormat = SME_EVENT_DATA_FORMAT_INT;
	Msg.nCategory = nCategory;
	Msg.Data.Int.nParam1 = Param1;
	Msg.Data.Int.nParam2 = Param2;

	pMsgPool = (X_EXT_MSG_POOL_T *)(pDestThreadContext->pExtEventPool);

	XSignalEvent(&(pMsgPool->EventToThread),&(pMsgPool->MutexForPool),(XTHREAD_SAFE_ACTION_T)XAppendMsgToBuf,&Msg);
	return 0;
}

int XPostThreadExtPtrEvent(SME_THREAD_CONTEXT_T* pDestThreadContext, int nMsgID, void *pData, int nDataSize, 
						   SME_OBJ_T *pDestObj, unsigned long nSequenceNum,unsigned char nCategory)
{
	X_EXT_MSG_T Msg;
	X_EXT_MSG_POOL_T *pMsgPool;
	if (nMsgID==0 || pDestThreadContext==NULL || NULL==pDestThreadContext->pExtEventPool) 
		return -1;

	Msg.nMsgID = nMsgID;
	Msg.pDestObj = pDestObj;
	Msg.pDestThread = pDestThreadContext;
	Msg.nSequenceNum = nSequenceNum;
	Msg.nCategory = nCategory;

	Msg.nDataFormat = SME_EVENT_DATA_FORMAT_PTR;

	if (pData!=NULL && nDataSize>0)
	{
#if SME_CPP
		Msg.Data.Ptr.pData = new char[nDataSize];
#else
		Msg.Data.Ptr.pData = malloc(nDataSize);
#endif
		memcpy(Msg.Data.Ptr.pData, pData, nDataSize);
		Msg.Data.Ptr.nSize = nDataSize;
	} else
	{
		Msg.Data.Ptr.pData = NULL;
		Msg.Data.Ptr.nSize = 0;
	}
	pMsgPool = (X_EXT_MSG_POOL_T *)(pDestThreadContext->pExtEventPool);


	XSignalEvent(&(pMsgPool->EventToThread),&(pMsgPool->MutexForPool),(XTHREAD_SAFE_ACTION_T)XAppendMsgToBuf,&Msg);
	return 0;
}

BOOL XGetExtEvent(SME_EVENT_T* pEvent)
{
	X_EXT_MSG_T NativeMsg;
	int ret=0;

	SME_THREAD_CONTEXT_T* p = XGetThreadContext();
	X_EXT_MSG_POOL_T *pMsgPool;
	if (NULL==pEvent || NULL==p || NULL==p->pExtEventPool)
		return FALSE;

	pMsgPool = (X_EXT_MSG_POOL_T*)(p->pExtEventPool);

	memset(&NativeMsg,0,sizeof(NativeMsg));
	while (TRUE)
	{
		ret = XWaitForEvent(&(pMsgPool->EventToThread), &(pMsgPool->MutexForPool), (XIS_CODITION_OK_T)XIsMsgAvailable, NULL, (XTHREAD_SAFE_ACTION_T)XGetMsgFromBuf,&NativeMsg);
			
		if (NativeMsg.nMsgID == SME_EVENT_EXIT_LOOP)
		{
			return FALSE; //Request Exit
		}
#ifdef SME_WIN32
#else
		// Built-in call back timer on Linux
		else if (SME_EVENT_TIMER == NativeMsg.nMsgID  && SME_TIMER_TYPE_CALLBACK == NativeMsg.Data.Int.nParam1)
		{
			// Invoke the call back function. 
			SME_TIMER_PROC_T pfnCallback = (SME_TIMER_PROC_T)(NativeMsg.Data.Int.nParam2);
			(*pfnCallback)(NativeMsg.pDestObj, NativeMsg.nSequenceNum);
		}
#endif
		else {
			// Translate the native message to SME event.
			memset(pEvent,0,sizeof(SME_EVENT_T));
			pEvent->nEventID = NativeMsg.nMsgID;
			pEvent->pDestObj = NativeMsg.pDestObj;
			pEvent->nSequenceNum = NativeMsg.nSequenceNum;
			pEvent->nDataFormat = NativeMsg.nDataFormat;
			pEvent->nCategory = NativeMsg.nCategory;
			pEvent->bIsConsumed = FALSE;
			memcpy(&(pEvent->Data),&(NativeMsg.Data), sizeof(union SME_EVENT_DATA_T));
		}

		//printf("External message received. \n");

		return TRUE;
	}; // while (TRUE)
}

BOOL XDelExtEvent(SME_EVENT_T *pEvent)
{
	if (0==pEvent)
		return FALSE;

	if (pEvent->nDataFormat == SME_EVENT_DATA_FORMAT_PTR)
	{
		if (pEvent->Data.Ptr.pData)
		{
#if SME_CPP
			delete pEvent->Data.Ptr.pData;
#else
			free(pEvent->Data.Ptr.pData);
#endif
			pEvent->Data.Ptr.pData=NULL;
		}
	}
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions