Fieldpine Logo Documentation Home  

Event Handlers using Mini C


Event handlers for the POS can be written in the C programming language. This is not required, but allows more possibilities for technical sites. C event handlers allow you to interface more easily to external systems, but allowing you to provide the glue logic.

The POS includes a small open source C compiler (TCC) which will dynamically compile and link your C code at runtime. Alternatively, you can precompile and ship a DLL/EXE with your functions.

Event Reference List. Documentation of each event code

Examples

The following event handler is called when a server system has processed and is about to store an inbound sale from a trading lane to the database. In this example, we simply log the sale details to a log file

:event(number(16100) index(0) lang(C))
	#include <stdio.h>
	#include <share.h>
	FILE* pf = _fsopen("event16100.out", "a", _SH_DENYNO);
	if (pf) {
		long Sid = PosContext_GetField(pContext, 420);
		long Srcuid = PosContext_GetField(pContext, 400);
		long Locid = PosContext_GetField(pContext, 401);
		long Srcuidkey = PosContext_GetField(pContext, 421);
		fprintf(pf, "Sale Loaded Locid=%ld Srcuid=%ld sKey=%ld AsSid=%ld\n", Locid, Srcuid, Srcuidkey, Sid);
		fclose(pf);
	}
	return 0;
:end

Allowing C into the POS processing has some guidelines that need to be followed. Your event handlers are operating in tightly controlled financially secure area

  1. Your event handlers are probably running in their own address space and cannot directly access the POS address space.
  2. Event handlers should not stall for long. The POS is likely to call critical events with timers and if your code does not respond inside this time frame it may be ignored. Consider a user scanning a barcode, we cannot block processing for more than about a second or two, as a user and probably a customer is waiting.
  3. If you are opening network connections of any kind, be aware that sometimes these operations can take a long time.
  4. Your code may call other functions or use multiple threads. Secondary threads should not communicate directly to the PosEngine
  5. The pContext argument passed to your event handler is only valid for the life of that call and can only be accessed from the thread it was passed on.

There are two ways C code can be implemented. As mini C routines inside Pos control files, or as true compiled and distributed code in a .DLL file

Mini C Routines

With mini C routines, you can place C code directly into event handlers. The POS will add required headers and entry points. This is essentially a short form of a full C compilation.

Entry Point

Each function called by the POS has the following function declaration

	int FuncName(void* pContext);

The argument pContext is a pointer to an area of memory with full details of the call. A number of functions are provided which can extract the details from this structure. You should not modify the data pointed to be pContext it is intended to be Read-Only.

Return Codes

Mini C routines must return a valid return code. Routines that return invalid values may be subject to removal and not being called again

ValueSymbolDescription
0FIELDPINE_REEV_NO_RESPONSEI do not wish to affect the default outcome. Continue to call me in future. Use this code if you do not know what to respond with
1FIELDPINE_REEV_ALLOWVote to specifically allow this operation
2FIELDPINE_REEV_DENYVote to block or deny this operation
4FIELDPINE_REEV_JUNCTION_DO_DEFAULTFor a Junction, this tells the system you explicitly want the default processing to occur. This is slightly different to NO_RESPONSE which says you do not care. Mostly this value is used where multiple event handlers are present on the same junction point.
5FIELDPINE_REEV_JUNCTION_DONEI have completed this operation and supplied a response. This code can only be used by Junction Events
16FIELDPINE_REEV_REMOVEReturns NO_RESPONSE internally but additionally marks that this handler does not need to be called again. This might be used by handlers that are not functional for some reason. Removed handlers are typically called again each time the Application starts, the removal is only for this process.
17FIELDPINE_REEV_REMOVE_DATESame as REMOVE, but states that we are only being ignored for this processing date (complete 24 hour period). This response might be used by handlers that are only valid on certain days.

The mini "C" interface is designed to be easy to write small scripts. It is not designed to handle very large programs, although it will work fine with larger programs

In order to simplify the scripts, there are a number of non-standard features used. You can disable these non standard features using the "entry()" directive (see below)

  1. If you start a line with "#include" anywhere in your program, it will be moved into the header.
  2. You do not need to define the entry point. The POS will automatically insert an entry function for you ( int FuncName(void* pContext) ). The system will also close the function with a }.
  3. We will include headers automatically if we can to save users
  4. The system links against user32.lib and kernel32.lib. If you need more functions than this you will need to either dynamically load the DLL or use the more fully featured Talk To Fieldpine interface.

If needed, you can stop the system automatically adjusting and writing code by adding the directive entry().

	:event(number(10002) index(0) lang(C) entry(MyFunc) )

	int MyFunc(void* pContext) {
		//  Process
		return 0;
	}

Defining the entry point can be useful if you need to create additional functions, for example

	:event(number(10002) index(0) lang(C) entry(MyFunc) )

	const char* GetMessage(int w) {
		if (w == 2) return "abc";
		else return "def";
	}

	int MyFunc(void* pContext) {
		const char* p = GetMessage(2);
		return 0;
	}

The mini "C" environment includes a number of API functions that are available. This allows you to read and write information to and from the PosEngine.


PosCommand()

void PosCommand(const char*);

This function allows an event handler to request execution of a PosCommand. Event handlers should not cause recursion (ie cause the same event to be fired again while still active).

Example

Select the item 2 before the one currently selected and then delete it from the sale

	PosCommand("sale(sel-2)");
	PosCommand("sale(delsel)");

PosPrimitive

void PosPrimitive(const char*);

PosContext_GetField

long PosContext_GetField(void*, int);

PosContext_GetFieldToBuffer

long PosContext_GetFieldToBuffer(void*, int, void*, int);

PosContext_GetFieldPtr

char* PosContext_GetFieldPtr(void* pC, int Want, int* pOutLen);

PosContext_SetFieldString

long PosContext_SetFieldString(void* pC, int Want, const char*);

PosContext_SetData

long PosContext_SetData(void* pC, const char*, const char*);

Example

	PosContext_SetData(pContext, "workingcommand.newscreen", "secret");

There are a number for functions specifically reserved for support and debugging. These functions must not be used to implement business logic and may be disabled, removed or changed without warning. They are intended to provide hooks for automatic support and analysis tools. Using these functions is an advanced option and not covered under operational support contracts

FLOW is used from the main engine to report what is happening inside. As the code moves through its execution it fires FLOW status reports. These can be trapped and handled by external functions for support purposes. Custom FLOW handlers can be used to capture additional error details for problem analysis, measure operation timing or as a debug PC like trace. Flow Reference


PosRegisterFlowHandler(long FlowNumber, FlowModule, const char* pFunctionName, unsigned long Flags)

The following example causes the system to call the function "Flow88" whenever the code passes over the point numbered 88.

PosRegisterFlowHandler(88, 0, "Flow88", 0);