I am new in C# and currently working on the backend code to support PIN pad. Basically, my code
OpenDevice() -> RequestPIN()
-> key in PIN on PIN PAD -> GetResultPIN()
-> ConsolePrintOutPIN() -> Print keyed PIN on the Console
I don't know how to write thread for this, so that once the "Enter key" is hit on the device after PIN, the system would automatically rolls to function GetResultPIN()
. So, with my elementary knowledge, I wrote the following codes using Console.ReadLine()
to separate each procedure:
static void Main(string[] args)
{
// 1. Open PIN Pad device
OpenDevice();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
// 2. Request PIN from PIN Pad device.
// On the PIN Pad device, it reads:
// "Key in the PIN: "
RequestPIN();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
// 3. get PIN from the device
GetResultPIN();
// 4. Print out on the Console
ConsolePrintOutPIN();
Console.ReadLine();// to hold up from the previous procedure, it is *not* for input data purpose
}
Question: Can anyone give me any suggestions on how to use threading/event/delegate that can avoid using Console.ReadLine()
?
As commended above, Console.ReadLine()
is used just to stop the procedure (sorry about my naivety of using it this way....) Once I use Console.ReadLine()
, between RequestPIN()
and GetResult()
, the system would at least wait for me to Key in the PIN from the PIN PAD (connected to the computer through USB, not from key board), and then I would hit any key on the keyboard to pass Console.ReadLine()
and GetResultPIN()
would be able to get my PIN number from PIN Pad.....the whole program works now, it is not customer ready, because it is very choppy, doesn't flow due to Console.ReadLine()
I added.....
So ideally, all the method would flow together. Once the device is opened, RequestPIN()
should show on the PIN Pad screen asking for PIN number, some one can key in and hit enter on PIN Pad and it naturally flow to GetResultPIN()
and read the result, and then it prints the PIN on the console...`
or
if the person doesn't key in PIN, the device would wait for 30s and directly goes to GetResultPIN()
and print out "0000" on the Console
I have looked up treading and delegate, but am not sure how to use them in this situation.... Thank you!
Reference: RequestPin() and GetResultPIN are listed down below:
mIPAD.requestPIN(waitTime, pinMsg, minLen, maxLen, tone, option, ",");
//This function wraps device command 0x04.
//It directs the device to prompt the user to enter a PIN
//by displaying one of five predetermined messages and playing
// a specified sound.
//The messages on the device’s screen look like the figures below.
//The event associated with this function is
//OnPINRequestCompleteEvent.
waitTime: Time the device should wait for the user to begin PIN entry
pinMsg: Message to display as a user prompt, such as "Enter PIN", "ReEnter PIN", "Verify PIN", etc
minLen and maxLen: minimum length and maximum length of PIN
tone: beeping tone option
Option: Verify PIN, not Verify PIN, ISO0 FOrmat, ISO3 Format
Output would be: an integer, 0: Success, Non-Zero: Error
public void GetResultPIN()
{
StringBuilder sb = new StringBuilder();
sb.Append(mIPAD.pin.KSN);
// Key Serial Number:
//a given number from the device, unique for each device
sb.Append("," + mIPAD.pin.EPB);
// EPB: encryption of PIN after Dubpt TripleDES,
// essentially, EPB is PIN
sb.Append("," + mIPAD.getStatusCode());
//status code: Zero is good/done
// None-Zero is Error
sb.Append("\r\n");
result = sb.ToString();
}
Basically, the GetResultPIN() returns a string of random code, for example:
9A00030000047A2000AB,AD781711481B08A2,0
when PIN is successful. If the pin-input part is skipped, it would return ,,0
.
Really hard to know if this will work or not without hardware to play with...
This is the way I envisioned it working:
static void Main()
{
OpenDevice();
RequestPIN();
if (GetResultPIN())
{
// do something with the PIN:
var pin = mIPAD.pin.EPB;
// ...
}
else
{
Console.WriteLine("0000");
}
}
public static bool GetResultPIN()
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
SW.Start();
while (mIPAD.getStatusCode() != 0 && SW.Elapsed < timeout)
{
System.Threading.Thread.Sleep(50); // small call to prevent CPU usage ramping to 100%
}
return (mIPAD.getStatusCode() == 0);
}
You can rewrite your api to:
- make
GetResultPIN()
return a value
- use this value as input for
ConsolePrintOutPIN()
In GetResultPIN
you need to make a Task To ReadYour Pin and wait for it.
See : https://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx
You can do something like this:
public string GetResultPIN()
{
StringBuilder sb = new StringBuilder();
sb.Append(mIPAD.pin.KSN);
// Key Serial Number:
//a given number from the device, unique for each device
sb.Append("," + mIPAD.pin.EPB);
// EPB: encryption of PIN after Dubpt TripleDES,
// essentially, EPB is PIN
sb.Append("," + mIPAD.getStatusCode());
//status code: Zero is good/done
// None-Zero is Error
sb.Append("\r\n");
Thread.Sleep(20*1000); // it is in milliseconds
return sb.ToString();
}
Thanks for posting... The solution is still not ideal....
I also did some more testing regarding the function RequestPIN()
. I have the following four scenarios:
- User finishes keying in PIN sooner than the
waitTime
goes out.
onPINRequestComplete :
OpStatus:0
KSN:9A00030000047A2000C8
EPB:39DED176D3EA40B9
..............................
User doesn't finish keying in PIN when the waitTime
is going out.
onPINRequestComplete :
OpStatus:2
KSN:00000000000000000000
EPB:0000000000000000
..............................
User cancels the PIN pad option by pressing "Cancel X" key on the PIN Pad.
onPINRequestComplete :
OpStatus:1
KSN:00000000000000000000
EPB:0000000000000000
..............................
User doesn't key in PIN at all during the waitTime, and then waitTime goes out.
onPINRequestComplete :
OpStatus:2
KSN:00000000000000000000
EPB:0000000000000000
..............................
So, scenario 1 and 3 would require the thread to wake up right away, while 2 and 4 would require the thread to wake up when the waiTime goes out. So using Thread.sleep(20*1000)
within GetResultPIN()
would work perfectly for scenario 2 and 4. As for 1 and 3, the user has to wait for a long time....
On the other hand, I found some code about Event
Within Car.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WaitOnTasksToComplete
{
class Car
{
public event Action OnChange;
private double speed;
public double Speed
{
get { return speed; }
set { speed = value;
if (speed >= 60)
{
if (OnChange != null)
{
OnChange();
}
}
}
}
}
}
Within Program.cs:
using System;
namespace WaitOnTasksToComplete
{
class Program
{
static void Main(string[] args)
{
Car c = new Car();
c.OnChange += C_OnChange;
c.Speed = 5;
c.Speed = 55;
c.Speed = 65;
c.Speed = 75;
}
private static void C_OnChange()
{
Console.WriteLine("Event fired: Car goes higher than 60 MPH.");
}
}
}
So, basically once the Car.speed
jumps above 60, the alarm would show. I am considering borrowing the condition into my situation: Initialize OpStatus = -999
. When OpStatus=0 or 1
, keep executing GetResultPIN()
and PrintMessagePIN()
. If OpStatus=2 or others
, keep waiting...
That is just my thoughts.... still have no clue how to implement it.... Any related ideas or suggestions would be appreciated.....
Ah, I figured out. I am basically using threading here. The main flow is OpenDevice()->RequestPIN()->Thread(()=>CheckOpStatus(getResultPIN)) -> Thread.Start()
. Within the Thread, a loop is set to check every half second what the OpStatus
is. Per my previous post, OpStatus
is the output parameter of PIN Pad, zero- success; non-zero: failure
. That said, the loop would proceed until either bool condition_WithinWaitTime
or bool condition_NoKeyEvent
breaks. After breaking out, invoke the getResultPIN
and so on....
Here is my source code, as PIN input is one of my functions, the rest of which have very similar behavior in terms programming (request->manual operation->feedback), so I also included a delegate variable to represents all functions (card swiping, PIN, signature bla bla).
static void Main(string[] args)
{
OpenDevice();
EventGetPIN();
}
static void EventGetPIN()
{
myDel getResult = new myDel(GetResultPIN);
Thread thread1 = new Thread(() => CheckOpStatus(getResult));
myDel requestDel = new myDel(RequestPIN); requestDel();
thread1.Start();
}
static void CheckOpStatus(Delegate getResult)
{
int count = 0;
int checkingPeriod = 500;
int totalWaitTime = waitTime * 1000 + offsetTime;
string OpStatus;
string ksnStart = mIPAD.getKSN();
string ksn = ksnStart;
bool condition_WithinWaitTime = true;
bool condition_NoKeyEvent = true;
while (condition_WithinWaitTime & condition_NoKeyEvent)
{
count++;
OpStatus = mIPAD.getStatusCode().ToString();
ksn = mIPAD.getKSN();
//Console.WriteLine(OpStatus);
condition_WithinWaitTime = (count * checkingPeriod) < totalWaitTime;
condition_NoKeyEvent = (ksn == ksnStart);
Thread.Sleep(checkingPeriod);
}
getResult.DynamicInvoke();
}