AndreasFagschlunger / O2Xfs

Java API for accessing CEN/XFS API, EMV Level 2 Kernel
47 stars 28 forks source link

Initialize Device and Get Event From Device #40

Closed azdafirmansyah closed 7 years ago

azdafirmansyah commented 7 years ago

Hi All,

I follow the instruction, build gradle project already success . And XFS from provider installed already. import all project into Eclipse success.

When I try to run each service, I still cannot get event from device.

How I can initialize device and get event from device ? Anyone can give me step by step what should I do to get event from device ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

There are two APIs, at.o2xfs.xfs and at.o2xfs.xfs.service. The first one, in combination with o2xfs-xfs3, is basically a wrapper for the C API. You can use it to call the essential XFS functions.

Than there is at.o2xfs.xfs.service which provides a higher level API for at.o2xfs.xfs. Basically you obtain the XfsServiceManager instance, call initialize method once and call openAndRegister(String, Class<E>). The XfsServiceManager returns a XfsService object, which provides listeners for specific events (e.g. IDCServiceListener). The XfsService object is also used to executed commands (e.g. ReadCardCommand).

So you can go on with the low-level at.o2xfs.xfs API and extract the necessary information from at.o2xfs.xfs.service, or you can try at.o2xfs.xfs.service as a higher level API. Can you explain what your try to achieve? Which devices you want to support?

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger ,

Thanks for your response. I will try your suggest.

I have one ATM machine for development. I need to access device in ATM :

Regards, Azda Firmansyah

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger ,

I follow your suggestion but still got below error : https://drive.google.com/file/d/0B3NRikF5MB_2clhqdFVxS3k0V2M/view?usp=sharing

I create TestApp.class in same project with at.o2xfs.xfs.service. When I try to run this test class, got error that "java.lang.UnsatisfiedLinkError: no at.o2xfs.win32 in java.library.path". But this project already dependencies with "at.o2xfs.win32". Why I still get this error ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Are you sure you are running TestApp with a 32-Bit JRE/JDK?

azdafirmansyah commented 7 years ago

Hi AndreasFagschlunger,

Yes, 100% sure. I use jdk 1.8.0_121 for 32 bit.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Sorry, I found the bug. I changed a lot the last days and didn't have the time to test fully yet. I will do a commit later the day, for you to go on the easiest way is to fix XfsAPI.java:

    private XfsAPI() {
-       System.loadLibrary("at.o2xfs.win32");
-       System.loadLibrary("at.o2xfs.xfs");
+       Library.loadLibrary("at.o2xfs.win32");
+       Library.loadLibrary("at.o2xfs.xfs");
    }

And copy at.o2xfs.xfs.dll, at.o2xfs.xfs.conf.dll to C:\Users\...\.o2xfs\lib\x86, because of this bug:

at.o2xfs.xfs/build-native.gradle
 task x86Jar(type: Jar) {
-    from file('build/libs/at.o2xfs.win32.dll/shared/x86/release/at.o2xfs.xfs.dll'),
-         file('build/libs/at.o2xfs.win32.dll/shared/x86/release/at.o2xfs.xfs.conf.dll')
+    from file('build/libs/at.o2xfs.xfs.dll/shared/at.o2xfs.xfs.dll'),
+         file('build/libs/at.o2xfs.xfs.conf.dll/shared/at.o2xfs.xfs.conf.dll')
 }

The at.o2xfs.xfs.binaries.x86 doesn't contain any DLLs at all.

azdafirmansyah commented 7 years ago

Hi AndreasFagschlunger,

I will try this way until you commit bu fix.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

I pushed the changes to develop branch. Hopefully I didn't miss anything. You can also run at.o2xfs.operator which is a app who demonstrates some basic features. Run

.\gradlew dist

To create a distribution ZIP at.o2xfs.operator\build\distributions or download from CI-Build:

https://repo.fagschlunger.co.at/webapp/#/artifacts/browse/tree/General/libs-snapshot-local/o2xfs/at.o2xfs.operator/1.0.0.BUILD-SNAPSHOT

But since the JAR files now contain version information, you have to change the path of at.o2xfs.operator.jar in start.cmd: at.o2xfs.operator-1.0.0.BUILD-SNAPSHOT.jar

Also create a services.properties file and put it in the at.o2xfs.operator directory, e.g.:

CDM=MyCurrencyDispenser
IDC=MyCardReader
PIN=MyPinpad
PTR=MyStatementPrinter
SIU=MySensors

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger ,

I try run at.o2xfs.operator after add services.properties like below : CDM=MyCurrencyDispenser IDC=MyCardReader PIN=MyPinpad PTR=MyStatementPrinter SIU=MySensors

But still got "Service Not Found". https://drive.google.com/file/d/0B3NRikF5MB_2bERQbmExYnpNYk0/view?usp=sharing

Regards, Azda Firmansyah

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Its look like successfull when I try to initialize device.

I use this code : XfsServiceManager xfsServiceManager = XfsServiceManager.getInstance(); xfsServiceManager.initialize();

  1. Way 1
    XfsService xfsService = xfsServiceManager.openAndRegister("PTR", PTRService.class); String sLogicalName = xfsService.getLogicalName();

  2. Way 2 PTRService ptrService = xfsServiceManager.openAndRegister("PTR", PTRService.class); String sLogicalNamex = ptrService.getLogicalName();

