/**
*
* @author Sebastien Riou
*/
package uk.co.nimp.scard;
import com.atolsystems.atolutilities.ACommandLineUtilities;
import com.atolsystems.atolutilities.ACommandLineUtilities.Arg;
import com.atolsystems.atolutilities.AStringUtilities;
import com.atolsystems.atolutilities.ArgSpec;
import java.util.List;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallFunctionMapper;
import java.io.File;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import uk.co.nimp.smartcard.AnswerToReset;
import static uk.co.nimp.scard.MP300Exception.*;
import uk.co.nimp.smartcard.Apdu;
public class MP65TerminalManager extends GenericTerminalManager {
public static final int MP65= 65;
public MP65TerminalManager(){
}
static public interface Win32Mp300ComDll extends Library {
// Functions from mp300com.dll
//WORD MPOS_OpenResource ( DWORD ResID, BYTE CplNum, DWORD BlockingMode);
short MPOS_OpenResource(int ResID, int CplNum, int BlockingMode);
//WORD MPOS_CloseResource ( DWORD ResID, BYTE CplNum);
short MPOS_CloseResource(int ResID, int CplNum);
//WORD MPS_ResetHard(BYTE CplNum);
short MPS_ResetHard(int CplNum);
//void CALL SetDLLTimeOutValue(WORD timeout);
void SetDLLTimeOutValue(int timeout);
//WORD CALL GetDLLTimeOutValue(void);
short GetDLLTimeOutValue();
//int CALL OpenCommunication(char * host);
//int OpenCommunication(String host);
int OpenCommunication(byte[] host);
//int CALL CloseCommunication(void);
int CloseCommunication();
//WORD MPS_SendPPS2 (BYTE CplNum, DWORD PPS, BYTE *pPPSResponse);
short MPS_SendPPS2(int CplNum, int PPS, byte[] pPPSResponse);
//void CALL SetDLLTimeOutValue(WORD timeout);
//WORD CALL GetDLLTimeOutValue(void);
//WORD CALL GetLastComError(void);
//int CALL SendFrame(HANDLE hcom, int noanswer, WORD timeout, char * command, char * repbuf);
//int CALL UseSequenceNumber(int onoff);
//WORD CALL StartDownloadTo (BYTE CplNum, char *pFileName);
//WORD CALL StartDownload (BYTE CplNum, PROC_DOWNLOAD pfunc, DWORD reserved, DWORD UserDefined);
//int CALL SetDLLMode( int Flag);
int SetDLLMode(int Flag);
//WORD CALL AbortCoupler( BYTE CplNum, char * host);
int AbortCoupler( int CplNum, byte[] host);
//WORD MPS_CouplerAbort (BYTE CplNum);
int MPS_CouplerAbort( int CplNum);
//WORD CALL MPS_BatchOpen( DWORD *pdwBatchId);
short MPS_BatchOpen( IntByReference pdwBatchId);
//WORD CALL MPS_Add2Batch( DWORD dwBatchId, WORD wRetCode, char *pstrRcmd);
short MPS_Add2Batch( int dwBatchId, int wRetCode, byte[] pstrRcmd);
//WORD MPS_AddResponse2Batch ( DWORD dwBatchId, char *pstrRcmd);
short MPS_AddResponse2Batch ( int dwBatchId, byte[] pstrRcmd);
//WORD CALL MPS_ExecuteBatch( DWORD dwBatchId, DWORD dwExecutionMode, DWORD *pdwFaulthyLine);
short MPS_ExecuteBatch( int dwBatchId, int dwExecutionMode, IntByReference pdwFaultyLine);
//WORD CALL MPS_CloseBatch( DWORD dwBatchId) ;
short MPS_CloseBatch( int dwBatchId) ;
//int CALL SelectActiveDevice(DWORD dwActDev);
short SelectActiveDevice(int dwActDev);
//WORD StartDownloadTo (BYTE CplNum, char * pFileName)
short StartDownloadTo (int CplNum, byte[] pFileName);
//WORD CALL MPS_EndDownload (BYTE CplNum);
short MPS_EndDownload(int CplNum);
/*-----------------*
* Concurrent mode *
*-----------------*/
//WORD CALL MPS_IsoOpen (BYTE CplNum);
//WORD CALL MPS_IsoClose (BYTE CplNum);
//WORD CALL MPS_SpyOpen (BYTE CplNum);
short MPS_SpyOpen(int CplNum);
//WORD CALL MPS_SpyClose (BYTE CplNum);
short MPS_SpyClose(int CplNum);
/*------------*
* Spy module *
*------------*/
//WORD CALL MPS_OpenLog (BYTE CplNum, DWORD mask_event, DWORD Reserved);
short MPS_OpenLog (int CplNum, int mask_event, int Reserved);
/*
WORD CALL MPS_SetUserEvent( BYTE CplNum, BYTE UserEventNum);
#define USER_EVENT1 0
#define USER_EVENT2 1
#define USER_EVENT3 2
#define USER_EVENT4 3
#define USER_EVENT5 4
#define USER_EVENT6 5
#define USER_EVENT7 6
#define USER_EVENT8 7
WORD CALL MPS_TriggerOut (BYTE CplNum, DWORD Event, DWORD Rfu);
#define MSK_TRIGOUT_EVENT 0x0000FFFF
#define TRIGOUT_NO_EVENT 0
#define TRIGOUT_C1 1
#define TRIGOUT_C2 2
#define TRIGOUT_C3 3
#define TRIGOUT_C4 4
#define TRIGOUT_C6 5
#define TRIGOUT_C7 6
#define TRIGOUT_C8 7
#define TRIGOUT_SWP_S2 8
#define TRIGOUT_SWP_S1_LOGIC 17
#define TRIGOUT_SWP_S2_LOGIC 18
#define TRIGOUT_CARD_DETECTION 21
#define TRIGOUT_ISO_SENSE_OUT 22 // IFD to ICC
#define TRIGOUT_ISO_SENSE_IN 23 // ICC to IFD
#define TRIGOUT_SWP_UICC_SOF 32
#define TRIGOUT_SWP_CLF_SOF 33
#define TRIGOUT_SWP_UICC_EOF 34
#define TRIGOUT_SWP_CLF_EOF 35
#define TRIGOUT_TRIGGER_IN 36
#define TRIGOUT_USB_SYNC 39
#define TRIGOUT_USB_EOP 40
#define TRIGOUT_MDR_IN 42
#define TRIGOUT_TTL_IN1 44
#define TRIGOUT_TTL_IN2 45
#define TRIGOUT_TTL_IN3 46
#define TRIGOUT_CLOCK_DETECTION 47
// Following events can be activated on a specific character value
#define TRIGOUT_ISO_CHAR_IFD 28
#define TRIGOUT_ISO_CHAR_ICC 29
#define TRIGOUT_SWP_CHAR_CLF 30
#define TRIGOUT_SWP_CHAR_UICC 31
#define TRIGOUT_SWP_CHAR_USB 41
#define MSK_TRIGOUT_CHAR_VALUE 0xFF000000
WORD CALL MPS_FlushLog( BYTE CplNum);
*/
//WORD CALL MPS_CloseLog( BYTE CplNum);
short MPS_CloseLog( int CplNum);
//WORD CALL MPS_LogClockSelect( BYTE CplNum, WORD Mode);
short MPS_LogClockSelect( int CplNum, int Mode);
//WORD CALL MPS_SetClkDiv( BYTE CplNum, DWORD value);
short MPS_SetClkDiv( int CplNum, int value);
/*
WORD CALL MPS_VccSpyStepSelect( BYTE CplNum, DWORD Pin, long StepValue);
#define VCC_SPY_MIN 10
#define VCC_SPY_MAX 5000
WORD CALL MPS_IccSpyStepSelect( BYTE CplNum, DWORD Pin, DWORD Range, long StepValue);
WORD CALL MPS_LaunchDownload (BYTE CplNum, DWORD reserved, char *target);
WORD CALL MPS_EndDownload (BYTE CplNum);
WORD CALL MPS_SetSpyMode( BYTE CplNum, DWORD Mode);
#define SPY_MODE_INTERNAL 1
#define SPY_MODE_EXTERNAL 2
WORD CALL MPS_SetSpySensitivity( BYTE CplNum, DWORD State);*/
//WORD MPS_LedOn( BYTE LedNum, BYTE Colour);
short MPS_LedOn(int LedNum, int Colour);
//WORD MPS_LedOff(BYTE LedNum);
short MPS_LedOff(int LedNum);
//WORD CALL MPS_OnCmm( BYTE CplNum, DWORD Frequency, WORD *pATRLg, BYTE *pATRBuf);
short MPS_OnCmm(int CplNum, int Frequency, ShortByReference pATRLg, byte[] pATRBuf);
//WORD CALL MPS_OffCmm( BYTE CplNum);
short MPS_OffCmm(int CplNum);
//
// WORD CALL MPS_SendAPDU( BYTE CplNum, DWORD Command, DWORD Lc, BYTE *pLcField, DWORD Le, BYTE *pLeField, DWORD *pLeFieldLen, WORD *SW1SW2);
short MPS_SendAPDU( int CplNum, int Command, int Lc, byte[] pLcField,
int Le, byte[] pLeField, LongByReference pLeFieldLen,IntByReference SW1SW2);
//
//WORD CALL MPS_SendPPS2 (BYTE CplNum, DWORD PPS, BYTE *pPPSResponse);
//WORD CALL MPS_SendIFSRequest( BYTE CplNum, BYTE IFSValue);
//
//// Change protocol parameters
//WORD CALL MPS_ChangeProtocolParameters( BYTE CplNum, DWORD TypeParam, void *Param, DWORD ParamSize);
//WORD CALL MPS_GetProtocolParameters( BYTE CplNum, DWORD TypeParam, void *Param, DWORD SizeofParam, DWORD *pParamSize);
short MPS_GetProtocolParameters( int CplNum, int TypeParam, Pointer Param, int SizeofParam, LongByReference pParamSize);
//static public final int CPP_IFSC 1 // Force IFSC value
//static public final int CPP_IFSD 2 // Force IFSD value
//static public final int CPP_SIM_ATR 3 // Change ATR specification
//static public final int CPP_INITIAL_WAITING_TIME 4 // Force initial waiting time (9600 ETU) with another value
//static public final int CPP_ATR_LEN 5 // For no ISO ATR specify ATR length
//static public final int CPP_INITIAL_ETU 6 // Change initial ETU for next MPS_OnCmm
//static public final int CPP_MAX_CLK_ATR 10 // Clock count after reset before card mute
//static public final int CPP_CLK_RST 11 // Clock count where RST is low
//static public final int CPP_STANDARD_USED 12 // Change the standard used
// static public final int STD_ISO_7816 0 // Standard ISO 7816
// static public final int STD_EMV_2000 1 // Standard EMV 2000
// static public final int STD_3GPP 2 // Standard 3GPP
//static public final int CPP_ERROR_SIGNAL 14 // Enable/Disable error signal handling
//static public final int CPP_CWT 15 // Change CWT in ETU
//static public final int CPP_BWT 16 // Change BWT in ETU
//static public final int CPP_WWT 17 // Change WWT in ETU
//static public final int CPP_BGT 18 // Change BGT in ETU
//static public final int CPP_EGT 19 // Change EGT in ETU
//static public final int CPP_RGT 20 // Change RGT in ETU
//static public final int CPP_PROTOCOL_TIMEOUT 21 // Enable/Disable protocol timeout IWT,WWT,BWT et CWT
//static public final int CPP_CURRENT_F_D 22 // Change and apply current F/D factor
//static public final int CPP_TIMEOUT_NULL_BYTE 23 // NULL byte timeout in T=0 protocol
//static public final int CPP_RGT1 24 // Change RGT1 in C3 clock count
//static public final int CPP_RGT2 25 // Change RGT2 in C3 clock count
//static public final int CPP_CHECK_ATR 28 // ON or OFF for enable/disable ATR analyze
//static public final int CPP_POWER_OFF_ON_ATR_ERROR 29 // ON or OFF for enable power off on ATR analyze error
//static public final int CPP_CURRENT_PROTOCOL 31 // Protocol in use (T=0 ou T=1)
//static public final int CPP_C6CONTROL 33 // control behaviour of C6 during activation/deactivation
//static public final int CPP_CURRENT_ETU 34
//
///*-----------------------------------------------*
// * Setting voltages and miscellaneous parameters *
// *-----------------------------------------------*/
//WORD CALL MPS_VCCSelectMV( BYTE CplNum, short ValVcc);
short MPS_VCCSelectMV(int CplNum, int ValVcc);
//static public final int VCC_MIN_MV 0L // 0 volts
//static public final int VCC_MAX_USB_IC 3600 // +3.6 volts max in USB-IC mode
//static public final int VCC_MAX_MV 6000L // +6 volts
//
//
//WORD CALL MPS_SetPullup(BYTE CplNum, BYTE PinNum, DWORD Pullup);
//static public final int PULLUP_IO_OFF 0 // Without pullup
//static public final int PULLUP_IO_5K 5000
//static public final int PULLUP_IO_22K 22000
//static public final int PULLUP_IO_INFINITE 1000000
//
//
//WORD CALL MPS_FrequencySelect( BYTE CplNum, DWORD Frequency);
short MPS_FrequencySelect(int CplNum, int Frequency);
//static public final int FREQ_MIN 500000
//static public final int FREQ_MAX 10000000
//WORD MPS_ClockStop( BYTE CplNum, DWORD TgClockCount, DWORD ThClockCount,DWORD PinState);
short MPS_ClockStop( int CplNum, int TgClockCount, int ThClockCount,int PinState);
/*-----------*
* Sequencer *
*-----------*/
// Additional pin state
static public final int CLOCK_APPLIED= 11;
static public final int CLOCK_STOP_HIGH=12;
static public final int CLOCK_STOP_LOW= 13;
static public final int CLOCK_RESUME= 14;
//WORD MPS_CardDetect( BYTE CplNum);
short MPS_CardDetect(int CplNum);
}
// Resources ID define
public static final int SIMULATOR= 0x100; // For MP300SC1 only
public static final int SPY= 0x200; // For MP300TC3 only
public static final int PORT_SERIAL1= 1;
public static final int PORT_SERIAL2= 2;
public static final int PORT_USB_EP1= 101;
public static final int PORT_USB_EP2= 102;
public static final int C1= 201;
public static final int C2= 207;
public static final int C3= 67;
public static final int CSWP= 224;
public static final int MC1= 228;
public static final int TC1= 202;
public static final int TC2= 205;
public static final int TC3= 131;
public static final int CL1= 203;
public static final int CL2= 206;
public static final int TCL1= 120;
public static final int TCL2= 122;
public static final int MHC6= 204;
public static final int SWPSPY= 232;
public static final int SC1= (SIMULATOR | SWPSPY);
public static final int MT1= 210;
public static final int SCL1= 200;
public static final int TPC1= 208;
static protected Throwable initException;
static protected final Win32Mp300ComDll win32Mp300ComDll;
static private final int RES_ID = MP65;
static transient Map<String,Integer> couplers;
static final String ARG_HELP = "-help";
static final int ARG_HELP_ID = 0;
static final String ARG_ADD_COM_PORT = "-addComPort:";
static final int ARG_ADD_COM_PORT_ID = 1;
static final String ARG_ADD_COUPLER = "-addCoupler:";
static final int ARG_ADD_COUPLER_ID = 2;
static final String CONF_FILE_NAME="Mp65TerminalManager.conf";
//static final String DEFAULT_IP="USB";
//static final String DEFAULT_MP300_DLL="MP300Com_forNimp";//MP300COM";//we should offer a way to override this in future
static final String DEFAULT_MP300_DLL="MP300COM";
static final String DEFAULT_COM="USB";//could be something like "USB:MSQ.08.46.27" if we want to work only with this MP65
static final int DEFAULT_COUPLER=0;
static final int DLL_MODE=2;//allow to work with several MP65, but does not work anymore after MPManager2.0 installed
//static final int DLL_MODE=0;
static {
Throwable ex;
Win32Mp300ComDll trial;
try {
//throw new RuntimeException("MP65 DLL disabled for test");
couplers=new HashMap<String,Integer>();
Map<String, Object> options = new HashMap<String, Object>();
options.put(Library.OPTION_FUNCTION_MAPPER, new StdCallFunctionMapper());
//trial = (Win32Mp300ComDll) Native.loadLibrary("C:\\MP300COM.dll", Win32Mp300ComDll.class);
trial = (Win32Mp300ComDll) Native.loadLibrary(DEFAULT_MP300_DLL, Win32Mp300ComDll.class, options);
trial=(Win32Mp300ComDll) Native.synchronizedLibrary(trial);
ex = null;
} catch (Throwable e) {
ex = e;
trial = null;
}
win32Mp300ComDll = trial;
initException = ex;
if(null==ex){
try {
initContext();
} catch (ScardException ex1) {
initException = ex1;
//Logger.getLogger(MP65TerminalManager.class.getName()).log(Level.SEVERE, null, ex1);
}
}
}
static void cleanupCoupler(int deviceId,int couplerId){
try {
int status=win32Mp300ComDll.SelectActiveDevice(deviceId);
if (RET_OK != status) {
System.out.println("SelectActiveDevice returned " + status);
//throw new ScardException("MPOS_CloseResource returned " + status);
}
status=win32Mp300ComDll.MPOS_CloseResource(RES_ID, couplerId);
if (RET_OK != status) {
System.out.println("MPOS_CloseResource returned " + status);
//throw new ScardException("MPOS_CloseResource returned " + status);
}
} catch (Throwable e) {
}
}
static public void initContext() throws ScardException {
//System.out.println("win32Mp300ComDll=" + win32Mp300ComDll);
if (null != initException) {
throw new ScardException("", initException);
}
if(2==DLL_MODE){
int status = win32Mp300ComDll.SetDLLMode(DLL_MODE);
if (RET_OK != status) {
throw new MP300Exception("SetDLLMode failed", status);
}
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
{
//release all resources
for(Entry<Integer, Integer>coupler:toClean.entrySet()){
cleanupCoupler(coupler.getKey(),coupler.getValue());
}
}
}
});
}
protected String getConfFileName(){
return CONF_FILE_NAME;
}
@Override
protected void loadConfigurationImpl(File argFile) throws Exception {
if(null!=initException)
throw new Exception(initException);
if(null==win32Mp300ComDll)
throw new NullPointerException(DEFAULT_MP300_DLL+" could not be loaded");
try{
if(argFile.exists()){
ArrayList<String> argList=ACommandLineUtilities.processArgFile(argFile);
if((null==argList) || argList.isEmpty())
return;
String args[] = new String[argList.size()];
argList.toArray(args);
Integer curArgIndex = null;
Arg curArg = null;
curArgIndex = 0;
ArgSpec argSpecs[] = {
new ArgSpec(ARG_HELP, ARG_HELP_ID),
new ArgSpec(ARG_ADD_COM_PORT, ARG_ADD_COM_PORT_ID, ArgSpec.UNLIMITED_OCCURENCE),
new ArgSpec(ARG_ADD_COUPLER, ARG_ADD_COUPLER_ID, ArgSpec.UNLIMITED_OCCURENCE),
};
Set<ArgSpec> specs=ACommandLineUtilities.addArgFileArgSpecs(argSpecs);
argSpecs=new ArgSpec[specs.size()];
specs.toArray(argSpecs);
args = ACommandLineUtilities.processArgFile(new File("").getAbsoluteFile(), args);
ACommandLineUtilities.checkArgs(args, argSpecs);
String curPort=DEFAULT_COM;
while (curArgIndex < args.length) {
curArg = ACommandLineUtilities.getArg(args, argSpecs, curArgIndex, null);
if(null!=curArg){
switch (curArg.id) {
case ARG_HELP_ID:
StringBuilder sb=new StringBuilder();
sb.append("Mp65TerminalManager configuration file help\n\n");
sb.append(ARG_ADD_COM_PORT);
sb.append("<name of port>\n");
sb.append("Add a port. Typical name looks like \"USB\", \"USB:MSQ.08.46.31\" and so on\n");
System.out.println(sb.toString());
break;
case ARG_ADD_COM_PORT_ID:
curPort=curArg.value;
couplers.put(curPort, DEFAULT_COUPLER);
break;
}
}
curArgIndex++;
}
}else{
couplers.put(DEFAULT_COM, DEFAULT_COUPLER);
}
}catch(Throwable e){
throw new RuntimeException("Exception occured during processing of configuration file below\n"+argFile.getAbsolutePath()+"\n", e);
}
}
@Override
public List<GenericTerminal> list() throws ScardException {
List<GenericTerminal> terminalsList = new ArrayList<GenericTerminal>();
if(null!=initException)
return Collections.unmodifiableList(terminalsList);
/*win32Mp300ComDll.MPS_LedOff(LED1);
win32Mp300ComDll.MPS_LedOn(LED1, LED_RED);
win32Mp300ComDll.MPS_LedOff(LED1);
win32Mp300ComDll.MPS_LedOn(LED1, LED_ORANGE);
win32Mp300ComDll.MPS_LedOff(LED1);
win32Mp300ComDll.MPS_LedOn(LED1, LED_GREEN);*/
for(Entry<String, Integer>coupler:couplers.entrySet()){
try {
GenericTerminal terminal = getTerminalImpl(RES_ID, coupler.getKey(), coupler.getValue());
terminalsList.add(terminal);
} catch (MP300Exception e) {
}
}
//listDone = true;//attempt connection only once
return Collections.unmodifiableList(terminalsList);
}
public static String resourceId2Name(int resourceId){
switch(resourceId){
case MP65:
return "MP65";
case TC3:
return "MP300TC3";
default:
throw new RuntimeException("unknown resourceId: "+ resourceId);
}
}
public static void main(String[] args) throws MP300Exception, ScardException {
//String host="192.168.107.80";
//String host="192.168.107.80:MP65";
//String host="10779:192.168.107.80";
//String host="MP65:192.168.107.80";
String host="USB:MSQ.08.46.31";
//String host="10779:MP65";
int couplerId=0;
int deviceId = 0;
int resourceId=RES_ID;
byte[] readerBytes = AStringUtilities.StringToBytesWithFinalNull(host);
int status = win32Mp300ComDll.OpenCommunication(readerBytes);
if (RET_OK != status)
throw new MP300Exception("Fail to establish communication with " + host, status);
status = win32Mp300ComDll.MPOS_OpenResource(resourceId, couplerId, OVERRIDE);
if (RET_OK != status)
throw new MP300Exception("Fail to establish communication with " + host, status);
status = win32Mp300ComDll.MPS_ResetHard(couplerId);
if (RET_OK != status) throw new MP300Exception("Fail to establish communication with " + host, status);
SCardSetVdd(deviceId,couplerId,5000);
status = win32Mp300ComDll.MPS_CardDetect(couplerId);
GenericTerminal.State out;
switch (status) {
case RET_OK:
out = GenericTerminal.State.CARD_PRESENT;
break;
case CRET_ABSENT:
out = GenericTerminal.State.CARD_ABSENT;
break;
default:
throw new MP300Exception("MPS_CardDetect failed", status);
}
System.out.println(out);
win32Mp300ComDll.CloseCommunication();
}
private static final Map<String, Reference<GenericTerminal>> terminals = new HashMap<String, Reference<GenericTerminal>>();
private static final Map<Integer, Integer> toClean = new HashMap<Integer, Integer>();
private static int nextDeviceId=0;
private static int currentDeviceId=0;
//static boolean listDone = false;
protected static synchronized GenericTerminal getTerminalImpl(int resourceId, String host, int couplerId) throws ScardException {
String name = resourceId2Name(resourceId)+" on "+ host + " coupler " + couplerId;
Reference<GenericTerminal> ref = terminals.get(name);
GenericTerminal terminal = (ref != null) ? ref.get() : null;
if (terminal != null) {
try{
terminal.isCardPresent();
return terminal;
}catch(Throwable e){
terminals.remove(name);
MP65Terminal mp65 = (MP65Terminal) terminal;
cleanupCoupler(mp65.deviceId,mp65.couplerId);
System.out.println("MP65 disconnected, to use it again, please restart the application.");
return null;
}
} //else if(listDone) return null;
int status;
int bu=win32Mp300ComDll.GetDLLTimeOutValue();
try{
win32Mp300ComDll.SetDLLTimeOutValue(1);
currentDeviceId=nextDeviceId;
if(2==DLL_MODE){
status = win32Mp300ComDll.SelectActiveDevice(currentDeviceId);
if (RET_OK != status)
throw new MP300Exception("SelectActiveDevice failed: ", status);
}
byte[] readerBytes = AStringUtilities.StringToBytesWithFinalNull(host);
status = win32Mp300ComDll.OpenCommunication(readerBytes);
if (RET_OK != status)
throw new MP300Exception("Fail to establish communication with " + host, status);
status = win32Mp300ComDll.MPOS_OpenResource(resourceId, couplerId, OVERRIDE);
if (RET_OK != status)
throw new MP300Exception("Fail to establish communication with " + host, status);
status = win32Mp300ComDll.MPS_ResetHard(couplerId);
if (RET_OK != status) throw new MP300Exception("Fail to establish communication with " + host, status);
toClean.put(currentDeviceId, couplerId);
nextDeviceId++;
switch(resourceId){
case MP65:
terminal = new MP65Terminal(currentDeviceId, couplerId, name, readerBytes);
break;
case TC3:
terminal = new MP300TC3Terminal(currentDeviceId, couplerId, name,readerBytes);
break;
}
terminals.put(name, new WeakReference<GenericTerminal>(terminal));
}finally{
win32Mp300ComDll.SetDLLTimeOutValue(bu);
}
return terminal;
}
static synchronized void setDeviceId(int deviceId) throws MP300Exception{
if(2==DLL_MODE){
if(deviceId!=currentDeviceId){
int status = win32Mp300ComDll.SelectActiveDevice(deviceId);
if (RET_OK != status) throw new MP300Exception("SelectActiveDevice failed: ", status);
currentDeviceId=deviceId;
}
}
}
static synchronized void SCardSetVdd(int deviceId, int couplerId, int vddMillivolts) throws ScardException {
int status;
setDeviceId(deviceId);
status = win32Mp300ComDll.MPS_VCCSelectMV(couplerId, vddMillivolts);
if (RET_OK != status) {
throw new MP300Exception("MPS_VCCSelectMV failed. deviceId = "+deviceId+", couplerId="+couplerId+", vddMillivolts = "+vddMillivolts, status);
}
}
static synchronized void SCardSetClk(int deviceId, int couplerId, int clkHertz) throws ScardException {
int status;
setDeviceId(deviceId);
status = win32Mp300ComDll.MPS_FrequencySelect(couplerId, clkHertz);
if (RET_OK != status) {
throw new MP300Exception("MPS_FrequencySelect failed", status);
}
}
static synchronized void SCardClkStop(int deviceId, int couplerId,int TgClockCount, int ThClockCount,int PinState) throws ScardException {
int status;
setDeviceId(deviceId);
status = win32Mp300ComDll.MPS_ClockStop(couplerId, TgClockCount, ThClockCount, PinState);
if (RET_OK != status) {
throw new MP300Exception("MPS_ClockStop failed", status);
}
}
//static AnswerToReset SCardConnect(int couplerId, int vddMillivolts, int clkHertz, int protocol) throws ScardException {
static synchronized AnswerToReset SCardConnect(int deviceId, int couplerId, int clkHertz, int protocol, boolean autoPps) throws ScardException {
setDeviceId(deviceId);
switch (protocol) {
case GenericTerminal.PROTOCOL_T_0:
//connectProtocol = SCARD_PROTOCOL_T0;
break;
case GenericTerminal.PROTOCOL_T_1:
//connectProtocol = SCARD_PROTOCOL_T1;
break;
case GenericTerminal.PROTOCOL_ANY:
//connectProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
break;
case GenericTerminal.PROTOCOL_DIRECT:
case GenericTerminal.PROTOCOL_T_15:
case GenericTerminal.PROTOCOL_T_CL_A:
case GenericTerminal.PROTOCOL_T_CL_B:
case GenericTerminal.PROTOCOL_ANY_STD_CL:
default:
throw new IllegalArgumentException("protocol = " + GenericTerminal.getProtocolName(protocol));
}
ShortByReference atrLenRef = new ShortByReference();
atrLenRef.setValue((short) 256);
int status;
byte atrBuf[] = new byte[256];
/*status = win32Mp300ComDll.MPS_VCCSelectMV(couplerId, vddMillivolts);
if (RET_OK != status) {
throw new MP300Exception("MPS_VCCSelectMV failed, couplerId="+couplerId+", vddMillivolts="+vddMillivolts, status);
}*/
status = win32Mp300ComDll.MPS_OnCmm(couplerId, clkHertz, atrLenRef, atrBuf);
if (RET_OK != status) {
throw new MP300Exception("MPS_OnCmm failed", status);
}
short len = atrLenRef.getValue();
AnswerToReset out=new AnswerToReset(atrBuf,0,len);
if(autoPps && out.acceptPps() && (out.getSupportedFiDi()!=0x11)){
byte ppsBuf[] = new byte[10];
for (int i = 0; i < ppsBuf.length; i++) {
ppsBuf[i] = 0;
}
int pps=0x10000000+(out.getSupportedFiDi()<<16);
if(GenericTerminal.PROTOCOL_T_1==protocol)
pps|=0x01000000;
status = win32Mp300ComDll.MPS_SendPPS2(couplerId, pps, ppsBuf);
if (RET_OK != status) {
throw new MP300Exception("MPS_SendPPS2 failed",status);
}
}
return out;
}
static synchronized Apdu.CardResponse SCardTransmit(int deviceId, int couplerId, int command, byte[] lcData, int le) throws ScardException {
setDeviceId(deviceId);
LongByReference actualLeByRef= new LongByReference();
actualLeByRef.setValue(le);
IntByReference internalSw=new IntByReference();
internalSw.setValue(0);
byte[] leData=new byte[le];
int internalLe=le;
if(0==le)
internalLe=NO_LE;
if(256==le)
internalLe=0;
int lc=lcData.length;
if(0==lc)
lc=NO_LC;
int status = win32Mp300ComDll.MPS_SendAPDU( couplerId, command, lc, lcData,
internalLe, leData, actualLeByRef,internalSw);
if (RET_OK != status) {
throw new MP300Exception("MPS_SendAPDU failed",status);
}
int actualLe=(int)actualLeByRef.getValue();
//if(actualLe!=internalLe){
if(actualLe!=le){
byte[] actualLeData=new byte[actualLe];
for(int i=0;i<actualLe;i++)
actualLeData[i]=leData[i];
leData=actualLeData;
}
Apdu.CardResponse out=new Apdu.CardResponse(leData,(short)internalSw.getValue());
return out;
}
static synchronized void SCardDisconnect(int deviceId, int couplerId) throws MP300Exception {
setDeviceId(deviceId);
int status = win32Mp300ComDll.MPS_OffCmm(couplerId);
if (RET_OK != status) {
throw new MP300Exception("MPS_OffCmm failed",status);
}
}
static void SCardForceDisconnection(int deviceId, int couplerId) throws MP300Exception {
setDeviceId(deviceId);
//int status = win32Mp300ComDll.MPS_CouplerAbort(couplerId);//more complicate to use, we need to use OpenComm and CloseComm
int status = win32Mp300ComDll.AbortCoupler(couplerId,null);
if (RET_OK != status) {
throw new MP300Exception("AbortCoupler failed",status);
}
}
static synchronized GenericTerminal.State SCardIsPresent(int deviceId, int couplerId) throws ScardException {
setDeviceId(deviceId);
int status = win32Mp300ComDll.MPS_CardDetect(couplerId);
GenericTerminal.State out;
switch (status) {
case RET_OK:
out = GenericTerminal.State.CARD_PRESENT;
break;
case CRET_ABSENT:
out = GenericTerminal.State.CARD_ABSENT;
break;
default:
throw new MP300Exception("MPS_CardDetect failed", status);
}
return out;
}
static public final int NO_LC= 0x80000000; // No Lc field in CAPDU
static public final int LC_EXTENDED= 0x40000000; // Extended Lc field in CAPDU
static public final int NO_LC_SEND= 0x20000000; // The Lc field is not transmit
//
static public final int NO_LE = 0x80000000; // No Le field in CAPDU
static public final int LE_EXTENDED= 0x40000000; // Extended Le field in CAPDU
static public final int NO_LE_SEND= 0x20000000; // The Le field is not transmit
static public final int BATCH_EXECUTE_STOP_ON_ERROR=0;
static public final int BATCH_EXECUTE_IGNORE_ERRORS=1;
///*******************
// * SYSTEM API CALL *
// *******************/
//// Define programming head number
//static public final int CPL0 0
//static public final int CPL1 1
//static public final int CPL2 2
//static public final int CPL3 3
//static public final int CPL4 4
//static public final int CPL5 5
//static public final int CPL6 6
//static public final int CPL7 7
//static public final int CPL8 8
//static public final int CPL9 9
//static public final int CPL10 10
//static public final int CPL11 11
//
//// Define for SLOT number
//static public final int SLOT_A 0
//static public final int SLOT_B 1
//static public final int SLOT_C 2
//static public final int SLOT_D 3
static public final int LED1 = 1;
static public final int LED_RED = 0;
static public final int LED_GREEN = 1;
static public final int LED_ORANGE = 2;
static public final int LED_OFF = 3;
static public final int LED_MAX = 2;
static public final int SEM_MODE_WAIT = 1;
static public final int SEM_MODE_NO_WAIT = 0;
// Blocking mode
static public final int BLOCKING = SEM_MODE_WAIT;
static public final int NOT_BLOCKING = SEM_MODE_NO_WAIT;
static public final int CONCURRENT_MODE = 2; // Only for CSWP, MC1, TC2, TC3
static public final int OVERRIDE = 3;
void batchInterfaceTest() throws ScardException {
int status=0;
IntByReference pdwBatchId=new IntByReference();
status=win32Mp300ComDll.MPS_BatchOpen(pdwBatchId);
if (RET_OK != status) {
throw new ScardException("MPS_BatchOpen returned " + status);
}
int batchId=pdwBatchId.getValue();
String command="CPSR 0 5 008A004402 05";
//String command="CPSA 0 008C0000 00000002 01EF";
status=win32Mp300ComDll.MPS_Add2Batch(batchId, 0, AStringUtilities.StringToBytes(command));
if (RET_OK != status) {
throw new ScardException("MPS_Add2Batch returned " + status);
}
String expected="CPSR 0 5 8A00089000";
//String expected="CPSA 0000";
status=win32Mp300ComDll.MPS_AddResponse2Batch(batchId, AStringUtilities.StringToBytes(expected));
if (RET_OK != status) {
throw new ScardException("MPS_AddResponse2Batch returned " + status);
}
IntByReference pdwFaultyLine=new IntByReference();
status=win32Mp300ComDll.MPS_ExecuteBatch(batchId, BATCH_EXECUTE_STOP_ON_ERROR, pdwFaultyLine);
if (RET_OK != status) {
throw new ScardException("MPS_ExecuteBatch returned " + status + "\n" +
"pdwFaultyLine="+pdwFaultyLine.getValue());
}
status=win32Mp300ComDll.MPS_CloseBatch(batchId);
if (RET_OK != status) {
throw new ScardException("MPS_CloseBatch returned " + status);
}
}
}