From a60ec5ab413ef674ac3b9244d2b971dbc64682d9 Mon Sep 17 00:00:00 2001 From: jdkbx Date: Wed, 7 Apr 2010 21:22:45 +0200 Subject: [PATCH] added possiblility to switch between rfcomm and l2cap in the source --- src/nfc/BluetoothNFCReader.java | 362 ++++++++++++++++++++++++++++------------ 1 file changed, 252 insertions(+), 110 deletions(-) diff --git a/src/nfc/BluetoothNFCReader.java b/src/nfc/BluetoothNFCReader.java index c435347..79e6b65 100644 --- a/src/nfc/BluetoothNFCReader.java +++ b/src/nfc/BluetoothNFCReader.java @@ -38,7 +38,10 @@ import javax.microedition.contactless.TargetListener; import javax.microedition.contactless.TargetProperties; import javax.microedition.contactless.TargetType; import javax.microedition.contactless.sc.ISO14443Connection; +import javax.microedition.io.Connection; import javax.microedition.io.Connector; +import javax.microedition.io.StreamConnection; +import javax.microedition.io.StreamConnectionNotifier; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; @@ -121,17 +124,28 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, private List deviceList; /** Bluetooth RFCOMM connection abstraction. */ - private L2CAPConnection connection; + private L2CAPConnection connectionL2CAP; + + private StreamConnection connectionRFCOMM; + + boolean USE_L2CAP = false; + boolean USE_FRAGMENTATION = true; //UUID SPP_UUID = new UUID("1101", true); /** Service UUID. */ private static final long SRV_UUID = 0x0100; + + UUID SPP_UUID = new UUID("1101", true); + /** actual Service name. */ private static final String SRV_NAME = "SPPServer1"; /** url needed to publish service. */ - private String serviceURL = + private String serviceURLL2CAP = "btl2cap://localhost:" + new UUID(SRV_UUID).toString() + ";name=" + SRV_NAME; + private String serviceURLRFCOMM = + "btspp://localhost:" + SPP_UUID + + ";name=" + SRV_NAME; /** holds APDU communication. */ private byte[] buffer; @@ -422,6 +436,7 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, } else if (cmd == cmdRemove) { disconnectCard(formError, true); startSmartCardDiscovery(); + resetFormError(); resetFormReader(); resetFormConnect(); display.setCurrent(formConnect); @@ -466,13 +481,21 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, resetFormStart(); isWaitingEvent = false; r.kill(); - if (connection != null) { + if (connectionL2CAP != null) { + try { + connectionL2CAP.close(); + } catch (IOException e) { + e.printStackTrace(); + } + connectionL2CAP = null; + } + if (connectionRFCOMM != null) { try { - connection.close(); + connectionRFCOMM.close(); } catch (IOException e) { e.printStackTrace(); } - connection = null; + connectionRFCOMM = null; } display.setCurrent(formStart); } @@ -488,18 +511,32 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, try { LocalDevice btDevice = LocalDevice.getLocalDevice(); btDevice.setDiscoverable(DiscoveryAgent.GIAC); - - L2CAPConnectionNotifier notifier = - (L2CAPConnectionNotifier) Connector.open(serviceURL); - formServerStart.append(">>waiting for connection on\n" - + serviceURL + "\n"); -// formServerStart.wait(); - connection = notifier.acceptAndOpen(); -// RemoteDevice rDev = RemoteDevice.getRemoteDevice(connection); -// formServerStart.append(">>remote address: " -// + rDev.getBluetoothAddress() + "\n"); -// formServerStart.append(">>remote name: " -// + rDev.getFriendlyName(true) + "\n"); + + if (USE_L2CAP == true) { + L2CAPConnectionNotifier notifier = + (L2CAPConnectionNotifier) Connector.open(serviceURLL2CAP); + formServerStart.append(">>waiting for connection on\n" + + serviceURLL2CAP + "\n"); + // formServerStart.wait(); + connectionL2CAP = notifier.acceptAndOpen(); + // RemoteDevice rDev = RemoteDevice.getRemoteDevice(connection); + // formServerStart.append(">>remote address: " + // + rDev.getBluetoothAddress() + "\n"); + // formServerStart.append(">>remote name: " + // + rDev.getFriendlyName(true) + "\n"); + } else { + StreamConnectionNotifier notifier2 = + (StreamConnectionNotifier) Connector.open(serviceURLRFCOMM); + formServerStart.append(">>waiting for connection on\n" + + serviceURLL2CAP + "\n"); + // formServerStart.wait(); + connectionRFCOMM = notifier2.acceptAndOpen(); + // RemoteDevice rDev = RemoteDevice.getRemoteDevice(connection); + // formServerStart.append(">>remote address: " + // + rDev.getBluetoothAddress() + "\n"); + // formServerStart.append(">>remote name: " + // + rDev.getFriendlyName(true) + "\n"); + } startSmartCardDiscovery(); @@ -832,9 +869,9 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, /** constant to check for 0x01. */ private final byte[] ONE_BYTES = new byte[] {(byte) 1}; /** buffer size limit. */ - private static final short BUFFER_SIZE = 258; + private static final short BUFFER_SIZE = 32767; /** max APDU size. */ - private static final short MAX_APDU_SIZE = 255; + private static final short MAX_APDU_SIZE = BUFFER_SIZE - 2; /** byte mask for converting 0xFF. */ private static final int BYTE_MASK = 0xFF; @@ -865,58 +902,85 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, buffer = new byte[BUFFER_SIZE]; byte[] cardResponse; byte[] response; - byte[] responseLength = new byte[1]; - + //byte[] responseLength = new byte[2]; + + OutputStream os = null; + InputStream is = null; + try { -// OutputStream os = connection.openOutputStream(); -// InputStream is = connection.openInputStream(); + if (USE_L2CAP == false) { + os = connectionRFCOMM.openOutputStream(); + is = connectionRFCOMM.openInputStream(); + } int realLen, readLen, offset, len = 0; + short hangcheck = 0; // reader loop while (!end) { realLen = -1; readLen = 0; len = 0; + hangcheck = 0; - // get input (this loop is probably completely useless) - while (readLen != realLen) { - len = connection.receive(buffer); -// , realLen + 1, -// MAX_APDU_SIZE - readLen); - - if (len < 1) { - try { - sleep(10); - } catch (InterruptedException e) { - formReader.append("ending\n"); - return; - } - continue; - } else { - if (realLen < 1) { - realLen = (int) (buffer[0] & BYTE_MASK); - readLen += len - 1; - } else { - readLen += len; - } - } - } - + if (USE_L2CAP == true) { + // get input (this loop is probably completely useless) + while (readLen != realLen) { + if (hangcheck > 0) + formLog.append("hangcheck " + hangcheck + "\n"); + len = connectionL2CAP.receive(buffer); + // , realLen + 1, + // MAX_APDU_SIZE - readLen); + + hangcheck++; + if (len < 2) { + try { + sleep(10); + } catch (InterruptedException e) { + formReader.append("ending\n"); + return; + } + continue; + } else { + if (realLen < 1) { + realLen = (int) (buffer[0] & BYTE_MASK) << 8; + realLen += (int) (buffer[1] & BYTE_MASK); + readLen += len - 2; + } else { + readLen += len; + } + } + } + } else { + // TODO error checking + len = is.read(buffer); + if (realLen < 1) { + realLen = (int) (buffer[0] & BYTE_MASK) << 8; + realLen += (int) (buffer[1] & BYTE_MASK); + readLen += len - 2; + } + + if (readLen != realLen) + formLog.append("error len in apdu:" + realLen + " recv:" + readLen + "\n"); + + if (readLen > 255) + formLog.append("extended APDU len: " + readLen + "\n"); + } + len = readLen; - offset = 1; + offset = 2; // byte[] cmd = new byte[len]; // for (int i = 0 ; i < readLen; ++i) { // cmd[i] = buffer[i + 1]; // } // write messages to screen - if (len > 1 && len != READER_CMD_LENGTH) { + if (len > 3) { // && len != READER_CMD_LENGTH) { tfReadIn.setString(">> " + len + "\n" - + toHexString(buffer, 1, 8)); + + toHexString(buffer, 2, 8)); tfWriteOut.setString(" \n "); - } - + } + // handle cmds if (len == READER_CMD_LENGTH) { //formLog.append("might have gotten cmd\n"); @@ -932,12 +996,18 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, // ATR/ATS request, will just write uid if (equal(GET_ATTR_CMD, buffer, len)) { //formLog.append(">>atr\n"); - response = new byte[uid.length() + 1]; - response[0] = (byte) (BYTE_MASK & uid.length()); + response = new byte[uid.length() + 2]; + response[0] = (byte) (BYTE_MASK & (uid.length() >> 8)); + response[1] = (byte) (BYTE_MASK & uid.length()); for (int j = 0; j < uid.length(); ++j) { - response[j + 1] = uid.getBytes()[j]; + response[j + 2] = uid.getBytes()[j]; + } + if (USE_L2CAP == true) { + connectionL2CAP.send(response); + } else { + os.write(response); + os.flush(); } - connection.send(response); continue; } @@ -948,14 +1018,20 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, */ if (equal(GET_PRESENCE_CMD, buffer, len)) { //formLog.append(">>presence\n"); - response = new byte[2]; - response[0] = (byte) 1; + response = new byte[3]; + response[0] = (byte) 0; + response[1] = (byte) 1; if (isCardPresent) { - response[1] = ONE_BYTES[0]; + response[2] = ONE_BYTES[0]; + } else { + response[2] = NULL_BYTES[0]; + } + if (USE_L2CAP == true) { + connectionL2CAP.send(response); } else { - response[1] = NULL_BYTES[0]; + os.write(response); + os.flush(); } - connection.send(response); continue; } @@ -967,10 +1043,16 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, //formLog.append(">>card_event\n"); if (isCardPresent) { - response = new byte[2]; - response[0] = (byte) 1; - response[1] = ONE_BYTES[0]; - connection.send(response); + response = new byte[3]; + response[0] = (byte) 0; + response[1] = (byte) 1; + response[2] = ONE_BYTES[0]; + if (USE_L2CAP == true) { + connectionL2CAP.send(response); + } else { + os.write(response); + os.flush(); + } isWaitingEvent = false; } else { isWaitingEvent = true; @@ -984,61 +1066,107 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, } // log APDU - tfIn.setString(toHexString(buffer, 1, len)); + tfIn.setString(toHexString(buffer, 1, len > 255 ? len : 255)); if (isCardPresent) { // relay APDU to card cardResponse = sendAPDU(buffer, offset, len); if (cardResponse != null && cardResponse.length > 0) { - if (cardResponse.length < 48) { - response = new byte[cardResponse.length + 1]; - response[0] = - (byte) (BYTE_MASK & cardResponse.length); - - for (int j = 0; j < cardResponse.length; ++j) { - response[j + 1] = cardResponse[j]; - } - - connection.send(response); - } else { - int cnt = ((cardResponse.length + 1) / 48) + 1; - response = new byte[48]; - response[0] = - (byte) (BYTE_MASK & cardResponse.length); - - for (int j = 0; j < 47; ++j) { - response[j + 1] = cardResponse[j]; - } - - connection.send(response); - int k = 1; - while (k < cnt) { - if (k == cnt - 1) { - response = new byte[(cardResponse.length % 48) + 1]; - } - for (int j = 0; j < 48 && j + ((48 * k) - 1) < cardResponse.length; ++j) { - response[j] = cardResponse[j + ((48 * k) - 1)]; + + if (USE_L2CAP == true) { + if (USE_FRAGMENTATION == true) { + if (cardResponse.length <= 48 - 2) { + response = new byte[cardResponse.length + 2]; + response[0] = 0; + response[1] = + (byte) (BYTE_MASK & cardResponse.length); + + for (int j = 0; j < cardResponse.length; ++j) { + response[j + 2] = cardResponse[j]; + } + + connectionL2CAP.send(response); + } else { + int cnt = ((cardResponse.length + 2) / 48) + 1; + response = new byte[48]; + response[0] = + (byte) (BYTE_MASK & (cardResponse.length >> 8)); + response[1] = + (byte) (BYTE_MASK & cardResponse.length); + + for (int j = 0; j < 46; ++j) { + response[j + 2] = cardResponse[j]; + } + + connectionL2CAP.send(response); + int k = 1; + while (k < cnt) { + if (k == cnt - 1) { + response = new byte[(cardResponse.length % 48) + 2]; + } + for (int j = 0; j < 48 && j + ((48 * k) - 2) < cardResponse.length; ++j) { + response[j] = cardResponse[j + ((48 * k) - 2)]; + } + + connectionL2CAP.send(response); + ++k; + } } - - connection.send(response); - ++k; + } else { + response = new byte[cardResponse.length + 2]; + response[0] = + (byte) (BYTE_MASK & (cardResponse.length >> 8)); + response[1] = + (byte) (BYTE_MASK & cardResponse.length); + + for (int j = 0; j < cardResponse.length; ++j) { + response[j + 2] = cardResponse[j]; + } + + connectionL2CAP.send(response); } - } + } else { + response = new byte[cardResponse.length + 2]; + response[0] = + (byte) (BYTE_MASK & (cardResponse.length >> 8)); + response[1] = + (byte) (BYTE_MASK & cardResponse.length); + for (int j = 0; j < cardResponse.length; ++j) { + response[j + 2] = cardResponse[j]; + } + os.write(response); + os.flush(); + } // log response - tfWriteOut.setString("<< " + cardResponse.length - + "\n" + toHexString(cardResponse, - cardResponse.length - 2, 2)); - tfOut.setString(toHexString( - cardResponse, 0, cardResponse.length)); + if (cardResponse.length >= 2) { + tfWriteOut.setString("<< " + cardResponse.length + + "\n" + toHexString(cardResponse, + cardResponse.length - 2, 2)); + tfOut.setString(toHexString( + cardResponse, 0, cardResponse.length > 255 ? 255: cardResponse.length)); + } else { + tfWriteOut.setString("<< " + cardResponse.length + + "\n" + toHexString(cardResponse, 0, 1)); + } } else { - connection.send(NULL_BYTES); + if (USE_L2CAP == true) { + connectionL2CAP.send(NULL_BYTES); + } else { + os.write(NULL_BYTES); + os.flush(); + } } } else { // this should never happen //formLog.append("nuthing done\n"); - connection.send(NULL_BYTES); + if (USE_L2CAP == true) { + connectionL2CAP.send(NULL_BYTES); + } else { + os.write(NULL_BYTES); + os.flush(); + } } } // end of reader loop } catch (IOException e) { @@ -1049,13 +1177,25 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, display.setCurrent(formError); return; } - if (connection != null) { + if (connectionL2CAP != null) { + try { + connectionL2CAP.close(); + } catch (IOException e) { + e.printStackTrace(); + } + connectionL2CAP = null; + } + if (connectionRFCOMM != null) { try { - connection.close(); + if (is != null) + is.close(); + if (os != null) + os.close(); + connectionRFCOMM.close(); } catch (IOException e) { e.printStackTrace(); } - connection = null; + connectionRFCOMM = null; } if (display.getCurrent() == formReader) { resetFormStart(); @@ -1084,11 +1224,13 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, } try { + return isoConn.exchangeData(cmd); } catch (IOException e) { e.printStackTrace(); formError.append(e.getMessage()); formError.append("!!NFC IO error\n"); + formLog.append(e.getMessage() + "\n"); formLog.append("!!NFC IO error\n"); } catch (ContactlessException e) { @@ -1117,7 +1259,7 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, /** * Compare to byte array for equality. - * in the second will always be an offset of 1 used + * in the second array an offset of 2 will be used * @param constCmd first * @param second second * @param secondLength length of second @@ -1125,7 +1267,7 @@ public class BluetoothNFCReader extends MIDlet implements TargetListener, */ private boolean equal(final byte[] constCmd, final byte[] second, final int secondLength) { - return equal(constCmd, 0, constCmd.length, second, 1, secondLength); + return equal(constCmd, 0, constCmd.length, second, 2, secondLength); } /** -- 2.11.4.GIT