Cash Payment with MEI and C# – Part 1

Although getting off to a shaky start with an MEI bill/note recycler, after some consultation with the supplier, firmware upgrades, and software reprovisioning, development has become a really nice experience in contrast to other hardware I have encountered. The MEI SCR 8327 is a note accepter and recycler; it will accept note/bill payment and can also dispense notes back to customers. A recycler differs from an accepter and dispenser because it can accept a note into its dispensable pool, which this unit stores on a drum internally.

cash-payment-with-mei-and-c-pt1-05

I struggled to get the device to function at first. I explored the MEI websites, downloaded everything that looked relevant, and attempted to install drivers and samples. MEI hardware seems to be of high build quality. The device exhibits nice fabrication, high serviceability and modularity, and is proudly represented at almost every kiosk I have encountered in my life, however their organisation of critical documents online is somewhat poor. My problems started when I attempted to connect it to my development PC (I develop on Windows 10, 64bit, with .Net 4.6), and try out the sample applications. I first attempted with the serial port, accessible through a tail at the rear. This resulted in no response. I then tried to install the USB drivers and connect the unit to my computer. The drivers installed without issue, but the device was in a Code 10 state and wouldn’t start.

After becoming stuck at this point I contacted the supplier who eventually connected me to a representative from Crane Payment Innovations (the MEI parent company). The representative (Glenn) was immensely helpful, and after 5 minutes of email conversations we had a Team Viewer session established and began making progress. The software I had downloaded was actually no longer relevant, the drivers were no longer supported, and the software and drivers I was issued are still not available on their website.

He first connected to the device with an application called “Cashflow STS v7.12”, using a new driver which was digitally signed and functional to connect via the device’s USB port (which is obnoxiously presented on the front of the device). From here he was able to upgrade the devices firmware, and enable the Serial port. The device was stuck in a ‘Stand Alone’ state form the supplier, and the serial port was not responsive nor usable. After moving out of this state, and setting up the note values and profiles to accept, he demonstrated their API through the example program, “CPI Integration Toolkit”.

The application seemed to separate out all the basic functions I would imagine that anyone would expect the platform to provide. You can:

  • Accept notes.
  • Decide what to do with an inserted note.
  • Empty the recycler to the cash box.
  • Return a note from the recycler.
  • Get the status of the hardware.
  • Perform simple configuration.

cash-payment-with-mei-and-c-pt1-03

The workflow of the primary use-case of this device seems pretty straight forward. You put the device in a listening state, which in turn allows a note to be inserted. Once the note is inserted the machine tries to match it to a configured denomination profile. If a match is found it is held in escrow. Escrow is like a buffering system for inserted notes; other models support multi-note escrow, allowing the ‘session’ of inserted notes to be returned to the customer who inserted them which might be desirable if the transaction was cancelled. This particular unit only holds a single note in an escrow state, and it must be either recycled or sent to the cassette, if not manually rejected. The recycler of this specific unit can hold 2 different denominations, and is configurable, with a total capacity of 60 notes (according to the sample application). Once the note is actioned, the device leaves the escrow state and returns to an idle state. The hosting system could then choose to raise some event or perform an action knowing that a note has been received, or the device could simply be told to go back into an accepting state.

cash-payment-with-mei-and-c-pt1-02

Viewing the demo application’s code initially made my hair jump after seeing ReSharper litter the main scrollbar (with the most orange markers I have ever seen) , and observing that all the code driving the demo was stored crudely in the code behind. Despite this, the code was actually nicely laid out, and lent itself well to learning, with well though-out comments, validation, and guidance distributed throughout the methods.

As described above, the machine should first enter an accepting state, this is done by calling the EnableAcceptance method on the device instance.

try
{
// Ensure communications are open
if (!_scr.IsOpen)
{
// Cannot enable acceptance. Communications are not open.
return;
}
// Enable acceptance
_scr.EnableAcceptance();
}
catch
{
// Communications are not open, or unknown/unexpected exception.
}

