Communication options between Open C engine and S60 UI
Article Metadata
Contents |
Introduction
This article examines the different ways to combine Open C functionalities to a Symbian application. Depending on the amount of functionality and type of data one can choose to either include the Open C code directly to a Symbian application binary or to create a new binary. The Open C binary can be a separate executable which runs in a separate process or a library that is used by the Symbian application executable.
Open C functionality in a separate process
Depending on the type of functionality that the Open C component provides there are several ways to design the communication (IPC) between the processes.
// Constants used in the examples
_LIT(KNoName, "");
_LIT(KTxtPanic,"Panic");
_LIT(KEngineName, “MyEngine.exe”);
#define KQueueIndex 10
#define KChunkIndex 11
#define KMutexIndex 12
#define KMemSize 1024
1) Launch engine process and wait until it finishes
/**
* S60 UI application
*/
void CMyClass.CallEngineL(const TDesC &aCommandLine)
{
TRequestStatus status;
RProcess process;
User::LeaveIfError(process.Create(KEngineName, aCommandLine));
process.Logon(status);
process.Resume();
User::WaitForRequest(status); // wait until the engine process finishes
process.Close();
}
/**
* Open C engine
*/
int main(int argc, char* argv[])
{
// ENGINE CODE
}
2) Exchange information between two running processes
If there exists a continuous flow of data between the processes a channel needs to be created. To handle the communication channel a layer of Symbian code is added on top of the Open C engine code. The main() function is replaced by E32Main() function.
/**
* New entry point for engine
*/
LOCAL_C void OpenCMainL(TPtrC &aCommandLine)
{
// ENGINE CODE
}
/**
* A normal Symbian OS executable provides an E32Main() function which is
* called by the operating system to start the program.
*/
GLDEF_C TInt E32Main()
{
CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack
// run actual engine code
RProcess process;
TRAPD(error,OpenCMainL(process.CommandLine()));
__ASSERT_ALWAYS(!error,User::Panic(KTxtPanic, error));
delete cleanup; // destroy clean-up stack
return 0;
}
2.1) Using message queue
Symbian U application code
// Data members
RProcess iProcess;
RMsgQueue<TInt32> iQueue;
// Initialization
User::LeaveIfError(iQueue.CreateGlobal(KNoName, 1);
User::LeaveIfError(iProcess.Create(KEngineName, aCommandLine));
iProcess.SetParameter(KQueueIndex, iQueue);
iProcess.Resume();
// Engine update
TInt32 msg;
iQueue.ReceiveBlocking(msg);
// Finalization
iProcess.Kill(KErrNone);
iQueue.Close();
iProcess.Close();
Open C engine code
#include <e32std.h>
#include <e32base.h>
#include <e32cons.h>
#include <e32msgqueue.h>
LOCAL_C void OpenCMainL(TPtrC &aCommandLine)
{
RMsgQueue<TInt32> queue;
User::LeaveIfError(queue.Open(KQueueIndex));
while ( ... )
{
...
// Update UI process
TInt32 msg;
queue.SendBlocking(msg);
}
queue.Close();
}
2.2) Using global memory
S60 UI application code
// Data members
RProcess iProcess;
RChunk iChunk;
RMutex iMutex;
// Initialization
User::LeaveIfError(iChunk.CreateGlobal(KNoName, KMemSize, KMemSize));
User::LeaveIfError(iMutex.CreateGlobal(KNoName));
User::LeaveIfError(iProcess.Create(KEngineName, aCommandLine));
iProcess.SetParameter(KChunkIndex, iChunk);
iProcess.SetParameter(KMutexIndex, iMutex);
iProcess.Resume();
// Engine update
iMutex.Wait();
unsigned char* ptr = iChunk.Base(); // Get global memory base address
...
iMutex.Signal();
// Finalization
iProcess.Kill(KErrNone);
iMutex.Close();
iChunk.Close();
iProcess.Close();
Open C engine code
#include <e32std.h>
#include <e32base.h>
#include <e32cons.h>
LOCAL_C void OpenCMainL(TPtrC &aCommandLine)
{
RChunk chunk;
RMutex mutex;
User::LeaveIfError(chunk.Open(KChunkIndex));
User::LeaveIfError(mutex.Open(KMutexIndex));
while ( ... )
{
...
// Update UI process
mutex.Wait();
unsigned char* ptr = chunk.Base(); // Get global memory base address
...
mutex.Signal();
}
chunk.Close();
mutex.Close();
}


