Fieldpine Logo Documentation Home  

Flow Reference


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 points are used to define a place in the code where it is doing something. That are not concerned with how it is being done, only that it is being done. Flow points can be added and removed over time, but the definition of a numbered flow point remains for all time.

Flow point numbers should be considered random numbers. There is no pattern or sequence to them. Instructions for developers around flow can be seen in the examples on Fieldpine Coding Standards

Some flow numbers are designated as "error" flows. These are points that are not expected under normal operation. Errors come in a wide variety and some errors are only just classed as errors and are less fatal than others. Not all error flow numbers necessarily mean you have a system problem. A flow error is only for unexpected errors at a technical level, a flow error is not logged if the user generates errors in normal operation. For example, a user generating a "wrong password" is not a flow error, while a failure to open a file would be.

Logging Flow

You can define the setting FlowInitMask to cause Pos to write flow statements into the log file FlowLog.txt See the examples tab for details of how to capture flow in real time rather than logging.

The records written to the FlowLog.txt file have the structure

TIME,TTT,NNN
TIME,TTT,NNN,E,RRR,Z

Where

Support Flow

A support engineer can inspect the current flow on a system with the QeDebug test 25,001. This can be done interactively on a lane (if enabled/configured) with the following URL

http://IP-ADDRESS-AND-PORT/gnap/buck?3=fieldpineinternal.fdl911.fetch&100=25001

Capturing a Flow

Create your function to handle the event. These functions can be placed in the "functions.c" in the POS folder

:function name(Flow88)
	MessageBox(0, "The FLOW 88 has just happened", "Flow Alert", 0);

Register the handler. This is done by calling the PosRegisterFlowHandler() function. This can be done quite easily by adding the following line to fpos.ctl

force:Setup.CompanyName=My Test Store
... Other parts of fpos.ctl ..

; Register a flow handler for point 88
PosRegisterFlowHandler(88, 0, "Flow88", 0);

.. Fpos.ctl continues ..

Notes.

  1. Do not use MessageBox() inside flow handlers or otherwise stop POS operation on production environments. This is used for an example only, but can be used on Test/Dev machines.
  2. The names of the functions must match exactly. If you register a function name that does not exist, it will simply not be called. If your implementation of Flow88() does not compile, it will also simply not be called. Essetially the POS ignores all errors in setting up Flow handlers.

A more Complex Handler

The handler above is quite simple, the following indicates a handler that does a little bit more. This handler records how many times the handler has been called and alerts the user if it is too many times. Again, we use MessageBox() for the example but this is considered bad style for production environments

:function name(Flow88)
	struct aa {
		int Cnt;
		int Advised;
	};

	/* Get our memory block, create a new one if none exists */
	struct aa *paa = (struct aa*) PosGetGlobalMemory("Flow88Data", NULL);
	if (paa == NULL) {
		paa = (struct aa*) malloc(sizeof(struct aa));
		if (paa) {
			paa->Cnt = 0;
			paa->Advised = 0;
			PosSetGlobalMemory("Flow88Data", paa);
		}
	}

	if (paa) {
		paa->Cnt++;

		/* Has this happened at least 8 times since last telling user */
		if ((paa->Cnt - paa->Advised) >= 8) {
			char buffer[88];

			sprintf(buffer, "Flow 88 has fired %d times", paa->Cnt);
			paa->Advised = paa->Cnt;
			MessageBox(0, buffer, "Flow 88 message", 0);
		}
	}

Individual Flow Points may be looked up in the reference database. See Reference Data. ( or Example Record ) When using the lookup function, the information returned includes:

The 3 relevance fields are estimates only. Some flow points refer to errors, and some errors are relevant to developers (eg logic faults), while others are more support (eg failing to print receipts), or customer operations teams (eg transaction declined as account on hold). A relevance of 0,0,0 indicates information not set. A relevance of 100,100,100 would indicate an impossible situation.

Example
<DATS>
	<Value>601160429</Value>
	<FlowType>ErrorGle</FlowType>
	<FileName>PrintOutput.cpp</FileName>
	<LineNo>398</LineNo>
	<RelevanceDev>0</RelevanceDev>
	<RelevanceSup>100</RelevanceSup>
	<RelevanceOps>30</RelevanceOps>
	<Common>50</Common>
	<Name>OpenPrinterGraphics</Name>
	<Comments>Failed to open a printer with CreateDC()</Comments>
</DATS>

The above example shows a flow point that fires when a CreateDC() call fails to open a defined printer name. This example will generate an Event as well. (Events are generated for a subset of Flow Points).

We can see the relevance has been set to 0% for developers (the code is doing the right action), and to 100% for support teams as the POS is trying to use a bad printer, which likely indicates it has either been renamed or removed.

Flow Points are by definition unable to record additional "data". So this flow point does not include the printer name, which is included in the Event record.

Documented Points

The following flow points are defined and published. Other flow points exist in the system, general purpose handlers may be called with unknown flow numbers.

Source code shown in descriptions is similar to actual code, but may not be the exact code in use. The API being called is correct, but arguments and syntax may have been adjusted for readability

Sale Related

Creating a new Sale