When a note is inserted, it will fire the event bound to the DocumentStatusReported event. This would allow an implementing system to check that the document is in a state where it can be stacked, and then proceed to stack the note to the recycler or cassette. The system could even decide to return the note.

To stack the note to the recycler:

try
{
// Ensure we are at a point where stacking is allowed.
if (_scr.DeviceState != DeviceState.ESCROWED)
{
           // Cannot Stack to Recycler : Device state != Escrowed
return;
}
// Check to see if this document is enabled for recycling.
var bCanStackToRecycler = false; // Default to False until we are sure we can recycler this document.
// Make sure we are dealing with a Banknote object
if (_document != null && _document is Banknote)
{
// Get a reference as a Banknote
var banknoteTmp = _document as Banknote;
var recyclerNoteTable = _scr.GetRecyclerNoteTable();
// Loop through the table and compare the 'ISO' and the 'Value'
foreach (var entry in recyclerNoteTable)
{
if (entry.ISO == banknoteTmp.ISO && entry.Value == banknoteTmp.Value)
{
// Valid entry- check the 'IsRecyclingEnabled' property
if (entry.IsRecyclingEnabled)
{
bCanStackToRecycler = true;
}
break;
}
}
}
// Abort if we cannot stack this document to the recycler
if (!bCanStackToRecycler)
{
// Cannot Stack to Recycler. Document is not enabled for recycling.
return;
}
// Stack the document to the recycler.
_scr.StackDocumentToRecycler();
}
catch
{
// See documentation for the plethora of issues that could arise.
}

To stack the note to the cassette:

try
{
// Ensure we are at a point where stacking is allowed
if (_scr.DeviceState != DeviceState.ESCROWED)
{
// Cannot Stack to Cassette : Device state != Escrowed
return;
}
// Stack the document to the cassette.
_scr.StackDocumentToCassette();
}
catch
{
// See documentation for the plethora of issues that could arise.
}

To return the note:

try
{
// Ensure we are at a point where stacking is allowed
if (_scr.DeviceState != DeviceState.ESCROWED)
{
// Cannot Return the Document : Device state != Escrowed
return;
}
// Return the document
_scr.ReturnDocument();
}
catch
{
// See documentation for the plethora of issues that could arise.
}

You could now re-enable the device to continue accepting notes. If nothing was to be inserted for a long time, it might be desirable to disable acceptance.

try
{
// Ensure communication is open
if (!_scr.IsOpen)
{
// Cannot disable acceptance. Communications are not open.
return;
}
// Disable acceptance
_scr.DisableAcceptance();
}
catch
{
// communications are not open, or unknown/unexpected exceptions.
}

You could issue change to your customer by dispensing notes like so:

// Set the index and quantity to dispense from the recycler accordingly.
int iIndex = 1;
int iCount = 2;
try
{
// Ensure we are in a state where we can dispense documents.
switch (_scr.DeviceState)
{
case DeviceState.IDLE:
// Ensure we aren't currently accepting.
_scr.DisableAcceptance();
break;
case DeviceState.HOST_DISABLED:
// Ok to proceed.
break;
default:
// Cannot Dispense Documents : Device state == _scr.DeviceState
return;
}
// Input has been validated so dispense the document(s)
_scr.DispenseByCount(iIndex, iCount);
}
catch
{
// Device is not in a valid state, index is invalid, quantity is invalid, comms loss, or other unknown error.
}

Decisions can be made on how to route notes and perform transactions by using the recycler note table. calling the GetRecyclerNoteTable command on the device instance will return an object describing the state of the devices reserves. The cassette should be manually monitored however.

I will follow up this article once I have completed the integration of this device into my own project, and outline any more issues that arise. Despite the obvious limitations that present themselves with the limited core instruction set, the hardware seems well fabricated, the API is easy to follow, and the features sensible to standard applications. I look forward to exploring other MEI/CPI devices in the future.