Friday, August 5, 2011

Implementing the Mode Handler of Self-Service Application using Finite State Machine

Implementing ATM/CDM/Kiosk states (Suprvisory, OOS, Offline, In-Service) in C#

Hi,

Some of you will find this post extremely useful, while, some of you will find it completely irrelevant. There is a good reason for both opinions. Self-Service industry is a very specialized domain. Unlike ASP .NET and other commonly used technologies, there is very little or no information available on this subject. Today, I am going to implement a mode handler of Self-Service application using Finite State Machine. Before doing that, we will first go through the basic concepts of SST, Modes, and Mode Handling. I am assuming in this article that you are well aware of the state design pattern and familiar with finite state machines.


Self-Service Terminals

Self-Service Terminals (SST) are pretty common today and come in different forms. You use an ATM to withdraw cash from banks. Kiosks at movie theaters are used to purchase movie tickets. Similarly, kiosks at airports are used for passenger check-in. These are all instances of Self-Service terminals.


Self-Service Transactions

SSTs offer a wide range of transactions. Though, it is not possible to list down all types of transactions, but the following are the most common SST transactions:

i. Cash Withdrawal
ii. Cash Deposit
iii. Check Deposit
iv. Balance Inquiry
v. Utility Bill Payment
vi. Toll/Fine Payment
vii. Mobile Topup/Recharge
viii. Tickets Purchasing
ix. Job Applications
x. Information Viewing


Self-Service Application Modes

Self-Service terminals such as ATMs, CDMs, and Kiosks operate in 4 standard modes. These are:

1. Offline

The connectivity of machine to the network is broken. The SST cannot send and receive messages over the network. This mode is called Offline mode.

2. Out-of-Service

An SST may become Out-of-Service (OOS) for various reasons. The two major reasons are software or hardware failure. However, in most of the cases, OOS mode is caused by a hardware problem. Common examples are notes stuck in Bunch-Note Acceptor, checks stuck in Check Processing Module, or Journal Printer out of paper. In most of the cases, the machine cannot recover itself from OOS mode by itself and requires manual human effort. Someone must come and remove the stuck notes/checks or replenish Journal paper.

3. Supervisory

This is the servicing mode of the SST. Terminal is switched to Supervisory mode when hardware repair is performed. Also, when the terminal is out of cash or paper, the replenishment activity can be only performed when the SST is in supervisory mode. Supervisory mode operations are not only restricted to repair and replenishment, but also include closing of the business cycle and balancing.

A hardware switch/button installed usually inside the SST is used to switch the machine to supervisory mode.

4. In-Service

When SST is not in any of the aforementioned modes, then it means it is ready to complete customer’s transactions. Hence, it is in In-Service mode. The following are the requisites for an SST to become In-Service:

a. Terminal is connected to the network and can send and receive messages
b. All critical devices required to complete a transactions are working
c. Supervisory switch is not turned on.


Mode Handler

A Mode Handler is a controller which is responsible to switch SST to appropriate modes based on the current state of the terminal. Mode Handler is the most critical part of any Self-Service application. Any flaw in Mode Handler can cause devastating results. Take the example of Supervisory mode. This mode should be available to machine supervisors/custodians only. If a customer is given access to the supervisory mode, then the customer can perform actions like clearing the business-cycle, dispense notes from the machine, etc. Scenarios like these may cause huge financial losses.


Implementation of Mode Handler through Finite State Machine

Since each mode of the Self-Service terminal represents the state of the machine, therefore, Mode Handler is implemented in the form of finite state machine. We will write a class to model each state of the machine. In this way, we will have 4 classes. We will also write a controller class to implement state switching.

Since, we are just writing the Mode Handler and not the whole Self-Service application, we will demonstrate the working of Mode Handler through a WinForms application. The WinForms application will contain checkboxes. Each checkbox will represent the condition that triggers state switching.