Flow NumberDescription
701160412Called first when preparing to create a new sale
1605160412
1604160412
1300160412About to check database for free Sid value
1603160412Database has returned from Sid checking. The time difference between this point and 1300160412 shows how long the database took for this operation
943160508A database scan returned no sales for this lane. This error can be reported once for new lanes
1602160412
643160505The calculcated Sid value was zero. This is not normal at this point, but not fatal
1601160412
1600160412New Sid determined, beginning initialisation
1559160412Starting write of new Sid to database
1558160412
1557160412Database about to be committed
1556160412Commit completed
1555160412
1554160412
1553160412
1552160412
1551160412
1550160412
1549160412PriceBand determined and applied, Pre Printing completed, Stocktake setup (if stocktake mode), SaleMachines executed
1548160412Customer specific NewSale event handlers completed. Sale is now fully prepared. Exit function

Other

Flow NumberDescription
600160415The system has entered the "CompleteSale" function.
601160415A sale receipt is about to be printed or emailed
602160415About to try and remove an item from a sale
603160415Salelines may have changed in some way. This is inside the "after change" handler

Device Related

Flow NumberDescription
700160415A serial device (COM port) has failed to open. The system is aborting and disabling functionality on this device. eg We tried to open COM15, but could not

Printing Related

Flow NumberDescription
601160429We attempted to open a printer DC are received an error. The general source code at this time is
if (0==pDC->CreateDC(winsp,prter,NULL,NULL)) {
	// We failed to initialise the printer
	long gle = GetLastError();
	FLOW_ERROR(601160429);
602160429A call to StartDoc() failed. The general source code at this time is
if (-1==pDC->StartDoc(&doci)) {
	long gle = GetLastError();
	FLOW_ERROR(602160429);
603160429A call to StartPage() failed. The general source code at this time is
if (pDC->StartPage() <= 0) FLOW_ERROR(603160429);          // begin a new page

Cash Drawer Related

Flow NumberDescription
726160509We failed to write the cash drawer firing command to the printer.
730160509Secondary open failure. We logged too many 731160509 errors and have given up. The cash drawer was not opened
731160509Temporary open failure. This error can be logged when we are struggling to open the printer device. This error is handled and logged for information purposes.
733160509A call to GetPrinter() failed and we cannot open the cash drawer. The user will be notified. Source code is:
	if (! GetPrinter(phnd,5,(unsigned char*)&pu.prt5,pcnt,&bcnt)) FLOW_ERROR(733160509);
734160509Failure from OpenPrinter(). The general source code at this time is
if (OpenPrinter(pDev,&phnd,NULL)==0) FLOW_ERROR(734160509);
737160509We failed to open a serial port connected cash drawer. The general source code at this time is
HANDLE hCom = CreateFile(m_Port,....)
if (hCom == INVALID_HANDLE_VALUE) FLOW_ERROR(737160509);

Network Related

Flow NumberDescription
215160508A call to WSAIoctl() failed. This is non fatal and the system continues anyway. This error can occur frequently if the version of Windows does not support the feature(s) we are trying to set.
217160508A call to connect() to open a network socket failed. This indicates something is wrong at the network layer currently. General code is
int cs = connect(s,  (SOCKADDR*)&trg, sizeof(SOCKADDR_IN));
if (cs != 0) FLOW_ERROR_SOCKET(217160508);
226160508The socket failed to come online (ready to use) using a select() call. General code is
switch(select(0, NULL, &myset, NULL, &WaitTime)) {
case	SOCKET_ERROR:
	FLOW_ERROR_SOCKET(226160508);
}
1400160707A GNAU packet was queued for transmission but is larger than maximum permitted
1401160707The sendto() function failed to send a GNAU packet
1402160707The sendto() function failed to send a GNAU packet
1923160707A call to WSAStartup() failed inside the UDP reader
1840160707The recvfrom() function returned an error inside the UDP reader function
1923160707A call to WSAStartup() failed inside the HTTP Sender
1922160707A call to WSAStartup() failed when initialising FieldpineUdp
1403160707A request to generate a socket handle failed.
	hSock = socket(AF_INET, SOCK_DGRAM, NULL);
	if (hSock == INVALID_SOCKET) FLOW_ERROR_SOCKET(1403160707);
1402160707
1412160707
sendto function failed while performing network connectivity tests. This can occur while the system samples the network to isolate the best method of communication.
916160708An exception was encountered while attempting to open an HTTP transmission to fieldpine support servers
1404160707A network connection was defined with an invalid port. The connection will not be used.
1405160707A call to WSAStartup() failed when initialising remote servers
1406160707A call to socket() to allocate a stream socket failed
1407160707A connect() returned a fatal error
1408160707
1409160707
A call to select() returned an unexpected error

Graphics and Windows

Flow NumberDescription
1011160508A call to CreateFont() failed to find and return a suitable font.
1012160508A call to CreatePointFontIndirect() failed.
1022160508A call to GetLogFont() failed.
1013160508A call to GetLogFont() failed.
1014160508A call to DeleteObject() failed.
1015160508A call to SelectObject() failed.
1016160508A call to SelectObject() did not return correctly
1017160508A call to SelectObject() failed.
1018160508A call to DeleteObject() failed.
1019160508A call to CreateFontIndirect() failed.
1020160508A call to SelectObject() failed.

Other

Flow NumberDescription
2038160430A call to GetDiskFreeSpaceEx() for the active working drive failed. This is not expected, but not fatal.
if ( GetDiskFreeSpaceEx(NULL, ...) == 0) FLOW_ERROR(2038160430);