Which one is correct ? both return same response How I can send data to test Print ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

Check out the Windows Registry on your machine for the correct logical names:

HKEY_USERS\.DEFAULT\XFS\LOGICAL_SERVICES

The logical names in services.properties are just example values. Regarding to your question, way two would be correct. Because sub classes of XfsService implement the user-event handling, see CdmService for example. Unfortunately PTRService is far from complete yet.

After initialization you can use XfsInfoCommand and XfsExecuteCommand classes to call Info/Execute commands. For PTR check out PTRRawDataTask, PTRRawDataCallable, PTRStatusCallable and PTRCapabilitiesCallable.

The most commands are currently implemented for cash dispensers, check packages at.o2xfs.xfs.service.cdm and at.o2xfs.xfs.service.cdm.xfs3. Wrappers for the various C-Structs are fully available for CIM/CDM in o2xfs-xfs3 project. at.o2xfs.xfs.service.cdm is a good example where I want to go, where PTR*Callable are somewhat outdated (naming conventions, etc.).

What do you want to do first? Dispense Cash, Print Data? I can create the C-Struct wrappers for specific services in relatively short time (one or two days).

azdafirmansyah commented 7 years ago

Hello @AndreasFagschlunger,

Thanks for your response and explanation.

I already success to open some device PTR, CDM, IDC, PIN, SIU.

what I want to do first is :

  1. Dispense Cash
  2. Deposit/Withdraw Cash
  3. Print Data

Thanks and regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

The at.o2xfs.operator project already contains Tasks for dispensing and presenting cash, see at.o2xfs.operator.task.xfs.cdm.DispenseTask and at.o2xfs.operator.task.xfs.cdm.PresentTask. There is no implementation for START_EXCHANGE and END_EXCHANGE commands yet, so maybe you have another way of how to tell that there is money in the machine or you must put a simple implementation together by yourself.

For cash deposit all possible data structures are present in o2xfs-xfs3 project, where all constants are found in package at.o2xfs.xfs.cim of at.o2xfs.xfs project. But the actual implementation of the various commands in at.o2xfs.xfs.service is missing, so try to follow the code in at.o2xfs.xfs.service.cdm.xfs3 package to implement them by yourself.

I will look forward to generate all available structures for PTR service as soon as possible.

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

HI @AndreasFagschlunger,

Thank you, I will try for dispense and deposit first.

Regards, Azda Firmansyah

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Here is the snippet code for CreateWizard function : Line 1. private DispenseWizard createWizard() throws XfsException { Line 2. DispenseWizard result = new DispenseWizard(getCommands(), getContent(),
Line 3. capabilities.getMaxDispenseItems()); Line 4. for (CashUnit3 cashUnit : sortedCashUnits) { Line 5. CurrencyExp3 currencyExp = service.getCurrencyExponents().stream().filter(e -> Line 6. Arrays.equals(e.getCurrencyID(), cashUnit.getCurrencyID())).findFirst().get(); Line 7. result.addPage(new DispenseWizardPage(cashUnit, currencyExp));

  1. What should I do with "e" (Line 5 and line 6) because I got error.
  2. How to open shutter and close shutter ?I didn't found how to do it
  3. How to execute WFSCommand ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hi @azdafirmansyah

The following line:

CurrencyExp3 currencyExp = service.getCurrencyExponents().stream().filter(e -> Arrays.equals(e.getCurrencyID(), cashUnit.getCurrencyID())).findFirst().get();

Tries to find the CurrencyExp3 matching the cash units currency ID. The idea was to use CurrencyExp3 do probably display cash unit value. Check the description of the WFS_INF_CDM_CURRENCY_EXP command in the XFS specification for details. I suggest to not use CurrencyExp3 and use java.text.DecimalFormat instead.

The isShutterControl() method in CdmCaps3 tells you, if you have to explicitly control shutter or if the shutter is controlled implicitly by the Service Provider. If isShutterControl() return false, you have to execute WFS_CMD_CDM_OPEN_SHUTTER and WFS_CMD_CDM_CLOSE_SHUTTER commands to open and close shutter. This case is currently not handled in DispenseTask.

But it shouldn't be that complicated, you can execute a OPEN_SHUTTER command, since it doesn't have any output parameters nor execute events. e.g.:

CdmService cdmService = XfsServiceManager.getInstance().getService(CdmService.class);
XfsExecuteCommand<CdmExecuteCommand> executeCommand = new XfsExecuteCommand<CdmExecuteCommand>(cdmService, CdmExecuteCommand.OPEN_SHUTTER, XfsWord.valueOf(Position.NULL));
WFSResult wfsResult = null;
try {
    wfsResult = executeCommand.call();
} catch (XfsException e) {
    e.printStackTrace();
} finally {
    if (wfsResult != null) {
        XfsServiceManager.getInstance().free(wfsResult);
    }
}

Take DispenseCommand as a template for a new OpenShutterCommand implementation.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger ,

Thank you for your response.

Regards, Azda Firmansyah