It is also to be noted that a Self-Service applications should always start in OOS mode. This is the safest mode. The Mode Handler should then check all state switching conditions and should switch SST to appropriate mode. Also, for security reasons, In-Service mode should be the last possible state of the machine after going through all state switching conditions. On the contrary, Supervisory mode should be the top priority mode because if a machine supervisor/custodian has pressed the supervisory switch, the Self-Service application should immediately switch to supervisory mode. The only exception is when a transaction is in progress. In this case, the terminal should first finish the transaction and then switch to supervisory mode.

The following is the sample code of a Mode Handler written in C#.

VariablesStore.cs

namespace SST
{
///
/// Summary description for VariablesStore.
///

public class VariablesStore
{ // implementing global store to save state of the machine
// and other variables to use throughout the application
// provides better control and code-maintenance
public static int SupervisoryOn = 0;
public static int Failure = 0;
public static int NetworkFailure = 0;
}
}


SSTModes.cs


namespace SST
{
abstract class Mode
{ // provides template for child mode classes
protected int MyMode = 0;

private int CheckSupervisorSwitchOn()
{ // check if someone pressed supervisory switch
return VariablesStore.SupervisoryOn;
}

private int CheckFailures()
{ // check if a device has failed
return VariablesStore.Failure;
}

private int CheckNetworkConnectivityFailure()
{ // check if network connection is broken
return VariablesStore.NetworkFailure;
}

public int GetNextMode()
{ // perform SST health check and recommend appropriate mode
// highest priority is supervisory switch

// returning modes based on HC
if (CheckSupervisorSwitchOn() == 1)
return 1;

if (CheckFailures() == 1)
return 2;

if (CheckNetworkConnectivityFailure() == 1)
return 3;

return 4;
}

// needs to be implemented in particular modes only
public abstract int ProcessMode();
}

class SupervisoryMode : Mode
{ // models Supervisory mode of SST

public SupervisoryMode()
{ // this is my mode number
MyMode = 1;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// supervisory operations start

// supervisory operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class OOSMode : Mode
{ // models OOS mode of SST
public OOSMode()
{
MyMode = 2;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// OOS operations start

// OOS operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class OfflineMode : Mode
{ // models Offline mode of SST
public OfflineMode()
{
MyMode = 3;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// Offline operations start

// Offline operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class InServiceMode : Mode
{ // models In-Service mode of SST
public InServiceMode()
{
MyMode = 4;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// In-Service operations start

// In-Service operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}
}


SSTApp.cs


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using System.Data;

namespace SST
{
///
/// Summary description for SSTApp.
///

public class SSTApp : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.CheckBox chkSupervisor;
private System.Windows.Forms.CheckBox chkFailure;
private System.Windows.Forms.CheckBox chkConnectivity;
///
/// Required designer variable.
///

private System.ComponentModel.Container components = null;

public SSTApp()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

///
/// Clean up any resources being used.
///

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

private void InitializeComponent()
{
this.btnStart = new System.Windows.Forms.Button();
this.chkSupervisor = new System.Windows.Forms.CheckBox();
this.chkFailure = new System.Windows.Forms.CheckBox();
this.chkConnectivity = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(8, 16);
this.btnStart.Name = "btnStart";
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// chkSupervisor
//
this.chkSupervisor.Location = new System.Drawing.Point(8, 64);
this.chkSupervisor.Name = "chkSupervisor";
this.chkSupervisor.Size = new System.Drawing.Size(136, 24);
this.chkSupervisor.TabIndex = 1;
this.chkSupervisor.Text = "Supervisor Switch On";
this.chkSupervisor.CheckedChanged += new System.EventHandler(this.chkSupervisor_CheckedChanged);
//
// chkFailure
//
this.chkFailure.Location = new System.Drawing.Point(8, 96);
this.chkFailure.Name = "chkFailure";
this.chkFailure.TabIndex = 2;
this.chkFailure.Text = "Device Failure";
this.chkFailure.CheckedChanged += new System.EventHandler(this.chkFailure_CheckedChanged);
//
// chkConnectivity
//
this.chkConnectivity.Location = new System.Drawing.Point(8, 128);
this.chkConnectivity.Name = "chkConnectivity";
this.chkConnectivity.Size = new System.Drawing.Size(128, 24);
this.chkConnectivity.TabIndex = 3;
this.chkConnectivity.Text = "Connectivity Failure";
this.chkConnectivity.CheckedChanged += new System.EventHandler(this.chkConnectivity_CheckedChanged);
//
// SSTApp
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(152, 165);
this.Controls.Add(this.chkConnectivity);
this.Controls.Add(this.chkFailure);
this.Controls.Add(this.chkSupervisor);
this.Controls.Add(this.btnStart);
this.Name = "SSTApp";
this.Text = "SSTApp";
this.Load += new System.EventHandler(this.SSTApp_Load);
this.ResumeLayout(false);

}
#endregion

///
/// The main entry point for the application.
///

[STAThread]
static void Main()
{
Application.Run(new SSTApp());
}

private void SSTApp_Load(object sender, System.EventArgs e)
{

}

public void ModeHandler()
{
// be default, SST will start in OOS mode
int CurrentMode = 2;

// init all modes
Mode ThisMode = null;
SupervisoryMode ThisSupervisoryMode = new SupervisoryMode();
OOSMode ThisOOSMode = new OOSMode();
OfflineMode ThisOfflineMode = new OfflineMode();
InServiceMode ThisInServiceMode = new InServiceMode();

while (true)
{
MessageBox.Show("Switching to Mode " + CurrentMode.ToString());

// check which mode to switch to
switch (CurrentMode)
{
case 1:
{ // set Supervisor mode as mode to run
ThisMode = ThisSupervisoryMode;
break;
}
case 2:
{ // set OOS mode as mode to run
ThisMode = ThisOOSMode;
break;
}
case 3:
{ // set Offline mode as mode to run
ThisMode = ThisOfflineMode;
break;
}
default:
{ // If everything is fine,
// set In-service mode as mode to run
ThisMode = ThisInServiceMode;
break;
}
}

// run this mode now
CurrentMode = ThisMode.ProcessMode();

// switch to different mode after 3 secs (not necessary)
Thread.Sleep(3000);
}
}

private void btnStart_Click(object sender, System.EventArgs e)
{ // start mode handler in a separate thread
Thread ModeHandlerThread = new Thread(new ThreadStart(ModeHandler));
ModeHandlerThread.Start();
}

private void chkSupervisor_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox supervisory switch pressing on the actual SST
if (chkSupervisor.Checked)
VariablesStore.SupervisoryOn = 1;
else
VariablesStore.SupervisoryOn = 0;
}

private void chkFailure_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox some device failure on the actual SST
if (chkFailure.Checked)
VariablesStore.Failure = 1;
else
VariablesStore.Failure = 0;
}

private void chkConnectivity_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox network connectivity failure
if (chkConnectivity.Checked)
VariablesStore.NetworkFailure = 1;
else
VariablesStore.NetworkFailure = 0;
}
}
}


UI Details

When you launch the application, you will see the main form. You need to click on Start button to start the Mode Handler. Use checkboxes to simulate state switching conditions. Whenever the application switches state, it will display a message box with state number. The following are the state numbers:

Supervisory = 1
OOS = 2
Offline = 3
In-Service = 4



I have included a 3 second delay in state switching to make it easier to observe.

If you work in Self-Service industry, this post will certainly help you in understanding:

1. Fundamental concepts related to SST
2. What are the Modes in which SST operates
3. What is a Mode Handler
4. How Mode Handler eorks
5. How to implement a Mode Handler

To get the complete code, please send me an email and I will reply to you with a copy of the working project.

Cheers!
JS

No comments:

Post a Comment