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.
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
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
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.
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.
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
Flow Number | Description |
701160412 | Called first when preparing to create a new sale |
1605160412 | |
1604160412 | |
1300160412 | About to check database for free Sid value |
1603160412 | Database has returned from Sid checking. The time difference between this point and 1300160412 shows how long the database took for this operation |
943160508 | A database scan returned no sales for this lane. This error can be reported once for new lanes |
1602160412 | |
643160505 | The calculcated Sid value was zero. This is not normal at this point, but not fatal |
1601160412 | |
1600160412 | New Sid determined, beginning initialisation |
1559160412 | Starting write of new Sid to database |
1558160412 | |
1557160412 | Database about to be committed |
1556160412 | Commit completed |
1555160412 | |
1554160412 | |
1553160412 | |
1552160412 | |
1551160412 | |
1550160412 | |
1549160412 | PriceBand determined and applied, Pre Printing completed, Stocktake setup (if stocktake mode), SaleMachines executed |
1548160412 | Customer specific NewSale event handlers completed. Sale is now fully prepared. Exit function |
Flow Number | Description |
600160415 | The system has entered the "CompleteSale" function. |
601160415 | A sale receipt is about to be printed or emailed |
602160415 | About to try and remove an item from a sale |
603160415 | Salelines may have changed in some way. This is inside the "after change" handler |
Flow Number | Description |
700160415 | A 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 |
Flow Number | Description |
601160429 | We 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); |
602160429 | A call to StartDoc() failed. The general source code at this time is
if (-1==pDC->StartDoc(&doci)) { long gle = GetLastError(); FLOW_ERROR(602160429); |
603160429 | A call to StartPage() failed. The general source code at this time is
if (pDC->StartPage() <= 0) FLOW_ERROR(603160429); // begin a new page |
Flow Number | Description |
726160509 | We failed to write the cash drawer firing command to the printer. |
730160509 | Secondary open failure. We logged too many 731160509 errors and have given up. The cash drawer was not opened |
731160509 | Temporary 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. |
733160509 | A 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); |
734160509 | Failure from OpenPrinter(). The general source code at this time is
if (OpenPrinter(pDev,&phnd,NULL)==0) FLOW_ERROR(734160509); |
737160509 | We 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); |
Flow Number | Description |
215160508 | A 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. |
217160508 | A 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); |
226160508 | The 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); } |
1400160707 | A GNAU packet was queued for transmission but is larger than maximum permitted |
1401160707 | The sendto() function failed to send a GNAU packet |
1402160707 | The sendto() function failed to send a GNAU packet |
1923160707 | A call to WSAStartup() failed inside the UDP reader |
1840160707 | The recvfrom() function returned an error inside the UDP reader function |
1923160707 | A call to WSAStartup() failed inside the HTTP Sender |
1922160707 | A call to WSAStartup() failed when initialising FieldpineUdp |
1403160707 | A 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. |
916160708 | An exception was encountered while attempting to open an HTTP transmission to fieldpine support servers |
1404160707 | A network connection was defined with an invalid port. The connection will not be used. |
1405160707 | A call to WSAStartup() failed when initialising remote servers |
1406160707 | A call to socket() to allocate a stream socket failed |
1407160707 | A connect() returned a fatal error |
1408160707 1409160707 | A call to select() returned an unexpected error |
Flow Number | Description |
1011160508 | A call to CreateFont() failed to find and return a suitable font. |
1012160508 | A call to CreatePointFontIndirect() failed. |
1022160508 | A call to GetLogFont() failed. |
1013160508 | A call to GetLogFont() failed. |
1014160508 | A call to DeleteObject() failed. |
1015160508 | A call to SelectObject() failed. |
1016160508 | A call to SelectObject() did not return correctly |
1017160508 | A call to SelectObject() failed. |
1018160508 | A call to DeleteObject() failed. |
1019160508 | A call to CreateFontIndirect() failed. |
1020160508 | A call to SelectObject() failed. |
Flow Number | Description |
2038160430 | A call to GetDiskFreeSpaceEx() for the active working drive failed. This is not expected, but not fatal.
if ( GetDiskFreeSpaceEx(NULL, ...) == 0) FLOW_ERROR(2038160430); |