diff --git a/PrinterLibs.iml b/PrinterLibs.iml
new file mode 100644
index 0000000..6e8fe23
--- /dev/null
+++ b/PrinterLibs.iml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 0000000..112cd42
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..d9a4a86
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 15
+ buildToolsVersion "27.0.3"
+
+ defaultConfig {
+ minSdkVersion 8
+ targetSdkVersion 19
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:support-v4:18.0.0'
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5464a4d
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/lvrenyang/callback/RecvCallBack.java b/app/src/main/java/com/lvrenyang/callback/RecvCallBack.java
new file mode 100644
index 0000000..145914c
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/callback/RecvCallBack.java
@@ -0,0 +1,5 @@
+package com.lvrenyang.callback;
+
+public interface RecvCallBack {
+ public void onRecv(byte[] buffer, int byteOffset, int byteCount);
+}
diff --git a/app/src/main/java/com/lvrenyang/encryp/DES2.java b/app/src/main/java/com/lvrenyang/encryp/DES2.java
new file mode 100644
index 0000000..dc29870
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/encryp/DES2.java
@@ -0,0 +1,455 @@
+package com.lvrenyang.encryp;
+
+public class DES2 {
+
+ // permuted choice table (PC1) [56]
+ static final byte[] PC1_Table = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42,
+ 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61,
+ 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 };
+ // permuted choice key (PC2) [48]
+ static final byte[] PC2_Table = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21,
+ 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47,
+ 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36,
+ 29, 32 };
+ // number left rotations of pc1 [16]
+ static final byte[] Shift_Table = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
+ 2, 2, 1 };
+ // initial permutation (IP) [64]
+ static final byte[] IP_Table = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44,
+ 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40,
+ 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27,
+ 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23,
+ 15, 7 };
+ // expansion operation matrix (E) [48]
+ static final byte[] E_Table = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9,
+ 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20,
+ 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 };
+ // The (in)famous S-boxes[8][4][16]
+ static final byte[][][] S_Box = {
+ // S1
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } },
+ // S2
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } },
+ // S3
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } },
+ // S4
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } },
+ // S5
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } },
+ // S6
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } },
+ // S7
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } },
+ // S8
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } } };
+ // 32-bit permutation function P used on the output of the S-boxes [32]
+ static final byte[] P_Table = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23,
+ 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22,
+ 11, 4, 25 };
+ // final permutation IP^-1 [64]
+ static final byte[] IPR_Table = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47,
+ 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13,
+ 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51,
+ 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17,
+ 57, 25 };
+
+ byte[][] szSubKeys = new byte[16][48];// 储存16组48位密钥
+ byte[] szCiphertextRaw = new byte[64]; // 储存二进制密文(64个Bits) int 0,1
+ byte[] szPlaintextRaw = new byte[64]; // 储存二进制密文(64个Bits) int 0,1
+ byte[] szCiphertextInBytes = new byte[8];// 储存8位密文
+ byte[] szPlaintextInBytes = new byte[8];// 储存8位明文字符串
+
+ byte[] szCiphertextInBinary = new byte[65]; // 储存二进制密文(64个Bits) U8
+ // '0','1',最后一位存'\0'
+ byte[] szCiphertextInHex = new byte[17]; // 储存十六进制密文,最后一位存'\0'
+ byte[] szPlaintext = new byte[9];// 储存8位明文字符串,最后一位存'\0'
+
+ // 功能:产生16个28位的key
+ // 参数:源8位的字符串(key)
+ // 结果:函数将调用private CreateSubKey将结果存于U8 SubKeys[16][48]
+ public void yxyDES2_InitializeKey(byte[] srcBytes) {
+ // convert 8 U8-bytes key to 64 binary-bits
+ byte[] sz_64key = new byte[64];
+ byte[] sz_56key = new byte[56];
+ int k = 0;
+ yxyDES2_Bytes2Bits(srcBytes, sz_64key, 64);
+ // PC 1
+ for (k = 0; k < 56; k++) {
+ sz_56key[k] = sz_64key[PC1_Table[k] - 1];
+ }
+ yxyDES2_CreateSubKey(sz_56key);
+ }
+
+ // 功能:加密8位字符串
+ // 参数:8位字符串
+ // 结果:函数将加密后结果存放于private szCiphertext[16]
+ // 用户通过属性Ciphertext得到
+ void yxyDES2_EncryptData(byte[] _srcBytes) {
+ byte[] szSrcBits = new byte[64];
+ byte[] sz_IP = new byte[64];
+ byte[] sz_Li = new byte[32];
+ byte[] sz_Ri = new byte[32];
+ byte[] sz_Final64 = new byte[64];
+ int i = 0, j = 0;
+
+ yxyDES2_Bytes2Bits(_srcBytes, szSrcBits, 64);
+ // IP
+ yxyDES2_InitialPermuteData(szSrcBits, sz_IP);
+ memcpy(sz_Li, 0, sz_IP, 0, 32);
+ memcpy(sz_Ri, 0, sz_IP, 32, 32);
+
+ for (i = 0; i < 16; i++) {
+ yxyDES2_FunctionF(sz_Li, sz_Ri, i);
+ }
+ // so D=LR
+
+ memcpy(sz_Final64, 0, sz_Ri, 0, 32);
+ memcpy(sz_Final64, 32, sz_Li, 0, 32);
+
+ // ~IP
+ for (j = 0; j < 64; j++) {
+ szCiphertextRaw[j] = sz_Final64[IPR_Table[j] - 1];
+ }
+ yxyDES2_Bits2Bytes(szCiphertextInBytes, szCiphertextRaw, 64);
+ }
+
+ // 功能:解密16位十六进制字符串
+ // 参数:16位十六进制字符串
+ // 结果:函数将解密候结果存放于private szPlaintext[8]
+ // 用户通过属性Plaintext得到
+ void yxyDES2_DecryptData(byte[] _srcBytes) {
+ byte[] szSrcBits = new byte[64];
+ byte[] sz_IP = new byte[64];
+ byte[] sz_Li = new byte[32];
+ byte[] sz_Ri = new byte[32];
+ byte[] sz_Final64 = new byte[64];
+ int i = 0, j = 0;
+ yxyDES2_Bytes2Bits(_srcBytes, szSrcBits, 64);
+ // IP --- return is sz_IP
+ yxyDES2_InitialPermuteData(szSrcBits, sz_IP);
+ // divide the 64 bits data to two parts
+ memcpy(sz_Ri, 0, sz_IP, 0, 32); // exchange L to R
+ memcpy(sz_Li, 0, sz_IP, 32, 32); // exchange R to L
+ // 16 rounds F and xor and exchange
+ for (i = 0; i < 16; i++) {
+ yxyDES2_FunctionF(sz_Ri, sz_Li, 15 - i);
+ }
+ memcpy(sz_Final64, 0, sz_Li, 0, 32);
+ memcpy(sz_Final64, 32, sz_Ri, 0, 32);
+ // ~IP
+ for (j = 0; j < 64; j++) {
+ szPlaintextRaw[j] = sz_Final64[IPR_Table[j] - 1];
+ }
+ yxyDES2_Bits2Bytes(szPlaintextInBytes, szPlaintextRaw, 64);
+ }
+
+ /**
+ * 返回解密后的字节数组
+ *
+ * @return
+ */
+ byte[] getPlaintext() {
+ return szPlaintextInBytes;
+ }
+
+ // 功能:加密任意长度字符串
+ // 参数:任意长度字符串,长度
+ // 结果:函数将加密后结果存放于private szFCiphertextAnyLength[8192]
+ // 用户通过属性CiphertextAnyLength得到
+ public int yxyDES2_EncryptAnyLength(byte[] _srcBytes, byte[] dst,
+ int _bytesLength) {
+
+ int iParts = 0, iResidue = 0, i = 0, rsLen = 0, dstIdx = 0;
+ byte szLast8Bits[] = new byte[8];
+
+ if (_bytesLength == 8) {
+ yxyDES2_EncryptData(_srcBytes);
+ memcpy(dst, 0, szCiphertextInBytes, 0, 8);
+ dst[8] = '\0';
+ rsLen = 8;
+ } else if (_bytesLength < 8) {
+ byte _temp8bytes[] = new byte[8];
+ memcpy(_temp8bytes, 0, _srcBytes, 0, _bytesLength);
+ yxyDES2_EncryptData(_temp8bytes);
+ memcpy(dst, 0, szCiphertextInBytes, 0, 8);
+ dst[8] = '\0';
+ rsLen = 8;
+ } else if (_bytesLength > 8) {
+ iParts = _bytesLength >> 3;
+ iResidue = _bytesLength % 8;
+
+ for (i = 0; i < iParts; i++) {
+ memcpy(szLast8Bits, 0, _srcBytes, (i * 8), 8);
+ yxyDES2_EncryptData(szLast8Bits);
+ memcpy(dst, dstIdx, szCiphertextInBytes, 0, 8);
+ dstIdx += 8;
+ rsLen += 8;
+ }
+ if (iResidue != 0) {
+ memset(szLast8Bits, 0, 8);
+ memcpy(szLast8Bits, 0, _srcBytes, (iParts * 8), iResidue);
+
+ yxyDES2_EncryptData(szLast8Bits);
+ memcpy(dst, 0, szCiphertextInBytes, 0, 8);
+ dst[8] = '\0';
+ rsLen += 8;
+ }
+ }
+ return rsLen;
+ }
+
+ // 功能:解密任意长度十六进制字符串
+ // 参数:任意长度字符串,长度
+ // 结果:函数将加密后结果存放于private szFPlaintextAnyLength[8192]
+ // 用户通过属性PlaintextAnyLength得到
+ public int yxyDES2_DecryptAnyLength(byte[] _srcBytes, byte[] dst, int _bytesLength) {
+ int iParts = 0, iResidue = 0, i = 0, rsLen = 0, dstIdx = 0;
+ byte[] szLast8Bits = new byte[8];
+ byte[] _temp8bytes = new byte[8];
+
+ if (_bytesLength == 8) {
+ yxyDES2_DecryptData(_srcBytes);
+ memcpy(dst, 0, szPlaintextInBytes, 0, 8);
+ dst[8] = '\0';
+ rsLen = 8;
+ } else if (_bytesLength < 8) {
+ memcpy(_temp8bytes, 0, _srcBytes, 0, 8);
+ yxyDES2_DecryptData(_temp8bytes);
+ memcpy(dst, 0, szPlaintextInBytes, 0, _bytesLength);
+ dst[_bytesLength] = '\0';
+ rsLen = 8;
+ } else if (_bytesLength > 8) {
+ iParts = _bytesLength >> 3;
+ iResidue = _bytesLength % 8;
+ for (i = 0; i < iParts; i++) {
+ memcpy(szLast8Bits, 0, _srcBytes, (i << 3), 8);
+ yxyDES2_DecryptData(szLast8Bits);
+ memcpy(dst, dstIdx, szPlaintextInBytes, 0, 8);
+ dstIdx += 8;
+ rsLen += 8;
+ }
+ if (iResidue != 0) {
+ memset(szLast8Bits, 0, 8);
+ memcpy(szLast8Bits, 0, _srcBytes, (iParts << 3), 8);
+ yxyDES2_DecryptData(szLast8Bits);
+ memcpy(dst, 0, szPlaintextInBytes, 0, iResidue);
+ rsLen += 8;
+ }
+ dst[8] = '\0';
+ }
+ return rsLen;
+ }
+
+ // 功能:Bytes到Bits的转换,
+ // 参数:待变换字符串,处理后结果存放缓冲区指针,Bits缓冲区大小
+ void yxyDES2_Bytes2Bits(byte[] srcBytes, byte[] dstBits, int sizeBits) {
+ int i = 0;
+ for (i = 0; i < sizeBits; i++)
+ dstBits[i] = (byte) ((((srcBytes[i >> 3] & 0xff) << (i & 7)) & 128) >> 7);
+ }
+
+ // 功能:Bits到Bytes的转换,
+ // 参数:待变换字符串,处理后结果存放缓冲区指针,Bits缓冲区大小
+ void yxyDES2_Bits2Bytes(byte[] dstBytes, byte[] srcBits, int sizeBits) {
+ int i = 0;
+ memset(dstBytes, 0, sizeBits >> 3);
+ for (i = 0; i < sizeBits; i++)
+ dstBytes[i >> 3] |= ((srcBits[i] & 0xff) << (7 - (i & 7)));
+ }
+
+ // 功能:Int到Bits的转换,
+ // 参数:待变换字符串,处理后结果存放缓冲区指针
+ void yxyDES2_Int2Bits(int _src, byte[] dstBits) {
+ int i = 0;
+ for (i = 0; i < 4; i++)
+ dstBits[i] = (byte) (((_src << i) & 8) >> 3);
+ }
+
+ // 功能:Bits到Hex的转换
+ // 参数:待变换字符串,处理后结果存放缓冲区指针,Bits缓冲区大小
+ void yxyDES2_Bits2Hex(byte[] dstHex, byte[] srcBits, int sizeBits) {
+ }
+
+ // 功能:Bits到Hex的转换
+ // 参数:待变换字符串,处理后结果存放缓冲区指针,Bits缓冲区大小
+ void yxyDES2_Hex2Bits(byte[] srcHex, byte[] dstBits, int sizeBits) {
+ }
+
+ // szCiphertextInBinary的get函数
+ byte[] yxyDES2_GetCiphertextInBinary() {
+ return null;
+ }
+
+ // szCiphertextInHex的get函数
+ byte[] yxyDES2_GetCiphertextInHex() {
+ return null;
+ }
+
+ // Ciphertext的get函数
+ byte[] yxyDES2_GetCiphertextInBytes() {
+ return null;
+ }
+
+ // Plaintext的get函数
+ byte[] yxyDES2_GetPlaintext() {
+ return null;
+ }
+
+ // 功能:生成子密钥
+ // 参数:经过PC1变换的56位二进制字符串
+ // 结果:将保存于U8 szSubKeys[16][48]
+ void yxyDES2_CreateSubKey(byte[] sz_56key) {
+ byte[] szTmpL = new byte[28];
+ byte[] szTmpR = new byte[28];
+ byte[] szCi = new byte[28];
+ byte[] szDi = new byte[28];
+ byte[] szTmp56 = new byte[56];
+ int i = 0, j = 0;
+
+ memcpy(szTmpL, 0, sz_56key, 0, 28);
+ memcpy(szTmpR, 0, sz_56key, 28, 28);
+
+ for (i = 0; i < 16; i++) {
+ // shift to left
+ // Left 28 bits
+ memcpy(szCi, 0, szTmpL, Shift_Table[i], 28 - Shift_Table[i]);
+ memcpy(szCi, 28 - Shift_Table[i], szTmpL, 0, Shift_Table[i]);
+ // Right 28 bits
+ memcpy(szDi, 0, szTmpR, Shift_Table[i], 28 - Shift_Table[i]);
+ memcpy(szDi, 28 - Shift_Table[i], szTmpR, 0, Shift_Table[i]);
+
+ // permuted choice 48 bits key
+ memcpy(szTmp56, 0, szCi, 0, 28);
+ memcpy(szTmp56, 28, szDi, 0, 28);
+ for (j = 0; j < 48; j++) {
+ szSubKeys[i][j] = szTmp56[PC2_Table[j] - 1];
+ }
+ // Evaluate new szTmpL and szTmpR
+ memcpy(szTmpL, 0, szCi, 0, 28);
+ memcpy(szTmpR, 0, szDi, 0, 28);
+ }
+ }
+
+ // 功能:DES中的F函数,
+ // 参数:左32位,右32位,key序号(0-15)
+ // 结果:均在变换左右32位
+ void yxyDES2_FunctionF(byte[] sz_Li, byte[] sz_Ri, int iKey) {
+ byte[] sz_48R = new byte[48];
+ byte[] sz_xor48 = new byte[48];
+ byte[] sz_P32 = new byte[32];
+ byte[] sz_Rii = new byte[32];
+ byte[] sz_Key = new byte[48];
+ byte[] s_Compress32 = new byte[32];
+ memcpy(sz_Key, 0, szSubKeys[iKey], 0, 48);
+ yxyDES2_ExpansionR(sz_Ri, sz_48R);
+ yxyDES2_XOR(sz_48R, sz_Key, 48, sz_xor48);
+
+ yxyDES2_CompressFuncS(sz_xor48, s_Compress32);
+ yxyDES2_PermutationP(s_Compress32, sz_P32);
+ yxyDES2_XOR(sz_P32, sz_Li, 32, sz_Rii);
+ memcpy(sz_Li, 0, sz_Ri, 0, 32);
+ memcpy(sz_Ri, 0, sz_Rii, 0, 32);
+ }
+
+ // 功能:IP变换
+ // 参数:待处理字符串,处理后结果存放指针
+ // 结果:函数改变第二个参数的内容
+ void yxyDES2_InitialPermuteData(byte[] _src, byte[] _dst) {
+ // IP
+ int i = 0;
+ for (i = 0; i < 64; i++) {
+ _dst[i] = _src[IP_Table[i] - 1];
+ }
+ }
+
+ // 功能:将右32位进行扩展位48位,
+ // 参数:原32位字符串,扩展后结果存放指针
+ // 结果:函数改变第二个参数的内容
+ void yxyDES2_ExpansionR(byte[] _src, byte[] _dst) {
+ int i = 0;
+ for (i = 0; i < 48; i++) {
+ _dst[i] = _src[E_Table[i] - 1];
+ }
+ }
+
+ // 功能:异或函数,
+ // 参数:待异或的操作字符串1,字符串2,操作数长度,处理后结果存放指针
+ // 结果: 函数改变第四个参数的内容
+ void yxyDES2_XOR(byte[] szParam1, byte[] szParam2, int uiParamLength,
+ byte[] szReturnValueBuffer) {
+ int i = 0;
+ for (i = 0; i < uiParamLength; i++) {
+ szReturnValueBuffer[i] = (byte) ((szParam1[i] & 0xff) ^ (szParam2[i] & 0xff));
+ }
+ }
+
+ // 功能:S-BOX , 数据压缩,
+ // 参数:48位二进制字符串,
+ // 结果:返回结果:32位字符串
+ void yxyDES2_CompressFuncS(byte[] _src48, byte[] _dst32) {
+ byte[][] bTemp = new byte[8][6];
+ byte[] dstBits = new byte[4];
+ int i = 0, iX = 0, iY = 0, j = 0;
+
+ for (i = 0; i < 8; i++) {
+ memcpy(bTemp[i], 0, _src48, i * 6, 6);
+ iX = (bTemp[i][0] & 0xff) * 2 + (bTemp[i][5] & 0xff);
+ iY = 0;
+ for (j = 1; j < 5; j++) {
+ iY += (bTemp[i][j] & 0xff) << (4 - j);
+ }
+ yxyDES2_Int2Bits(S_Box[i][iX][iY], dstBits);
+ memcpy(_dst32, i * 4, dstBits, 0, 4);
+ }
+ }
+
+ // 功能:IP逆变换,
+ // 参数:待变换字符串,处理后结果存放指针
+ // 结果:函数改变第二个参数的内容
+ void yxyDES2_PermutationP(byte[] _src, byte[] _dst) {
+ int i = 0;
+ for (i = 0; i < 32; i++) {
+ _dst[i] = _src[P_Table[i] - 1];
+ }
+ }
+
+ /**
+ * 从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
+ *
+ */
+ public void memcpy(byte[] dest, int desOffset, byte[] src, int srcOffset,
+ int nLength) {
+ for (int i = 0; i < nLength; i++)
+ dest[desOffset + i] = src[srcOffset + i];
+ }
+
+ public void memset(byte[] s, int ch, int n) {
+ for (int i = 0; i < n; i++)
+ s[i] = (byte) ch;
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/label/Label1.java b/app/src/main/java/com/lvrenyang/label/Label1.java
new file mode 100644
index 0000000..1316c36
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/label/Label1.java
@@ -0,0 +1,455 @@
+package com.lvrenyang.label;
+
+import com.lvrenyang.pos.IO;
+import com.lvrenyang.utils.DataUtils;
+
+public class Label1 {
+
+ /**
+ * 描述: 指示一个 Page 页面的开始,并设置 Page 页的大小,参考点坐标和页面旋转角度。
+ *
+ * @param startx
+ * 页面起始点x坐标
+ * @param starty
+ * 页面起始点y坐标
+ * @param width
+ * 页面页宽 startx + width
+ * 的范围为[1,384]。编写SDK的时候,该打印机一行的打印点数为384点。如果你不确定每行打印点数
+ * ,请参考打印机规格书。一般来说有384,576,832这三种规格。
+ * @param height
+ * 页面页高 starty + height
+ * 的范围[1,936]。编写SDK的时候,限制是936,但是这个值并不确定,这和打印机的资源有关
+ * 。即便如此,也不建议把页宽设置过大。建议页宽和页高设置和标签纸匹配即可。
+ * @param rotate
+ * 页面旋转。 rotate的取值范围为{0,1}。为0,页面不旋转打印,为1,页面旋转90度打印。
+ */
+ public static void PageBegin(int startx, int starty, int width, int height,
+ int rotate) {
+ byte[] data = new byte[12];
+
+ data[0] = 0x1A;
+ data[1] = 0x5B;
+ data[2] = 0x01;
+
+ data[3] = (byte) (startx & 0xFF);
+ data[4] = (byte) ((startx >> 8) & 0xFF);
+ data[5] = (byte) (starty & 0xFF);
+ data[6] = (byte) ((starty >> 8) & 0xFF);
+
+ data[7] = (byte) (width & 0xFF);
+ data[8] = (byte) ((width >> 8) & 0xFF);
+ data[9] = (byte) (height & 0xFF);
+ data[10] = (byte) ((height >> 8) & 0xFF);
+
+ data[11] = (byte) (rotate & 0xFF);
+
+ IO.Write(data, 0, data.length);
+
+ }
+
+ /**
+ * 描述: 只是一个Page页面的结束。
+ */
+ public static void PageEnd() {
+ byte[] data = new byte[] { 0x1A, 0x5D, 0x00 };
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 将 Page 页上的内容打印到标签纸上。
+ *
+ * @param num
+ * 打印的次数,1-255。
+ */
+ public static void PagePrint(int num) {
+ byte[] data = new byte[] { 0x1A, 0x4F, 0x01, 0x01 };
+
+ data[3] = (byte) (num & 0xFF);
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页面上指定位置绘制文本。只在一行展开,打印机返回占用的区域的坐标值。
+ *
+ * @param startx
+ * 定义文本起始位置 x 坐标,取值范围:[0, Page_Width-1]
+ * @param starty
+ * 定义文本起始位置 y 坐标,取值范围:[0, Page_Height-1]
+ * @param font
+ * 选择字体,有效值范围为{16, 24, 32, 48, 64, 80, 96}
+ * @param style
+ * 字符风格。 数据位 定义 0 加粗标志位:置 1 字体加粗,清零则字体不加粗。 1 下划线标志位:置 1
+ * 文本带下划线,清零则无下划线。 2 反白标志位:置 1 文本反白(黑底白字),清零不反白。 3 删除线标志位:置 1
+ * 文本带删除线,清零则无删除线。 [5,4] 旋转标志位:00 旋转 0° ; 01 旋转 90°; 10 旋转 180°;
+ * 11 旋转 270°; [11,8] 字体宽度放大倍数; [15,12] 字体高度放大倍数;
+ * @param str
+ * 字符串数据流
+ */
+ public static void DrawPlainText(int startx, int starty, int font,
+ int style, byte[] str) {
+ int datalen = 11 + str.length + 1;
+ byte[] data = new byte[datalen];
+
+ data[0] = 0x1A;
+ data[1] = 0x54;
+ data[2] = 0x01;
+
+ data[3] = (byte) (startx & 0xFF);
+ data[4] = (byte) ((startx >> 8) & 0xFF);
+ data[5] = (byte) (starty & 0xFF);
+ data[6] = (byte) ((starty >> 8) & 0xFF);
+
+ data[7] = (byte) (font & 0xFF);
+ data[8] = (byte) ((font >> 8) & 0xFF);
+ data[9] = (byte) (style & 0xFF);
+ data[10] = (byte) ((style >> 8) & 0xFF);
+
+ DataUtils.copyBytes(str, 0, data, 11, str.length);
+ data[datalen - 1] = 0;
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定两点间绘制一条直线段。
+ *
+ * @param startx
+ * 直线段起始点 x 坐标值,取值范围:[0, Page_Width-1]。
+ * @param starty
+ * 直线段起始点 y 坐标值,取值范围:[0,Page_Height-1]。
+ * @param endx
+ * 直线段终止点 x 坐标值,取值范围:[0, Page_Width-1]。
+ * @param endy
+ * 直线段终止点 y 坐标值,取值范围:[0,Page_Height-1]。
+ * @param width
+ * 直线段线宽,取值范围:[1,Page_Height-1]。
+ * @param color
+ * 直线段颜色,取值范围:{0, 1}。当 Color 为 1 时,线段为黑色。当 Color 为 0 时,线段为白色。
+ */
+ public static void DrawLine(int startx, int starty, int endx, int endy,
+ int width, int color) {
+ byte[] data = new byte[14];
+
+ data[0] = 0x1A;
+ data[1] = 0x5C;
+ data[2] = 0x01;
+
+ data[3] = (byte) (startx & 0xFF);
+ data[4] = (byte) ((startx >> 8) & 0xFF);
+ data[5] = (byte) (starty & 0xFF);
+ data[6] = (byte) ((starty >> 8) & 0xFF);
+
+ data[7] = (byte) (endx & 0xFF);
+ data[8] = (byte) ((endx >> 8) & 0xFF);
+ data[9] = (byte) (endy & 0xFF);
+ data[10] = (byte) ((endy >> 8) & 0xFF);
+
+ data[11] = (byte) (width & 0xFF);
+ data[12] = (byte) ((width >> 8) & 0xFF);
+
+ data[13] = (byte) (color & 0xFF);
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制指定大小的矩形框。
+ *
+ * @param left
+ * 矩形框左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+ * @param top
+ * 矩形框左上角 y 坐标值。取值范围:[0, Page_Height-1]。
+ * @param right
+ * 矩形框右下角 x 坐标值。取值范围:[0, Page_Width-1]。
+ * @param bottom
+ * 矩形框右下角 y 坐标值。取值范围:[0, Page_Height-1]。
+ * @param borderwidth
+ * 矩形框线宽。
+ * @param bordercolor
+ * 矩形框线颜色,曲直范围{0,1}。当 Color = 1 时,绘制黑色矩形宽,Color = 0 时,绘制白色矩形框。
+ */
+ public static void DrawBox(int left, int top, int right, int bottom,
+ int borderwidth, int bordercolor) {
+ byte[] data = new byte[14];
+
+ data[0] = 0x1A;
+ data[1] = 0x26;
+ data[2] = 0x01;
+
+ data[3] = (byte) (left & 0xFF);
+ data[4] = (byte) ((left >> 8) & 0xFF);
+ data[5] = (byte) (top & 0xFF);
+ data[6] = (byte) ((top >> 8) & 0xFF);
+
+ data[7] = (byte) (right & 0xFF);
+ data[8] = (byte) ((right >> 8) & 0xFF);
+ data[9] = (byte) (bottom & 0xFF);
+ data[10] = (byte) ((bottom >> 8) & 0xFF);
+
+ data[11] = (byte) (borderwidth & 0xFF);
+ data[12] = (byte) ((borderwidth >> 8) & 0xFF);
+
+ data[13] = (byte) (bordercolor & 0xFF);
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制矩形块。
+ *
+ * @param left
+ * 矩形块左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+ * @param top
+ * 矩形块左上角 y 坐标值。取值范围:[0, Page_Height-1]。
+ * @param right
+ * 矩形块右下角 x 坐标值。取值范围:[0, Page_Width-1]。
+ * @param bottom
+ * 矩形块右下角 y 坐标值。取值范围:[0, Page_Height-1]。
+ * @param color
+ * 矩形块颜色,取值范围:{0, 1}。当 Color 为 1 时,矩形块为黑色。当 Color 为 0时,矩形块为白色。
+ */
+ public static void DrawRectangel(int left, int top, int right, int bottom,
+ int color) {
+ byte[] data = new byte[12];
+
+ data[0] = 0x1A;
+ data[1] = 0x2A;
+ data[2] = 0x00;
+
+ data[3] = (byte) (left & 0xFF);
+ data[4] = (byte) ((left >> 8) & 0xFF);
+ data[5] = (byte) (top & 0xFF);
+ data[6] = (byte) ((top >> 8) & 0xFF);
+
+ data[7] = (byte) (right & 0xFF);
+ data[8] = (byte) ((right >> 8) & 0xFF);
+ data[9] = (byte) (bottom & 0xFF);
+ data[10] = (byte) ((bottom >> 8) & 0xFF);
+
+ data[11] = (byte) (color & 0xFF);
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制一维条码。
+ *
+ * @param startx
+ * 条码左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+ * @param starty
+ * 条码左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+ * @param type
+ * 标识条码类型,取值范围:[0, 29]。
+ * 各值定义如下:
+ * type 类型 长度 条码值范围(十进制)
+ * 0 UPC-A 11 48-57
+ * 1 UPC-E 6 48-57
+ * 2 EAN13 12 48-57
+ * 3 EAN8 7 48-57
+ * 4 CODE39 1- 48-57,65-90,32,36,37,43,45,46,47
+ * 5 I25 1-偶数 48-57
+ * 6 CODABAR 1- 48-57,65-68,36,43,45,46,47,58
+ * 7 CODE93 1-255 0-127
+ * 8 CODE128 2-255 0-127
+ * 9 CODE11
+ * 10 MSI
+ * 11 "128M", // 可以根据数据切换编码模式-> !096 - !105
+ * 12 "EAN128", // 自动切换编码模式
+ * 13 "25C", // 25C Check use mod 10-> 奇数先在前面补0,
+ * 10的倍数-[(奇数位的数字之和<从左至右)+(偶数位数字之和)*3]
+ * 14 "39C", // 39碼的檢查碼必須搭配「檢查碼相對值對照表」,如表所示,將查出的相對值累加後再除以43,得到的餘數再查出相對的編碼字元,即為檢查碼字元。
+ * 15 "39", // Full ASCII 39 Code, 特殊字符用两个可表示的字来表示, 39C 同样是包含Full ASCII,
+ * 注意宽窄比处理
+ * 16 "EAN13+2", // 附加码与主码间隔 7-12 单位,起始为 1011 间隔为 01 ,(_0*10+_1) Mod 4-> 0--AA 1--AB 2--BA 3--BB
+ * 17 "EAN13+5", // 附加码部分同上,模式((_0+_2+_4)*3+(_1+_3)*9) mod 10 ->"bbaaa", "babaa", "baaba", "baaab", "abbaa", "aabba", "aaabb", "ababa", "abaab", "aabab
+ * 18 "EAN8+2", // 同 EAN13+2
+ * 19 "EAN8+5", // 同 EAN13+5
+ * 20 "POST", // 详见规格说明,是高低条码,不是宽窄条码
+ * 21 "UPCA+2", // 附加码见 EAN
+ * 22 "UPCA+5", // 附加码见 EAN
+ * 23 "UPCE+2", // 附加码见 EAN
+ * 24 "UPCE+5", // 附加码见 EAN
+ * 25 "CPOST", // 测试不打印。。。
+ * 26 "MSIC", // 将检查码作为数据再计算一次检查码
+ * 27 "PLESSEY", // 测试不打印。。。
+ * 28 "ITF14", // 25C 变种, 第一个数前补0,检查码计算时需扣除最后一个数,但仍填充为最尾端
+ * 29 "EAN14"
+ * @param height
+ * 定义条码高度。
+ * @param unitwidth
+ * 定义条码码宽。取值范围:[1, 4]。各值定义如下: Width取值 多级条码单位宽度(mm) 二进制条码窄线条宽度
+ * 二进制条码宽线条宽度 1 0.125 0.125 0.25 2 0.25 0.25 0.50 3 0.375 0.375
+ * 0.75 4 0.50 0.50 1.0
+ * @param rotate
+ * 表示条码旋转角度。取值范围:[0, 3]。各值定义如下: Rotate取值 定义 0 条码不旋转绘制。 1 条码旋转
+ * 90°绘制。 2 条码旋转 180°绘制。 3 条码旋转 270°绘制。
+ * @param str
+ * 文本字符数据流
+ */
+ public static void DrawBarcode(int startx, int starty, int type,
+ int height, int unitwidth, int rotate, byte[] str) {
+ int datalen = 11 + str.length + 1;
+ byte[] data = new byte[datalen];
+
+ data[0] = 0x1A;
+ data[1] = 0x30;
+ data[2] = 0x00;
+
+ data[3] = (byte) (startx & 0xFF);
+ data[4] = (byte) ((startx >> 8) & 0xFF);
+ data[5] = (byte) (starty & 0xFF);
+ data[6] = (byte) ((starty >> 8) & 0xFF);
+
+ data[7] = (byte) (type & 0xFF);
+ data[8] = (byte) (height & 0xFF);
+ data[9] = (byte) (unitwidth & 0xFF);
+ data[10] = (byte) (rotate & 0xFF);
+
+ DataUtils.copyBytes(str, 0, data, 11, str.length);
+ data[datalen - 1] = 0;
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制 QRCode 码。
+ *
+ * @param startx
+ * QRCode 码左上角 x 坐标值,取值范围:[0,Page_Width-1]。
+ * @param starty
+ * QRCode 码左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+ * @param version
+ * 指定字符版本。取值范围:[0,20]。当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+ * @param ecc
+ * 指定纠错等级。取值范围:[1, 4]。各值定义如下: ECC 纠错等级 1 L:7%,低纠错,数据多。 2
+ * M:15%,中纠错 3 Q:优化纠错 4 H:30%,最高纠错,数据少。
+ * @param unitwidth
+ * QRCode 码码块,取值范围:[1, 4]。各值定义与一维条码指令输入参数UniWidth相同。
+ * @param rotate
+ * QRCode 码旋转角度,取值范围:[0, 3]。各值定义与一维条码指令输入参数Rotate 相同。
+ * @param str
+ * QRCode 文本字符数据流
+ */
+ public static void DrawQRCode(int startx, int starty, int version, int ecc,
+ int unitwidth, int rotate, byte[] str) {
+ int datalen = 11 + str.length + 1;
+ byte[] data = new byte[datalen];
+
+ data[0] = 0x1A;
+ data[1] = 0x31;
+ data[2] = 0x00;
+
+ data[3] = (byte) (version & 0xFF);
+ data[4] = (byte) (ecc & 0xFF);
+
+ data[5] = (byte) (startx & 0xFF);
+ data[6] = (byte) ((startx >> 8) & 0xFF);
+ data[7] = (byte) (starty & 0xFF);
+ data[8] = (byte) ((starty >> 8) & 0xFF);
+
+ data[9] = (byte) (unitwidth & 0xFF);
+ data[10] = (byte) (rotate & 0xFF);
+
+ DataUtils.copyBytes(str, 0, data, 11, str.length);
+ data[datalen - 1] = 0;
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制 PDF417 条码 。
+ *
+ * @param startx
+ * PDF417 码左上角 x 坐标值,取值范围:[0,Page_Width-1]。
+ * @param starty
+ * PDF417 码左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+ * @param colnum
+ * ColNum 为列数,表述每行容纳多少码字。一个码字为 17*UnitWidth 个点。行数由打印机自动产生,行数范围限定为
+ * 3~90。ColNum 的取值范围:[1,30]。
+ * @param lwratio
+ * 宽高比。取值范围:[3,5]。
+ * @param ecc
+ * 纠错等级,取值范围:[0. 8]。 ecc取值 纠错码数 可存资料量(字节) 0 2 1108 1 4 1106 2 8
+ * 1101 3 16 1092 4 32 1072 5 64 1024 6 128 957 7 256 804 8 512
+ * 496
+ * @param unitwidth
+ * PDF417 码码块,取值范围:[1, 3]。各值定义与一维条码指令输入参数 UniWidth 相同。
+ * @param rotate
+ * PDF417 码旋转角度,取值范围:[0, 3]。各值定义与一维条码指令输入参数 Rotate 相同。
+ * @param str
+ * PDF417 文本字符数据流。
+ */
+ public static void DrawPDF417(int startx, int starty, int colnum,
+ int lwratio, int ecc, int unitwidth, int rotate, byte[] str) {
+ int datalen = 12 + str.length + 1;
+ byte[] data = new byte[datalen];
+
+ data[0] = 0x1A;
+ data[1] = 0x31;
+ data[2] = 0x01;
+
+ data[3] = (byte) (colnum & 0xFF);
+ data[4] = (byte) (ecc & 0xFF);
+ data[5] = (byte) (lwratio & 0xFF);
+
+ data[6] = (byte) (startx & 0xFF);
+ data[7] = (byte) ((startx >> 8) & 0xFF);
+ data[8] = (byte) (starty & 0xFF);
+ data[9] = (byte) ((starty >> 8) & 0xFF);
+
+ data[10] = (byte) (unitwidth & 0xFF);
+ data[11] = (byte) (rotate & 0xFF);
+
+ DataUtils.copyBytes(str, 0, data, 12, str.length);
+ data[datalen - 1] = 0;
+
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 描述: 在 Page 页指定位置绘制位图。
+ *
+ * @param startx
+ * 位图左上角 x 坐标值,取值范围:[0, Page_Width]。
+ * @param starty
+ * 位图左上角 y 坐标值,取值范围:[0, Page_Height]。
+ * @param width
+ * 位图的像素宽度。
+ * @param height
+ * 位图的像素高度。
+ * @param style
+ * 位图打印特效,各位定义如下: 位 定义 0 反白标志位,置 1 位图反白打印,清零正常打印。 [2:1] 旋转标志位: 00
+ * 旋转 0° ; 01 旋转 90°; 10 旋转 180°; 11 旋转 270° [7:3] 保留。 [11:8]
+ * 位图宽度放大倍数。 [12:15] 位图高度放大倍数。
+ * @param pdata
+ * 位图的点阵数据。
+ */
+ public static void DrawBitmap(int startx, int starty, int width,
+ int height, int style, byte[] pdata) {
+ int datalen = 13 + width * height / 8;
+ byte[] data = new byte[datalen];
+
+ data[0] = 0x1A;
+ data[1] = 0x21;
+ data[2] = 0x01;
+
+ data[3] = (byte) (startx & 0xFF);
+ data[4] = (byte) ((startx >> 8) & 0xFF);
+ data[5] = (byte) (starty & 0xFF);
+ data[6] = (byte) ((starty >> 8) & 0xFF);
+
+ data[7] = (byte) (width & 0xFF);
+ data[8] = (byte) ((width >> 8) & 0xFF);
+ data[9] = (byte) (height & 0xFF);
+ data[10] = (byte) ((height >> 8) & 0xFF);
+
+ data[11] = (byte) (style & 0xFF);
+ data[12] = (byte) ((style >> 8) & 0xFF);
+
+ DataUtils.copyBytes(pdata, 0, data, 13, pdata.length);
+
+ IO.Write(data, 0, data.length);
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/pos/Cmd.java b/app/src/main/java/com/lvrenyang/pos/Cmd.java
new file mode 100644
index 0000000..b24f0d5
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/pos/Cmd.java
@@ -0,0 +1,620 @@
+package com.lvrenyang.pos;
+
+public class Cmd {
+
+ public static class PCmd {
+ public static byte[] test = { 0x03, (byte) 0xFF, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, (byte) 0xD4, 0x18, 0x44, 0x45,
+ 0x56, 0x49, 0x43, 0x45, 0x3F, 0x3F };
+ public static byte[] startUpdate = { 0x03, (byte) 0xFF, 0x2F, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xD3, 0x00 };
+ // 更新程序里,下标4,5,6,7为参数偏移地址,10为包头校验和,11为数据校验和
+ public static byte[] imaUpdate = { 0x03, (byte) 0xFF, 0x2E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, (byte) 0xD3, 0x00 };
+ public static byte[] endUpdate = { 0x03, (byte) 0xFF, 0x2F, 0x00,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00,
+ (byte) 0xD3, 0x00 };
+
+ // 更新字体
+ public static byte[] fontUpdate = { 0x03, (byte) 0xFF, 0x2D, 0x00,
+ 0x00, 0x00, 0x00, 0x00, (byte) 0xFF, 0x00, 0x2E, 0x00 };
+
+ public static byte[] setBaudrate = { 0x03, (byte) 0xFF, 0x2B, 0x00,
+ (byte) 0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00 };
+
+ public static byte[] setPrintParam = { 0x03, (byte) 0xFF, 0x60, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, (byte) 0x8C, 0x18,
+ // 9600波特率
+ (byte) 0x80, 0x25, 0x00, 0x00,
+
+ // 语言
+ (byte) 0xFF,
+
+ // 加热浓度,0,1,2(2是最浓
+ 0x02,
+
+ // 第6 byte 默认字体, 0--12x24 1--9x24 2--9x17 3--8x16 4--16x18
+ 0x00,
+
+ // 第7 byte 换行命令: 0--0x0A 1--0x0D
+ 0x00,
+
+ // 第8-9 byte空闲等待时间(单位:秒),高字节在后
+ 0x40, 0x00,
+ // 第10-11 byte自动关机时间(单位:秒),高字节在后
+ (byte) 0xFF, 0x00,
+
+ // 第12-13 byte走纸键最大走纸长度(单位:毫米),高字节 在后
+ (byte) 0xFF, 0x00,
+
+ // 第14-15 byte黑标最大寻找距离(单位:毫米),高字节在 后
+ (byte) 0xFF, 0x00 };
+
+ public static byte[] readFlash = { 0x03, (byte) 0xFF, 0x2C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xD0, 0x00 };
+
+ public static byte[] setBluetooth = { 0x03, (byte) 0xFF, 0x61, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ public static byte[] setSystemInfo = { 0x03, (byte) 0xFF, 0x64, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ }
+
+ // /
+ // / 包含热敏打印机基本指令
+ // /
+ public static class ESCCmd {
+
+ /**
+ * 设置密钥,一定是8个字节的密钥
+ */
+ public static byte[] DES_SETKEY = { 0x1f, 0x1f, 0x00, 0x08, 0x00, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+
+ /**
+ * 发送明文 0x00,0x00是明文数据长度。必须使用随机数。后面跟着的是明文数据 该命令会返回加密后的数据。相同格式。
+ */
+ public static byte[] DES_ENCRYPT = { 0x1f, 0x1f, 0x01 };
+
+ public static byte[] ERROR = { 0x00 };
+
+ // /
+ // / 复位打印机
+ // /
+ public static byte[] ESC_ALT = { 0x1b, 0x40 };
+
+ // /
+ // / 选择页模式
+ // /
+ public static byte[] ESC_L = { 0x1b, 0x4c };
+
+ // /
+ // / 页模式下取消打印数据
+ // /
+ public static byte[] ESC_CAN = { 0x18 };
+
+ // /
+ // / 打印并回到标准模式(在页模式下)
+ // /
+ public static byte[] FF = { 0x0c };
+
+ // /
+ // / 页模式下打印缓冲区所有内容
+ // / 只在页模式下有效,不清除缓冲区内容
+ // /
+ public static byte[] ESC_FF = { 0x1b, 0x0c };
+
+ // /
+ // / 选择标准模式
+ // /
+ public static byte[] ESC_S = { 0x1b, 0x53 };
+
+ // /
+ // / 设置横向和纵向移动单位
+ // / 分别将横向移动单位近似设置成1/x英寸,纵向移动单位设置成1/y英寸。
+ // / 当x和y为0时,x和y被设置成默认值200。
+ // /
+ public static byte[] GS_P_x_y = { 0x1d, 0x50, 0x00, 0x00 };
+
+ // /
+ // / 选择国际字符集,值可以为0-15。默认值为0(美国)。
+ // /
+ public static byte[] ESC_R_n = { 0x1b, 0x52, 0x00 };
+
+ // /
+ // / 选择字符代码表,值可以为0-10,16-19。默认值为0。
+ // /
+ public static byte[] ESC_t_n = { 0x1b, 0x74, 0x00 };
+
+ // /
+ // / 打印并换行
+ // /
+ public static byte[] LF = { 0x0a };
+
+ public static byte[] CR = { 0x0d };
+
+ // /
+ // / 设置行间距为[n*纵向或横向移动单位]英寸
+ // /
+ public static byte[] ESC_3_n = { 0x1b, 0x33, 0x00 };
+
+ // /
+ // / 设置字符右间距,当字符放大时,右间距也随之放大相同倍数
+ // /
+ public static byte[] ESC_SP_n = { 0x1b, 0x20, 0x00 };
+
+ // /
+ // / 在指定的钱箱插座引脚产生设定的开启脉冲。
+ // /
+ public static byte[] DLE_DC4_n_m_t = { 0x10, 0x14, 0x01, 0x00, 0x01 };
+
+ // /
+ // / 选择切纸模式并直接切纸,0为全切,1为半切
+ // /
+ public static byte[] GS_V_m = { 0x1d, 0x56, 0x00 };
+
+ // /
+ // / 进纸并且半切。
+ // /
+ public static byte[] GS_V_m_n = { 0x1d, 0x56, 0x42, 0x00 };
+
+ // /
+ // / 设置打印区域宽度,该命令仅在标准模式行首有效。
+ // / 如果【左边距+打印区域宽度】超出可打印区域,则打印区域宽度为可打印区域-左边距。
+ // /
+ public static byte[] GS_W_nL_nH = { 0x1d, 0x57, 0x76, 0x02 };
+
+ // /
+ // / 设置绝对打印位置
+ // / 将当前位置设置到距离行首(nL + nH x 256)处。
+ // / 如果设置位置在指定打印区域外,该命令被忽略
+ // /
+ public static byte[] ESC_dollors_nL_nH = { 0x1b, 0x24, 0x00, 0x00 };
+
+ /**
+ * 选择对齐方式 0 左对齐 1 中间对齐 2 右对齐
+ */
+ public static byte[] ESC_a_n = { 0x1b, 0x61, 0x00 };
+
+ // /
+ // / 选择字符大小
+ // / 0-3位选择字符高度,4-7位选择字符宽度
+ // / 范围为从0-7
+ // /
+ public static byte[] GS_exclamationmark_n = { 0x1d, 0x21, 0x00 };
+
+ // /
+ // / 选择字体
+ // / 0 标准ASCII字体
+ // / 1 压缩ASCII字体
+ // /
+ public static byte[] ESC_M_n = { 0x1b, 0x4d, 0x00 };
+
+ // /
+ // / 选择/取消加粗模式
+ // / n的最低位为0,取消加粗模式
+ // / n最低位为1,选择加粗模式
+ // / 与0x01即可
+ // /
+ public static byte[] GS_E_n = { 0x1b, 0x45, 0x00 };
+
+ // /
+ // / 选择/取消下划线模式
+ // / 0 取消下划线模式
+ // / 1 选择下划线模式(1点宽)
+ // / 2 选择下划线模式(2点宽)
+ // /
+ public static byte[] ESC_line_n = { 0x1b, 0x2d, 0x00 };
+
+ // /
+ // / 选择/取消倒置打印模式
+ // / 0 为取消倒置打印
+ // / 1 选择倒置打印
+ // /
+ public static byte[] ESC_lbracket_n = { 0x1b, 0x7b, 0x00 };
+
+ // /
+ // / 选择/取消黑白反显打印模式
+ // / n的最低位为0是,取消反显打印
+ // / n的最低位为1时,选择反显打印
+ // /
+ public static byte[] GS_B_n = { 0x1d, 0x42, 0x00 };
+
+ // /
+ // / 选择/取消顺时针旋转90度
+ // /
+ public static byte[] ESC_V_n = { 0x1b, 0x56, 0x00 };
+
+ // /
+ // / 打印下载位图
+ // / 0 正常
+ // / 1 倍宽
+ // / 2 倍高
+ // / 3 倍宽、倍高
+ // /
+ public static byte[] GS_backslash_m = { 0x1d, 0x2f, 0x00 };
+
+ // /
+ // / 打印NV位图
+ // / 以m指定的模式打印flash中图号为n的位图
+ // / 1≤n≤255
+ // /
+ public static byte[] FS_p_n_m = { 0x1c, 0x70, 0x01, 0x00 };
+
+ // /
+ // / 选择HRI字符的打印位置
+ // / 0 不打印
+ // / 1 条码上方
+ // / 2 条码下方
+ // / 3 条码上、下方都打印
+ // /
+ public static byte[] GS_H_n = { 0x1d, 0x48, 0x00 };
+
+ // /
+ // / 选择HRI使用字体
+ // / 0 标准ASCII字体
+ // / 1 压缩ASCII字体
+ // /
+ public static byte[] GS_f_n = { 0x1d, 0x66, 0x00 };
+
+ // /
+ // / 选择条码高度
+ // / 1≤n≤255
+ // / 默认值 n=162
+ // /
+ public static byte[] GS_h_n = { 0x1d, 0x68, (byte) 0xa2 };
+
+ // /
+ // / 设置条码宽度
+ // / 2≤n≤6
+ // / 默认值 n=3
+ // /
+ public static byte[] GS_w_n = { 0x1d, 0x77, 0x03 };
+
+ // /
+ // / 打印条码
+ // / 0x41≤m≤0x49
+ // / n的取值有条码类型m决定
+ // /
+ public static byte[] GS_k_m_n_ = { 0x1d, 0x6b, 0x41, 0x0c };
+
+ /**
+ * version: 1 <= v <= 17 error correction level: 1 <= r <= 4
+ */
+ public static byte[] GS_k_m_v_r_nL_nH = { 0x1d, 0x6b, 0x61, 0x00, 0x02,
+ 0x00, 0x00 };
+
+ // /
+ // / 页模式下设置打印区域
+ // / 该命令在标准模式下只设置内部标志位,不影响打印
+ // /
+ public static byte[] ESC_W_xL_xH_yL_yH_dxL_dxH_dyL_dyH = { 0x1b, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0x02, (byte) 0xb0, 0x04 };
+
+ // /
+ // / 在页模式下选择打印区域方向
+ // / 0≤n≤3
+ // /
+ public static byte[] ESC_T_n = { 0x1b, 0x54, 0x00 };
+
+ // /
+ // / 页模式下设置纵向绝对位置
+ // / 这条命令只有在页模式下有效
+ // /
+ public static byte[] GS_dollors_nL_nH = { 0x1d, 0x24, 0x00, 0x00 };
+
+ // /
+ // / 页模式下设置纵向相对位置
+ // / 页模式下,以当前点位参考点设置纵向移动距离
+ // / 这条命令只在页模式下有效
+ // /
+ public static byte[] GS_backslash_nL_nH = { 0x1d, 0x5c, 0x00, 0x00 };
+
+ // /
+ // / 选择/取消汉字下划线模式
+ // /
+ public static byte[] FS_line_n = { 0x1c, 0x2d, 0x00 };
+
+ /** 设置模块类型,缺省[7]=3, 0<=n<=16 */
+ public static byte[] GS_leftbracket_k_pL_pH_cn_67_n = { 0x1d, 0x28,
+ 0x6b, 0x03, 0x00, 0x31, 0x43, 0x3 };
+
+ /**
+ * 设置QR码的水平效验误差 缺省[7]=48, 48 - 7%, 49 - 15%, 50 - 25%, 51 - %30
+ */
+ public static byte[] GS_leftbracket_k_pL_pH_cn_69_n = { 0x1d, 0x28,
+ 0x6b, 0x03, 0x00, 0x31, 0x45, 0x30 };
+
+ /**
+ * 4<=pl+ph*256<=7092(0<=pl<=255,0<=ph<=28) ((pL + pH×256
+ * )-3)的字节在m(d1...dk)后作为图形的数据被处理。
+ */
+ public static byte[] GS_leftbracket_k_pL_pH_cn_80_m__d1dk = { 0x1d,
+ 0x28, 0x6b, 0x03, 0x00, 0x31, 0x50, 0x30 };
+
+ /**
+ * 打印二维码
+ */
+ public static byte[] GS_leftbracket_k_pL_pH_cn_fn_m = { 0x1d, 0x28,
+ 0x6b, 0x03, 0x00, 0x31, 0x51, 0x30 };
+
+ }
+
+ public static class Constant {
+
+ public static final int LAN_ADDR = 0x193000;
+
+ // 第一段参数的地址
+ public static final int LAN_INFO_ADDR = LAN_ADDR;
+ public static final int LAN_INFO_LEN = 13;
+
+ public static final int PRN_INFO_ADDR = LAN_INFO_ADDR + LAN_INFO_LEN;
+ public static final int PRN_INFO_LEN = 40;
+
+ public static final int OEM_NAME_LEN = 40;
+ public static final int OEM_INFO_ADDR = (PRN_INFO_ADDR + PRN_INFO_LEN);
+ public static final int OEM_INFO_LEN = (OEM_NAME_LEN * 4 + 2);
+
+ public static final int USER_INFO_ADDR = (OEM_INFO_ADDR + OEM_INFO_LEN);
+ public static final int USER_INFO_LEN = 50;
+
+ public static final int BT_INFO_ADDR = (USER_INFO_ADDR + USER_INFO_LEN);
+ public static final int BT_INFO_LEN = 30;
+
+ public static final int IRD_INFO_ADDR = (BT_INFO_ADDR + BT_INFO_LEN);
+ public static final int IRD_INFO_LEN = 30;
+
+ public static final int FAC_INFO_ADDR = (IRD_INFO_ADDR + IRD_INFO_LEN);
+ public static final int FAC_INFO_LEN = 68;
+
+ public static final int USER_INFO2_ADDR = (FAC_INFO_ADDR + FAC_INFO_LEN);
+ public static final int USER_INFO2_LEN = 20;
+ // 最后一段参数
+
+ public static final int PARA_LEN = (USER_INFO2_ADDR + USER_INFO2_LEN - LAN_INFO_ADDR);
+
+ public static final int BT_MAX_NAME_LEN = 12;
+ public static final int BT_MAX_PWD_LEN = 15;
+
+ public static final int FAC_MAX_NAME_LEN = 32;
+ public static final int FAC_MAX_SN_LEN = 29;
+
+ public static final int BARCODE_TYPE_UPC_A = 0x41;
+ public static final int BARCODE_TYPE_UPC_E = 0x42;
+ public static final int BARCODE_TYPE_EAN13 = 0x43;
+ public static final int BARCODE_TYPE_EAN8 = 0x44;
+ public static final int BARCODE_TYPE_CODE39 = 0x45;
+ public static final int BARCODE_TYPE_ITF = 0x46;
+ public static final int BARCODE_TYPE_CODEBAR = 0x47;
+ public static final int BARCODE_TYPE_CODE93 = 0x48;
+ public static final int BARCODE_TYPE_CODE128 = 0x49;
+
+ public static final int BARCODE_FONTPOSITION_NO = 0x00;
+ public static final int BARCODE_FONTPOSITION_ABOVE = 0x01;
+ public static final int BARCODE_FONTPOSITION_BELOW = 0x02;
+ public static final int BARCODE_FONTPOSITION_ABOVEANDBELOW = 0x03;
+
+ public static final int BARCODE_FONTTYPE_STANDARD = 0x00;
+ public static final int BARCODE_FONTTYPE_SMALL = 0x01;
+
+ public static final int ALIGN_LEFT = 0x00;
+ public static final int ALIGN_CENTER = 0x01;
+ public static final int ALIGN_RIGHT = 0x02;
+
+ public static final int FONTSTYLE_NORMAL = 0x00;
+ public static final int FONTSTYLE_BOLD = 0x08;
+ public static final int FONTSTYLE_UNDERLINE1 = 0x80;
+ public static final int FONTSTYLE_UNDERLINE2 = 0x100;
+ public static final int FONTSTYLE_UPSIDEDOWN = 0x200;
+ public static final int FONTSTYLE_BLACKWHITEREVERSE = 0x400;
+ public static final int FONTSTYLE_TURNRIGHT90 = 0x1000;
+
+ public static final int CODEPAGE_CHINESE = 255;
+ public static final int CODEPAGE_BIG5 = 254;
+ public static final int CODEPAGE_UTF_8 = 253;
+ public static final int CODEPAGE_SHIFT_JIS = 252;
+ public static final int CODEPAGE_EUC_KR = 251;
+ public static final int CODEPAGE_CP437_Standard_Europe = 0;
+ public static final int CODEPAGE_Katakana = 1;
+ public static final int CODEPAGE_CP850_Multilingual = 2;
+ public static final int CODEPAGE_CP860_Portuguese = 3;
+ public static final int CODEPAGE_CP863_Canadian_French = 4;
+ public static final int CODEPAGE_CP865_Nordic = 5;
+ public static final int CODEPAGE_WCP1251_Cyrillic = 6;
+ public static final int CODEPAGE_CP866_Cyrilliec = 7;
+ public static final int CODEPAGE_MIK_Cyrillic_Bulgarian = 8;
+ public static final int CODEPAGE_CP755_East_Europe_Latvian_2 = 9;
+ public static final int CODEPAGE_Iran = 10;
+ public static final int CODEPAGE_CP862_Hebrew = 15;
+ public static final int CODEPAGE_WCP1252_Latin_I = 16;
+ public static final int CODEPAGE_WCP1253_Greek = 17;
+ public static final int CODEPAGE_CP852_Latina_2 = 18;
+ public static final int CODEPAGE_CP858_Multilingual_Latin = 19;
+ public static final int CODEPAGE_Iran_II = 20;
+ public static final int CODEPAGE_Latvian = 21;
+ public static final int CODEPAGE_CP864_Arabic = 22;
+ public static final int CODEPAGE_ISO_8859_1_West_Europe = 23;
+ public static final int CODEPAGE_CP737_Greek = 24;
+ public static final int CODEPAGE_WCP1257_Baltic = 25;
+ public static final int CODEPAGE_Thai = 26;
+ public static final int CODEPAGE_CP720_Arabic = 27;
+ public static final int CODEPAGE_CP855 = 28;
+ public static final int CODEPAGE_CP857_Turkish = 29;
+ public static final int CODEPAGE_WCP1250_Central_Eurpoe = 30;
+ public static final int CODEPAGE_CP775 = 31;
+ public static final int CODEPAGE_WCP1254_Turkish = 32;
+ public static final int CODEPAGE_WCP1255_Hebrew = 33;
+ public static final int CODEPAGE_WCP1256_Arabic = 34;
+ public static final int CODEPAGE_WCP1258_Vietnam = 35;
+ public static final int CODEPAGE_ISO_8859_2_Latin_2 = 36;
+ public static final int CODEPAGE_ISO_8859_3_Latin_3 = 37;
+ public static final int CODEPAGE_ISO_8859_4_Baltic = 38;
+ public static final int CODEPAGE_ISO_8859_5_Cyrillic = 39;
+ public static final int CODEPAGE_ISO_8859_6_Arabic = 40;
+ public static final int CODEPAGE_ISO_8859_7_Greek = 41;
+ public static final int CODEPAGE_ISO_8859_8_Hebrew = 42;
+ public static final int CODEPAGE_ISO_8859_9_Turkish = 43;
+ public static final int CODEPAGE_ISO_8859_15_Latin_3 = 44;
+ public static final int CODEPAGE_Thai2 = 45;
+ public static final int CODEPAGE_CP856 = 46;
+ public static final int CODEPAGE_Cp874 = 47;
+
+ public static final String[] strcodepages = { "CHINESE", "BIG5",
+ "UTF-8", "SHIFT-JIS", "EUC-KR",
+ "CP437 [U.S.A., Standard Europe]", "Katakana",
+ "CP850 [Multilingual]", "CP860 [Portuguese]",
+ "CP863 [Canadian-French]", "CP865 [Nordic]",
+ "WCP1251 [Cyrillic]", "CP866 Cyrilliec #2",
+ "MIK[Cyrillic /Bulgarian]", "CP755 [East Europe Latvian 2]",
+ "Iran", "CP862 [Hebrew]", "WCP1252 Latin I", "WCP1253 [Greek]",
+ "CP852 [Latina 2]", "CP858 Multilingual Latin)", "Iran II",
+ "Latvian", "CP864 [Arabic]", "ISO-8859-1 [West Europe]",
+ "CP737 [Greek]", "WCP1257 [Baltic]", "Thai", "CP720[Arabic]",
+ "CP855", "CP857[Turkish]", "WCP1250[Central Eurpoe]", "CP775",
+ "WCP1254[Turkish]", "WCP1255[Hebrew]", "WCP1256[Arabic]",
+ "WCP1258[Vietnam]", "ISO-8859-2[Latin 2]",
+ "ISO-8859-3[Latin 3]", "ISO-8859-4[Baltic]",
+ "ISO-8859-5[Cyrillic]", "ISO-8859-6[Arabic]",
+ "ISO-8859-7[Greek]", "ISO-8859-8[Hebrew]",
+ "ISO-8859-9[Turkish]", "ISO-8859-15 [Latin 3]", "Thai2",
+ "CP856", "Cp874" };
+
+ public static final int[] ncodepages = { Constant.CODEPAGE_CHINESE,
+ Constant.CODEPAGE_BIG5, Constant.CODEPAGE_UTF_8,
+ Constant.CODEPAGE_SHIFT_JIS, Constant.CODEPAGE_EUC_KR,
+ Constant.CODEPAGE_CP437_Standard_Europe,
+ Constant.CODEPAGE_Katakana,
+ Constant.CODEPAGE_CP850_Multilingual,
+ Constant.CODEPAGE_CP860_Portuguese,
+ Constant.CODEPAGE_CP863_Canadian_French,
+ Constant.CODEPAGE_CP865_Nordic,
+ Constant.CODEPAGE_WCP1251_Cyrillic,
+ Constant.CODEPAGE_CP866_Cyrilliec,
+ Constant.CODEPAGE_MIK_Cyrillic_Bulgarian,
+ Constant.CODEPAGE_CP755_East_Europe_Latvian_2,
+ Constant.CODEPAGE_Iran, Constant.CODEPAGE_CP862_Hebrew,
+ Constant.CODEPAGE_WCP1252_Latin_I,
+ Constant.CODEPAGE_WCP1253_Greek,
+ Constant.CODEPAGE_CP852_Latina_2,
+ Constant.CODEPAGE_CP858_Multilingual_Latin,
+ Constant.CODEPAGE_Iran_II, Constant.CODEPAGE_Latvian,
+ Constant.CODEPAGE_CP864_Arabic,
+ Constant.CODEPAGE_ISO_8859_1_West_Europe,
+ Constant.CODEPAGE_CP737_Greek,
+ Constant.CODEPAGE_WCP1257_Baltic, Constant.CODEPAGE_Thai,
+ Constant.CODEPAGE_CP720_Arabic, Constant.CODEPAGE_CP855,
+ Constant.CODEPAGE_CP857_Turkish,
+ Constant.CODEPAGE_WCP1250_Central_Eurpoe,
+ Constant.CODEPAGE_CP775, Constant.CODEPAGE_WCP1254_Turkish,
+ Constant.CODEPAGE_WCP1255_Hebrew,
+ Constant.CODEPAGE_WCP1256_Arabic,
+ Constant.CODEPAGE_WCP1258_Vietnam,
+ Constant.CODEPAGE_ISO_8859_2_Latin_2,
+ Constant.CODEPAGE_ISO_8859_3_Latin_3,
+ Constant.CODEPAGE_ISO_8859_4_Baltic,
+ Constant.CODEPAGE_ISO_8859_5_Cyrillic,
+ Constant.CODEPAGE_ISO_8859_6_Arabic,
+ Constant.CODEPAGE_ISO_8859_7_Greek,
+ Constant.CODEPAGE_ISO_8859_8_Hebrew,
+ Constant.CODEPAGE_ISO_8859_9_Turkish,
+ Constant.CODEPAGE_ISO_8859_15_Latin_3, Constant.CODEPAGE_Thai2,
+ Constant.CODEPAGE_CP856, Constant.CODEPAGE_Cp874 };
+
+ public static String getCodePageStr(int nCodePage) {
+ for (int i = 0; i < ncodepages.length; i++) {
+ if (ncodepages[i] == nCodePage)
+ return strcodepages[i];
+ }
+ return "";
+ }
+
+ public static int getCodePageInt(String strCodePage) {
+ for (int i = 0; i < strcodepages.length; i++) {
+ if (strcodepages[i].equals(strCodePage))
+ return ncodepages[i];
+ }
+ return -1;
+ }
+
+ public static final int[] nbaudrate = { 4800, 9600, 19200, 38400,
+ 57600, 115200 };
+ public static final String[] strbaudrate = { "4800", "9600", "19200",
+ "38400", "57600", "115200", };
+
+ public static String getBaudrateStr(int nBaudrate) {
+ for (int i = 0; i < nbaudrate.length; i++) {
+ if (nbaudrate[i] == nBaudrate)
+ return strbaudrate[i];
+ }
+ return "";
+ }
+
+ public static int getBaudrateInt(String strBaudrate) {
+ for (int i = 0; i < strbaudrate.length; i++) {
+ if (strbaudrate[i].equals(strBaudrate))
+ return nbaudrate[i];
+ }
+ return -1;
+ }
+
+ public static final int[] ndarkness = { 0, 1, 2 };
+ public static final String[] strdarkness = { "Level 0", "Level 1",
+ "Level 2" };
+
+ public static String getDarknessStr(int nDarkness) {
+ for (int i = 0; i < ndarkness.length; i++) {
+ if (ndarkness[i] == nDarkness)
+ return strdarkness[i];
+ }
+ return "";
+ }
+
+ public static int getDarknessInt(String strDarkness) {
+ for (int i = 0; i < strdarkness.length; i++) {
+ if (strdarkness[i].equals(strDarkness))
+ return ndarkness[i];
+ }
+ return -1;
+ }
+
+ public static final int[] ndefaultfont = { 0, 1, 2, 3, 4 };
+ public static final String[] strdefaultfont = { "12x24", "9x24",
+ "9x17", "8x16", "16x18" };
+
+ public static String getDefaultFontStr(int nDefaultFont) {
+ for (int i = 0; i < ndefaultfont.length; i++) {
+ if (ndefaultfont[i] == nDefaultFont)
+ return strdefaultfont[i];
+ }
+ return "";
+ }
+
+ public static int getDefaultFontInt(String strDefaultFont) {
+ for (int i = 0; i < strdefaultfont.length; i++) {
+ if (strdefaultfont[i].equals(strDefaultFont))
+ return ndefaultfont[i];
+ }
+ return -1;
+ }
+
+ public static final int[] nlinefeed = { 0, 1 };
+ public static final String[] strlinefeed = { "LF", "CRLF" };
+
+ public static String getLineFeedStr(int nLineFeed) {
+ for (int i = 0; i < nlinefeed.length; i++) {
+ if (nlinefeed[i] == nLineFeed)
+ return strlinefeed[i];
+ }
+ return "";
+ }
+
+ public static int getLineFeedInt(String strLineFeed) {
+ for (int i = 0; i < strlinefeed.length; i++) {
+ if (strlinefeed[i].equals(strLineFeed))
+ return nlinefeed[i];
+ }
+ return -1;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/pos/IO.java b/app/src/main/java/com/lvrenyang/pos/IO.java
new file mode 100644
index 0000000..6eca05f
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/pos/IO.java
@@ -0,0 +1,125 @@
+package com.lvrenyang.pos;
+
+import com.lvrenyang.rwbt.BTRWThread;
+import com.lvrenyang.rwusb.USBRWThread;
+import com.lvrenyang.rwwifi.NETRWThread;
+import com.lvrenyang.utils.DataUtils;
+import com.lvrenyang.utils.FileUtils;
+
+/**
+ * IO 软件层面和底层的接口。 上层读写都调用IO里面的函数。 IO 调用rwbt,rwwifi,rwusb,rwbuf等底层函数。
+ *
+ * @author Administrator
+ *
+ */
+public class IO {
+
+ public static final int PORT_NET = 1;
+ public static final int PORT_BT = 2;
+ public static final int PORT_USB = 3;
+
+ private static int curPort = PORT_BT;
+
+ public static synchronized int GetCurPort() {
+ return curPort;
+ }
+
+ public static synchronized void SetCurPort(int port) {
+ curPort = port;
+ }
+
+ public static synchronized int Write(byte[] buffer, int offset, int count) {
+ int result = 0;
+ if (curPort == PORT_NET) {
+ result = NETRWThread.Write(buffer, offset, count);
+ } else if (curPort == PORT_BT) {
+ result = BTRWThread.Write(buffer, offset, count);
+ } else if (curPort == PORT_USB) {
+ result = USBRWThread.Write(buffer, offset, count);
+ }
+
+ FileUtils.DebugAddToFile(
+ "WRITE\r\n" + DataUtils.bytesToStr(buffer, offset, count)
+ + "\r\n", FileUtils.sdcard_dump_txt);
+ return result;
+ }
+
+ public static synchronized int Read(byte[] buffer, int byteOffset,
+ int byteCount, int timeout) {
+ int result = 0;
+ if (curPort == PORT_NET) {
+ result = NETRWThread.Read(buffer, byteOffset, byteCount, timeout);
+ } else if (curPort == PORT_BT) {
+ result = BTRWThread.Read(buffer, byteOffset, byteCount, timeout);
+ } else if (curPort == PORT_USB) {
+ result = USBRWThread.Read(buffer, byteOffset, byteCount, timeout);
+ }
+ if (result > 0) {
+ FileUtils.DebugAddToFile(
+ "READ:\r\n"
+ + DataUtils.bytesToStr(buffer, byteOffset,
+ byteCount) + "\r\n",
+ FileUtils.sdcard_dump_txt);
+ }
+ return result;
+ }
+
+ public static synchronized boolean Request(byte sendbuf[], int sendlen,
+ int requestlen, byte recbuf[], Integer reclen, int timeout) {
+ if (curPort == PORT_NET) {
+ return NETRWThread.Request(sendbuf, sendlen, requestlen, recbuf,
+ reclen, timeout);
+ } else if (curPort == PORT_BT) {
+ return BTRWThread.Request(sendbuf, sendlen, requestlen, recbuf,
+ reclen, timeout);
+ } else if (curPort == PORT_USB) {
+ return USBRWThread.Request(sendbuf, sendlen, requestlen, recbuf,
+ reclen, timeout);
+ } else {
+ return false;
+ }
+ }
+
+ public static synchronized void ClrRec() {
+ if (curPort == PORT_NET)
+ NETRWThread.ClrRec();
+ else if (curPort == PORT_BT)
+ BTRWThread.ClrRec();
+ else if (curPort == PORT_USB)
+ USBRWThread.ClrRec();
+ }
+
+ public static synchronized boolean IsEmpty() {
+ if (curPort == PORT_NET)
+ return NETRWThread.IsEmpty();
+ else if (curPort == PORT_BT)
+ return BTRWThread.IsEmpty();
+ else if (curPort == PORT_USB)
+ return USBRWThread.IsEmpty();
+ else
+ return true;
+ }
+
+ public static synchronized byte GetByte() {
+ if (curPort == PORT_NET)
+ return NETRWThread.GetByte();
+ else if (curPort == PORT_BT)
+ return BTRWThread.GetByte();
+ else if (curPort == PORT_USB)
+ return USBRWThread.GetByte();
+ else
+ return 0;
+ }
+
+ public static synchronized boolean IsOpened() {
+ if (curPort == PORT_NET)
+ return NETRWThread.IsOpened();
+ else if (curPort == PORT_BT)
+ return BTRWThread.IsOpened();
+ else if (curPort == PORT_USB)
+ return USBRWThread.IsOpened();
+ else
+ return false;
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/pos/ImageProcessing.java b/app/src/main/java/com/lvrenyang/pos/ImageProcessing.java
new file mode 100644
index 0000000..426e14a
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/pos/ImageProcessing.java
@@ -0,0 +1,269 @@
+package com.lvrenyang.pos;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Bitmap.Config;
+
+public class ImageProcessing {
+ // 转成灰度图
+ public static Bitmap toGrayscale(Bitmap bmpOriginal) {
+ int width, height;
+ height = bmpOriginal.getHeight();
+ width = bmpOriginal.getWidth();
+ Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(bmpGrayscale);
+ Paint paint = new Paint();
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(0);
+ ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
+ paint.setColorFilter(f);
+ c.drawBitmap(bmpOriginal, 0, 0, paint);
+ return bmpGrayscale;
+ }
+
+ // 缩放,暂时需要public以便调试,完成之后不用这个。
+ public static Bitmap resizeImage(Bitmap bitmap, int w, int h) {
+
+ // load the origial Bitmap
+ Bitmap BitmapOrg = bitmap;
+
+ int width = BitmapOrg.getWidth();
+ int height = BitmapOrg.getHeight();
+ int newWidth = w;
+ int newHeight = h;
+
+ // calculate the scale
+ float scaleWidth = ((float) newWidth) / width;
+ float scaleHeight = ((float) newHeight) / height;
+
+ // create a matrix for the manipulation
+ Matrix matrix = new Matrix();
+ // resize the Bitmap
+ matrix.postScale(scaleWidth, scaleHeight);
+ // if you want to rotate the Bitmap
+ // matrix.postRotate(45);
+
+ // recreate the new Bitmap
+ Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width,
+ height, matrix, true);
+
+ // make a Drawable from Bitmap to allow to set the Bitmap
+ // to the ImageView, ImageButton or what ever
+ return resizedBitmap;
+ }
+
+ // 16*16
+ private static int[][] Floyd16x16 = /* Traditional Floyd ordered dither */
+ {
+ { 0, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42,
+ 170 },
+ { 192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74,
+ 234, 106 },
+ { 48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186,
+ 26, 154 },
+ { 240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250,
+ 122, 218, 90 },
+ { 12, 140, 44, 172, 4, 132, 36, 164, 14, 142, 46, 174, 6, 134, 38,
+ 166 },
+ { 204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70,
+ 230, 102 },
+ { 60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182,
+ 22, 150 },
+ { 252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246,
+ 118, 214, 86 },
+ { 3, 131, 35, 163, 11, 139, 43, 171, 1, 129, 33, 161, 9, 137, 41,
+ 169 },
+ { 195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73,
+ 233, 105 },
+ { 51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185,
+ 25, 153 },
+ { 243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249,
+ 121, 217, 89 },
+ { 15, 143, 47, 175, 7, 135, 39, 167, 13, 141, 45, 173, 5, 133, 37,
+ 165 },
+ { 207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69,
+ 229, 101 },
+ { 63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181,
+ 21, 149 },
+ { 254, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245,
+ 117, 213, 85 } };
+ // 8*8
+ private static int[][] Floyd8x8 = { { 0, 32, 8, 40, 2, 34, 10, 42 },
+ { 48, 16, 56, 24, 50, 18, 58, 26 },
+ { 12, 44, 4, 36, 14, 46, 6, 38 },
+ { 60, 28, 52, 20, 62, 30, 54, 22 },
+ { 3, 35, 11, 43, 1, 33, 9, 41 },
+ { 51, 19, 59, 27, 49, 17, 57, 25 },
+ { 15, 47, 7, 39, 13, 45, 5, 37 },
+ { 63, 31, 55, 23, 61, 29, 53, 21 } };
+ // 4*4
+ @SuppressWarnings("unused")
+ private static int[][] Floyd4x4 = { { 0, 8, 2, 10 }, { 12, 4, 14, 6 },
+ { 3, 11, 1, 9 }, { 15, 7, 13, 5 } };
+
+ /**
+ * 将256色灰度图转换为2值图
+ *
+ * @param orgpixels
+ * @param xsize
+ * @param ysize
+ * @param despixels
+ */
+ public static void format_K_dither16x16(int[] orgpixels, int xsize,
+ int ysize, byte[] despixels) {
+ int k = 0;
+ for (int y = 0; y < ysize; y++) {
+
+ for (int x = 0; x < xsize; x++) {
+
+ if ((orgpixels[k] & 0xff) > Floyd16x16[x & 15][y & 15])
+ despixels[k] = 0;// black
+ else
+ despixels[k] = 1;
+
+ k++;
+ }
+ }
+
+ }
+
+ /**
+ * 将256色灰度图转换为2值图
+ *
+ * @param orgpixels
+ * @param xsize
+ * @param ysize
+ * @param despixels
+ */
+ public static void format_K_dither8x8(int[] orgpixels, int xsize,
+ int ysize, byte[] despixels) {
+ int k = 0;
+ for (int y = 0; y < ysize; y++) {
+
+ for (int x = 0; x < xsize; x++) {
+
+ if (((orgpixels[k] & 0xff) >> 2) > Floyd8x8[x & 7][y & 7])
+ despixels[k] = 0;// black
+ else
+ despixels[k] = 1;
+
+ k++;
+ }
+ }
+ }
+
+ public static void format_K_threshold(int[] orgpixels, int xsize,
+ int ysize, byte[] despixels) {
+
+ int graytotal = 0;
+ int grayave = 128;
+ int i, j;
+ int gray;
+
+ int k = 0;
+ for (i = 0; i < ysize; i++) {
+
+ for (j = 0; j < xsize; j++) {
+
+ gray = orgpixels[k] & 0xff;
+ graytotal += gray;
+ k++;
+ }
+ }
+ grayave = graytotal / ysize / xsize;
+
+ // 二值化
+ k = 0;
+ for (i = 0; i < ysize; i++) {
+
+ for (j = 0; j < xsize; j++) {
+
+ gray = orgpixels[k] & 0xff;
+
+ if (gray > grayave)
+ despixels[k] = 0;// white
+ else
+ despixels[k] = 1;
+
+ k++;
+ }
+ }
+ }
+
+ /*
+ * 对灰度图(ARGB_8888)执行平均阀值算法(滤去0和255不考虑)
+ *
+ * 可以先调用toGrayscale从彩色图片生成灰度图 再调用该函数,将灰度图片转成2值图片
+ */
+ public static void format_K_threshold(Bitmap mBitmap) {
+
+ int graytotal = 0;
+ int grayave = 128;
+ int graycnt = 1;
+ int gray;
+
+ int ysize = mBitmap.getHeight();
+ int xsize = mBitmap.getWidth();
+
+ int i, j;
+ for (i = 0; i < ysize; ++i) {
+ for (j = 0; j < xsize; ++j) {
+ gray = mBitmap.getPixel(j, i) & 0xFF;
+ if (gray != 0 && gray != 255) {
+ graytotal += gray;
+ ++graycnt;
+ }
+ }
+ }
+ grayave = graytotal / graycnt;
+
+ // 根据前面的计算,求得一个平均阀值
+ for (i = 0; i < ysize; i++) {
+
+ for (j = 0; j < xsize; j++) {
+
+ gray = mBitmap.getPixel(j, i) & 0xFF;
+
+ if (gray > grayave)
+ mBitmap.setPixel(j, i, Color.WHITE);
+ else
+ mBitmap.setPixel(j, i, Color.BLACK);
+ }
+ }
+ }
+
+ public static Bitmap alignBitmap(Bitmap bitmap, int wbits, int hbits,
+ int color) {
+ // 已经是对齐的,可以直接返回。
+ if ((bitmap.getWidth() % wbits == 0)
+ && (bitmap.getHeight() % hbits == 0))
+ return bitmap;
+
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+ int[] pixels = new int[width * height];
+ bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+
+ int newwidth = (width + wbits - 1) / wbits * wbits;
+ int newheight = (height + hbits - 1) / hbits * hbits;
+ int[] newpixels = new int[newwidth * newheight];
+ Bitmap newbitmap = Bitmap.createBitmap(newwidth, newheight,
+ Config.ARGB_8888);
+ for (int i = 0; i < newheight; ++i) {
+ for (int j = 0; j < newwidth; ++j) {
+ if ((i < height) && (j < width))
+ newpixels[i * newwidth + j] = pixels[i * width + j];
+ else
+ newpixels[i * newwidth + j] = color;
+ }
+ }
+ newbitmap.setPixels(newpixels, 0, newwidth, 0, 0, newwidth, newheight);
+ return newbitmap;
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/pos/Pos.java b/app/src/main/java/com/lvrenyang/pos/Pos.java
new file mode 100644
index 0000000..9dbaf62
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/pos/Pos.java
@@ -0,0 +1,798 @@
+package com.lvrenyang.pos;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.Environment;
+import android.util.Log;
+
+import com.lvrenyang.encryp.DES2;
+import com.lvrenyang.pos.Cmd.ESCCmd;
+import com.lvrenyang.rwbt.BTRWThread;
+import com.lvrenyang.utils.DataUtils;
+
+public class Pos {
+
+ /**
+ * 打印图片的时候,如果端口为蓝牙,那么这个设置值可以设置图片是否使用软件流控。
+ *
+ */
+ public static boolean pictureUseFlowControl = false;
+ private static final String TAG = "Pos";
+
+ /**
+ * 使用软件流控,当打印机收到0x13则停止发送,当打印机收到0x11,则继续发送。
+ *
+ * 只有蓝牙才会使用软件流控。对于网口和USB,该方法无效。
+ *
+ * @param buffer
+ * @param offset
+ * @param count
+ * @param percount
+ * @return
+ */
+ public static int POS_Write_FlowControl(byte[] buffer, int offset,
+ int count, int percount) {
+
+ int idx = 0;
+ int curcount = 0;
+ byte ch;
+ boolean canSend = true;
+ BTRWThread.PauseRead();
+ DataInputStream is = BTRWThread.GetInputStream();
+ DataOutputStream os = BTRWThread.GetOutputStream();
+ Log.i(TAG, "POS_Write_FlowControl");
+ try {
+
+ if (null != is) {
+ is.skipBytes(is.available());
+ }
+
+ while (idx < count) {
+
+ if ((null == is) || (null == os))
+ break;
+
+ if (is.available() > 0) {
+
+ ch = is.readByte();
+
+ Log.w(TAG, "Receive char: " + ch);
+
+ if (0x13 == ch)
+ canSend = false;
+ else if (0x11 == ch)
+ canSend = true;
+ else
+ continue;
+ }
+
+ if (canSend) // 如果没有收到任何字节,继续发送
+ {
+ if (count - idx > percount)
+ curcount = percount;
+ else
+ curcount = count - idx;
+
+ os.write(buffer, offset + idx, curcount);
+
+ idx += curcount;
+ }
+ Log.i(TAG, "idx:" + idx);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ BTRWThread.ResumeRead();
+ return idx;
+ }
+
+ private static synchronized int POS_Write_Safety(byte[] buffer, int offset,
+ int count, int percount) {
+ int idx = 0;
+ int curcount = 0;
+ byte[] reset = { 0x1b, 0x40 };
+ byte[] precbuf = new byte[1];
+ int timeout = 1000;
+ if (POS_QueryStatus(precbuf, timeout)) {
+ while (idx < count) {
+ if (count - idx > percount)
+ curcount = percount;
+ else
+ curcount = count - idx;
+
+ IO.Write(buffer, offset + idx, curcount);
+ if (!POS_QueryStatus(precbuf, timeout))
+ break;
+ else
+ IO.Write(reset, 0, reset.length);
+ idx += curcount;
+ }
+ }
+ return idx;
+ }
+
+ public static void saveDataToBin(String fileName, byte[] data) {
+ File f = new File(Environment.getExternalStorageDirectory().getPath(),
+ fileName);
+ try {
+ f.createNewFile();
+ } catch (IOException e) {
+ }
+ FileOutputStream fOut = null;
+ try {
+ fOut = new FileOutputStream(f);
+ fOut.write(data, 0, data.length);
+ fOut.flush();
+ fOut.close();
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ }
+ }
+
+ // nWidth必须为8的倍数,这个只需在上层控制即可
+ // 之所以弄成一维数组,是因为一维数组速度会快一点
+ private static int[] p0 = { 0, 0x80 };
+ private static int[] p1 = { 0, 0x40 };
+ private static int[] p2 = { 0, 0x20 };
+ private static int[] p3 = { 0, 0x10 };
+ private static int[] p4 = { 0, 0x08 };
+ private static int[] p5 = { 0, 0x04 };
+ private static int[] p6 = { 0, 0x02 };
+
+ // 1行作为1个图片,这样打印不会乱
+ @SuppressWarnings("unused")
+ private static byte[] pixToCmd(byte[] src, int nWidth, int nMode) {
+ // nWidth = 384; nHeight = 582;
+ int nHeight = src.length / nWidth;
+ byte[] data = new byte[8 + (src.length / 8)];
+ data[0] = 0x1d;
+ data[1] = 0x76;
+ data[2] = 0x30;
+ data[3] = (byte) (nMode & 0x01);
+ data[4] = (byte) ((nWidth / 8) % 0x100);// (xl+xh*256)*8 = nWidth
+ data[5] = (byte) ((nWidth / 8) / 0x100);
+ data[6] = (byte) ((nHeight) % 0x100);// (yl+yh*256) = nHeight
+ data[7] = (byte) ((nHeight) / 0x100);
+ int k = 0;
+ for (int i = 8; i < data.length; i++) {
+ // 不行,没有加权
+ data[i] = (byte) (p0[src[k]] + p1[src[k + 1]] + p2[src[k + 2]]
+ + p3[src[k + 3]] + p4[src[k + 4]] + p5[src[k + 5]]
+ + p6[src[k + 6]] + src[k + 7]);
+ k = k + 8;
+ }
+ return data;
+
+ }
+
+ private static byte[] eachLinePixToCmd(byte[] src, int nWidth, int nMode) {
+ int nHeight = src.length / nWidth;
+ int nBytesPerLine = nWidth / 8;
+ byte[] data = new byte[nHeight * (8 + nBytesPerLine)];
+ int offset = 0;
+ int k = 0;
+ for (int i = 0; i < nHeight; i++) {
+ offset = i * (8 + nBytesPerLine);
+ data[offset + 0] = 0x1d;
+ data[offset + 1] = 0x76;
+ data[offset + 2] = 0x30;
+ data[offset + 3] = (byte) (nMode & 0x01);
+ data[offset + 4] = (byte) (nBytesPerLine % 0x100);
+ data[offset + 5] = (byte) (nBytesPerLine / 0x100);
+ data[offset + 6] = 0x01;
+ data[offset + 7] = 0x00;
+ for (int j = 0; j < nBytesPerLine; j++) {
+ data[offset + 8 + j] = (byte) (p0[src[k]] + p1[src[k + 1]]
+ + p2[src[k + 2]] + p3[src[k + 3]] + p4[src[k + 4]]
+ + p5[src[k + 5]] + p6[src[k + 6]] + src[k + 7]);
+ k = k + 8;
+ }
+ }
+
+ return data;
+ }
+
+ /**
+ * 将ARGB图转换为二值图,0代表黑,1代表白
+ *
+ * @param mBitmap
+ * @return
+ */
+ public static byte[] bitmapToBWPix(Bitmap mBitmap) {
+
+ int[] pixels = new int[mBitmap.getWidth() * mBitmap.getHeight()];
+ byte[] data = new byte[mBitmap.getWidth() * mBitmap.getHeight()];
+
+ mBitmap.getPixels(pixels, 0, mBitmap.getWidth(), 0, 0,
+ mBitmap.getWidth(), mBitmap.getHeight());
+
+ // for the toGrayscale, we need to select a red or green or blue color
+ ImageProcessing.format_K_dither16x16(pixels, mBitmap.getWidth(),
+ mBitmap.getHeight(), data);
+
+ return data;
+ }
+
+ @SuppressWarnings("unused")
+ private static void saveDataToBin(byte[] data) {
+ File f = new File(Environment.getExternalStorageDirectory().getPath(),
+ "Btatotest.bin");
+ try {
+ f.createNewFile();
+ } catch (IOException e) {
+ }
+ FileOutputStream fOut = null;
+ try {
+ fOut = new FileOutputStream(f);
+ fOut.write(data, 0, data.length);
+ fOut.flush();
+ fOut.close();
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ }
+ }
+
+ public static void saveMyBitmap(Bitmap mBitmap, String name) {
+ File f = new File(Environment.getExternalStorageDirectory().getPath(),
+ name);
+ try {
+ f.createNewFile();
+ } catch (IOException e) {
+ }
+ FileOutputStream fOut = null;
+ try {
+ fOut = new FileOutputStream(f);
+ mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
+ fOut.flush();
+ fOut.close();
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {
+ }
+
+ }
+
+ private static byte[] pixToRaster(byte[] src) {
+
+ byte[] data = new byte[src.length / 8];
+ int k = 0;
+ for (int i = 0; i < data.length; i++) {
+ // 不行,没有加权
+ data[i] = (byte) (p0[src[k]] + p1[src[k + 1]] + p2[src[k + 2]]
+ + p3[src[k + 3]] + p4[src[k + 4]] + p5[src[k + 5]]
+ + p6[src[k + 6]] + src[k + 7]);
+ k = k + 8;
+ }
+ return data;
+ }
+
+ public static byte[] genRasterData(Bitmap mBitmap) {
+
+ Bitmap grayBitmap = ImageProcessing.toGrayscale(mBitmap);
+ byte[] dithered = bitmapToBWPix(grayBitmap);
+ byte[] data = pixToRaster(dithered);
+ return data;
+
+ }
+
+ public static void POS_PrintPicture(Bitmap mBitmap, int nWidth, int nMode) {
+
+ // 先转黑白,再调用函数缩放位图
+ // 不转黑白
+ int width = ((nWidth + 7) / 8) * 8;
+ int height = mBitmap.getHeight() * width / mBitmap.getWidth();
+ height = ((height + 7) / 8) * 8;
+ Bitmap rszBitmap = ImageProcessing.resizeImage(mBitmap, width, height);
+ Bitmap grayBitmap = ImageProcessing.toGrayscale(rszBitmap);
+ byte[] dithered = bitmapToBWPix(grayBitmap);
+
+ byte[] data = eachLinePixToCmd(dithered, width, nMode);
+
+ if (IO.PORT_BT == IO.GetCurPort() && pictureUseFlowControl) {
+ // 基本超时1000ms 40k的数据4000ms超时
+ POS_Write_FlowControl(data, 0, data.length, 128);
+ } else {
+ // 当width = 384时,一行数据占48个字节,加上8个字节头,总共width/8+8个字节。
+ int nBytesPerLine = width / 8 + 8;
+ int nLinesPerTest = 1;
+ if (IO.PORT_BT == IO.GetCurPort())
+ nLinesPerTest = 30;
+ else if (IO.PORT_NET == IO.GetCurPort())
+ nLinesPerTest = 5;
+ else if (IO.PORT_USB == IO.GetCurPort())
+ nLinesPerTest = 60;
+
+ POS_Write_Safety(data, 0, data.length, nBytesPerLine
+ * nLinesPerTest);
+ // IO.Write(data, 0, data.length);
+ }
+ }
+
+ /**
+ * 这个打印灰度图片的算法,会使用平均灰度值作为阀值,将灰度图片二值化。
+ *
+ * @param mBitmap
+ * 灰度图
+ * @param nWidth
+ * @param nMode
+ */
+ public static void POS_PrintBWPic(Bitmap mBitmap, int nWidth, int nMode) {
+ // 先转黑白,再调用函数缩放位图
+ // 不转黑白
+ int width = ((nWidth + 7) / 8) * 8;
+ int height = mBitmap.getHeight() * width / mBitmap.getWidth();
+ height = ((height + 7) / 8) * 8;
+
+ saveMyBitmap(mBitmap, "origin.png");
+
+ Bitmap rszBitmap = mBitmap;
+ if (mBitmap.getWidth() != width)
+ rszBitmap = ImageProcessing.resizeImage(mBitmap, width, height);
+ saveMyBitmap(rszBitmap, "rsz.png");
+
+ Bitmap grayBitmap = ImageProcessing.toGrayscale(rszBitmap);
+ saveMyBitmap(grayBitmap, "gray.png");
+ byte[] dithered = thresholdToBWPic(grayBitmap);
+
+ // 将转换过的图片,保存到文件,以下图片,仅作调试使用。
+ overWriteBitmap(grayBitmap, dithered);
+ saveMyBitmap(grayBitmap, "dithered.png");
+
+ byte[] data = eachLinePixToCmd(dithered, width, nMode);
+
+ // 将data保存到文件,使用电脑打印
+ // FileUtils.AddToFile(data, 0, data.length, FileUtils.dump_bin);
+
+ if (IO.PORT_BT == IO.GetCurPort() && pictureUseFlowControl) {
+ // 基本超时1000ms 40k的数据4000ms超时
+ int send = POS_Write_FlowControl(data, 0, data.length, 128);
+ if (data.length != send) {
+ Log.i(TAG, "POS_Write_FlowControl Error. data.length:"
+ + data.length + " send:" + send);
+ }
+ } else {
+ // 当width = 384时,一行数据占48个字节,加上8个字节头,总共width/8+8个字节。
+ int nBytesPerLine = width / 8 + 8;
+ int nLinesPerTest = 1;
+ if (IO.PORT_BT == IO.GetCurPort())
+ nLinesPerTest = 30;
+ else if (IO.PORT_NET == IO.GetCurPort())
+ nLinesPerTest = 5;
+ else if (IO.PORT_USB == IO.GetCurPort())
+ nLinesPerTest = 60;
+
+ POS_Write_Safety(data, 0, data.length, nBytesPerLine
+ * nLinesPerTest);
+ // IO.Write(data, 0, data.length);
+ }
+
+ }
+
+ private static byte[] thresholdToBWPic(Bitmap mBitmap) {
+ int[] pixels = new int[mBitmap.getWidth() * mBitmap.getHeight()];
+ byte[] data = new byte[mBitmap.getWidth() * mBitmap.getHeight()];
+
+ mBitmap.getPixels(pixels, 0, mBitmap.getWidth(), 0, 0,
+ mBitmap.getWidth(), mBitmap.getHeight());
+
+ // for the toGrayscale, we need to select a red or green or blue color
+ ImageProcessing.format_K_threshold(pixels, mBitmap.getWidth(),
+ mBitmap.getHeight(), data);
+
+ return data;
+ }
+
+ private static void overWriteBitmap(Bitmap mBitmap, byte[] dithered) {
+ int ysize = mBitmap.getHeight();
+ int xsize = mBitmap.getWidth();
+
+ int k = 0;
+ for (int i = 0; i < ysize; i++) {
+
+ for (int j = 0; j < xsize; j++) {
+
+ if (dithered[k] == 0) {
+ mBitmap.setPixel(j, i, Color.WHITE);
+ } else {
+ mBitmap.setPixel(j, i, Color.BLACK);
+ }
+ k++;
+ }
+ }
+ }
+
+ public static Bitmap getBWedBitmap(Bitmap mBitmap, int nWidth) {
+ // 先转黑白,再调用函数缩放位图
+ // 不转黑白
+ int width = ((nWidth + 7) / 8) * 8;
+ int height = mBitmap.getHeight() * width / mBitmap.getWidth();
+ height = ((height + 7) / 8) * 8;
+
+ Bitmap rszBitmap = mBitmap;
+ if (mBitmap.getWidth() != width)
+ rszBitmap = ImageProcessing.resizeImage(mBitmap, width, height);
+
+ Bitmap grayBitmap = ImageProcessing.toGrayscale(rszBitmap);
+
+ byte[] dithered = thresholdToBWPic(grayBitmap);
+ // byte[] dithered = bitmapToBWPix(grayBitmap);
+
+ // 将转换过的图片,保存到文件,以下图片,仅作调试使用。
+ overWriteBitmap(grayBitmap, dithered);
+
+ return grayBitmap;
+ }
+
+ // nFontType 0 标准 1 压缩 其他不指定
+ public static void POS_S_TextOut(String pszString, String encoding,
+ int nOrgx, int nWidthTimes, int nHeightTimes, int nFontType,
+ int nFontStyle) {
+ if (nOrgx > 65535 | nOrgx < 0 | nWidthTimes > 7 | nWidthTimes < 0
+ | nHeightTimes > 7 | nHeightTimes < 0 | nFontType < 0
+ | nFontType > 4 | (pszString.length() == 0))
+ return;
+
+ Cmd.ESCCmd.ESC_dollors_nL_nH[2] = (byte) (nOrgx % 0x100);
+ Cmd.ESCCmd.ESC_dollors_nL_nH[3] = (byte) (nOrgx / 0x100);
+
+ byte[] intToWidth = { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70 };
+ byte[] intToHeight = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+ Cmd.ESCCmd.GS_exclamationmark_n[2] = (byte) (intToWidth[nWidthTimes] + intToHeight[nHeightTimes]);
+
+ byte[] tmp_ESC_M_n = Cmd.ESCCmd.ESC_M_n;
+ if ((nFontType == 0) || (nFontType == 1))
+ tmp_ESC_M_n[2] = (byte) nFontType;
+ else
+ tmp_ESC_M_n = new byte[0];
+
+ // 字体风格
+ // 暂不支持平滑处理
+ Cmd.ESCCmd.GS_E_n[2] = (byte) ((nFontStyle >> 3) & 0x01);
+
+ Cmd.ESCCmd.ESC_line_n[2] = (byte) ((nFontStyle >> 7) & 0x03);
+ Cmd.ESCCmd.FS_line_n[2] = (byte) ((nFontStyle >> 7) & 0x03);
+
+ Cmd.ESCCmd.ESC_lbracket_n[2] = (byte) ((nFontStyle >> 9) & 0x01);
+
+ Cmd.ESCCmd.GS_B_n[2] = (byte) ((nFontStyle >> 10) & 0x01);
+
+ Cmd.ESCCmd.ESC_V_n[2] = (byte) ((nFontStyle >> 12) & 0x01);
+
+ byte[] pbString = null;
+ try {
+ pbString = pszString.getBytes(encoding);
+ } catch (UnsupportedEncodingException e) {
+ return;
+ }
+
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ Cmd.ESCCmd.ESC_dollors_nL_nH, Cmd.ESCCmd.GS_exclamationmark_n,
+ tmp_ESC_M_n, Cmd.ESCCmd.GS_E_n, Cmd.ESCCmd.ESC_line_n,
+ Cmd.ESCCmd.FS_line_n, Cmd.ESCCmd.ESC_lbracket_n,
+ Cmd.ESCCmd.GS_B_n, Cmd.ESCCmd.ESC_V_n, pbString });
+
+ IO.Write(data, 0, data.length);
+
+ }
+
+ public static void POS_FeedLine() {
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] { Cmd.ESCCmd.CR,
+ Cmd.ESCCmd.LF });
+ // byte[] data = Cmd.ESCCmd.LF;
+ IO.Write(data, 0, data.length);
+ }
+
+ public static void POS_S_Align(int align) {
+ if (align < 0 || align > 2)
+ return;
+ byte[] data = Cmd.ESCCmd.ESC_a_n;
+ data[2] = (byte) align;
+ IO.Write(data, 0, data.length);
+ }
+
+ public static void POS_SetLineHeight(int nHeight) {
+ if (nHeight < 0 || nHeight > 255)
+ return;
+ byte[] data = Cmd.ESCCmd.ESC_3_n;
+ data[2] = (byte) nHeight;
+ IO.Write(data, 0, data.length);
+ }
+
+ public static void POS_S_SetBarcode(String strCodedata, int nOrgx,
+ int nType, int nWidthX, int nHeight, int nHriFontType,
+ int nHriFontPosition) {
+ if (nOrgx < 0 | nOrgx > 65535 | nType < 0x41 | nType > 0x49
+ | nWidthX < 2 | nWidthX > 6 | nHeight < 1 | nHeight > 255)
+ return;
+
+ byte[] bCodeData = null;
+ try {
+ bCodeData = strCodedata.getBytes("GBK");
+ } catch (UnsupportedEncodingException e) {
+ return;
+ }
+ ;
+
+ Cmd.ESCCmd.ESC_dollors_nL_nH[2] = (byte) (nOrgx % 0x100);
+ Cmd.ESCCmd.ESC_dollors_nL_nH[3] = (byte) (nOrgx / 0x100);
+ Cmd.ESCCmd.GS_w_n[2] = (byte) nWidthX;
+ Cmd.ESCCmd.GS_h_n[2] = (byte) nHeight;
+ Cmd.ESCCmd.GS_f_n[2] = (byte) (nHriFontType & 0x01);
+ Cmd.ESCCmd.GS_H_n[2] = (byte) (nHriFontPosition & 0x03);
+ Cmd.ESCCmd.GS_k_m_n_[2] = (byte) nType;
+ Cmd.ESCCmd.GS_k_m_n_[3] = (byte) bCodeData.length;
+
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ Cmd.ESCCmd.ESC_dollors_nL_nH, Cmd.ESCCmd.GS_w_n,
+ Cmd.ESCCmd.GS_h_n, Cmd.ESCCmd.GS_f_n, Cmd.ESCCmd.GS_H_n,
+ Cmd.ESCCmd.GS_k_m_n_, bCodeData });
+ IO.Write(data, 0, data.length);
+
+ }
+
+ public static void POS_S_SetQRcode(String strCodedata, int nWidthX,
+ int nErrorCorrectionLevel) {
+
+ if (nWidthX < 2 | nWidthX > 6 | nErrorCorrectionLevel < 1
+ | nErrorCorrectionLevel > 4)
+ return;
+
+ byte[] bCodeData = null;
+ try {
+ bCodeData = strCodedata.getBytes("GBK");
+ } catch (UnsupportedEncodingException e) {
+ return;
+ }
+ ;
+
+ Cmd.ESCCmd.GS_w_n[2] = (byte) nWidthX;
+ Cmd.ESCCmd.GS_k_m_v_r_nL_nH[4] = (byte) nErrorCorrectionLevel;
+ Cmd.ESCCmd.GS_k_m_v_r_nL_nH[5] = (byte) (bCodeData.length & 0xff);
+ Cmd.ESCCmd.GS_k_m_v_r_nL_nH[6] = (byte) ((bCodeData.length & 0xff00) >> 8);
+
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ Cmd.ESCCmd.GS_w_n, Cmd.ESCCmd.GS_k_m_v_r_nL_nH, bCodeData });
+ IO.Write(data, 0, data.length);
+
+ }
+
+ public static void POS_EPSON_SetQRCode(String strCodedata, int nWidthX,
+ int nErrorCorrectionLevel) {
+ if (nWidthX < 2 | nWidthX > 6 | nErrorCorrectionLevel < 1
+ | nErrorCorrectionLevel > 4)
+ return;
+
+ byte[] bCodeData = null;
+ try {
+ bCodeData = strCodedata.getBytes("GBK");
+ } catch (UnsupportedEncodingException e) {
+ return;
+ }
+ ;
+
+ Cmd.ESCCmd.GS_w_n[2] = (byte) nWidthX;
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_69_n[7] = (byte) (47 + nErrorCorrectionLevel);
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_80_m__d1dk[3] = (byte) ((bCodeData.length + 3) & 0xff);
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_80_m__d1dk[4] = (byte) (((bCodeData.length + 3) & 0xff00) >> 8);
+
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ Cmd.ESCCmd.GS_w_n, Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_67_n,
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_69_n,
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_80_m__d1dk, bCodeData,
+ Cmd.ESCCmd.GS_leftbracket_k_pL_pH_cn_fn_m });
+ IO.Write(data, 0, data.length);
+
+ }
+
+ public static void POS_SetKey(byte[] key) {
+ byte[] data = Cmd.ESCCmd.DES_SETKEY;
+ for (int i = 0; i < key.length; i++) {
+ data[i + 5] = key[i];
+ }
+ // 设置DES密钥,打印机不会返回,需要发送命令设置
+ IO.Write(data, 0, data.length);
+ }
+
+ public static boolean POS_CheckKey(byte[] key, byte[] random) {
+ boolean result = false;
+ final int HeaderSize = 5;
+ byte[] recHeader = new byte[HeaderSize];
+ byte[] recData = null;
+ int rec = 0;
+ int recDataLen = 0;
+ byte[] randomlen = new byte[2];
+ randomlen[0] = (byte) (random.length & 0xff);
+ randomlen[1] = (byte) ((random.length >> 8) & 0xff);
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ Cmd.ESCCmd.DES_ENCRYPT, randomlen, random });
+ IO.Write(data, 0, data.length);
+ rec = IO.Read(recHeader, 0, HeaderSize, 1000);
+ if (rec != HeaderSize)
+ return false;
+ recDataLen = (recHeader[3] & 0xff) + ((recHeader[4] << 8) & 0xff);
+ recData = new byte[recDataLen];
+ rec = IO.Read(recData, 0, recDataLen, 1000);
+ if (rec != recDataLen)
+ return false;
+
+ byte[] encrypted = recData;
+ byte[] decrypted = new byte[encrypted.length + 1];
+ /**
+ * 对数据进行解密
+ */
+ DES2 des2 = new DES2();
+ // 初始化密钥
+ des2.yxyDES2_InitializeKey(key);
+ des2.yxyDES2_DecryptAnyLength(encrypted, decrypted, encrypted.length);
+ result = DataUtils.bytesEquals(random, 0, decrypted, 0, random.length);
+ if (!result) {
+ Log.v(TAG + " random", DataUtils.bytesToStr(random));
+ Log.v(TAG + " decryp", DataUtils.bytesToStr(decrypted));
+ }
+ return result;
+ }
+
+ /**
+ * 复位打印机
+ */
+ public static void POS_Reset() {
+ byte[] data = Cmd.ESCCmd.ESC_ALT;
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 设置移动单位
+ *
+ * @param nHorizontalMU
+ * @param nVerticalMU
+ */
+ public static void POS_SetMotionUnit(int nHorizontalMU, int nVerticalMU) {
+ if (nHorizontalMU < 0 || nHorizontalMU > 255 || nVerticalMU < 0
+ || nVerticalMU > 255)
+ return;
+
+ byte[] data = Cmd.ESCCmd.GS_P_x_y;
+ data[2] = (byte) nHorizontalMU;
+ data[3] = (byte) nVerticalMU;
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 设置字符集和代码页
+ *
+ * @param nCharSet
+ * @param nCodePage
+ */
+ public static void POS_SetCharSetAndCodePage(int nCharSet, int nCodePage) {
+ if (nCharSet < 0 | nCharSet > 15 | nCodePage < 0 | nCodePage > 19
+ | (nCodePage > 10 & nCodePage < 16))
+ return;
+
+ Cmd.ESCCmd.ESC_R_n[2] = (byte) nCharSet;
+ Cmd.ESCCmd.ESC_t_n[2] = (byte) nCodePage;
+ byte[] data = DataUtils.byteArraysToBytes(new byte[][] {
+ ESCCmd.ESC_R_n, ESCCmd.ESC_t_n });
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 设置字符右间距
+ *
+ * @param nDistance
+ */
+ public static void POS_SetRightSpacing(int nDistance) {
+ if (nDistance < 0 | nDistance > 255)
+ return;
+
+ Cmd.ESCCmd.ESC_SP_n[2] = (byte) nDistance;
+ byte[] data = Cmd.ESCCmd.ESC_SP_n;
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 设置打印区域宽度
+ *
+ * @param nWidth
+ */
+ public static void POS_S_SetAreaWidth(int nWidth) {
+ if (nWidth < 0 | nWidth > 65535)
+ return;
+
+ byte nL = (byte) (nWidth % 0x100);
+ byte nH = (byte) (nWidth / 0x100);
+ Cmd.ESCCmd.GS_W_nL_nH[2] = nL;
+ Cmd.ESCCmd.GS_W_nL_nH[3] = nH;
+ byte[] data = Cmd.ESCCmd.GS_W_nL_nH;
+ IO.Write(data, 0, data.length);
+ }
+
+ public static void POS_FillZero(int nCount) {
+ byte[] data = new byte[nCount];
+ IO.Write(data, 0, data.length);
+ }
+
+ /**
+ * 使用1D 72 01这个命令,获取打印机状态。
+ *
+ * @param precbuf
+ * 长度为1的字节数组,存储返回的状态。
+ * @param timeout
+ * @return
+ */
+ public static boolean POS_QueryStatus(byte precbuf[], int timeout) {
+
+ int retry;
+ byte pcmdbuf[] = { 0x1D, 0x72, 0x01 };
+ //byte pcmdbuf[] = { 0x10, 0x04, 0x01 };
+
+ retry = 3;
+ while (retry > 0) {
+ retry--;
+
+ /**
+ * 数据接收归零
+ */
+ IO.ClrRec();
+ IO.Write(pcmdbuf, 0, pcmdbuf.length);
+ if (IO.Read(precbuf, 0, 1, timeout) == 1)
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean POS_RTQueryStatus(byte precbuf[], int timeout) {
+
+ int retry;
+ // byte pcmdbuf[] = { 0x1D, 0x72, 0x01 };
+ byte pcmdbuf[] = { 0x10, 0x04, 0x01 };
+
+ retry = 3;
+ while (retry > 0) {
+ retry--;
+
+ /**
+ * 数据接收归零
+ */
+ IO.ClrRec();
+ IO.Write(pcmdbuf, 0, pcmdbuf.length);
+ if (IO.Read(precbuf, 0, 1, timeout) == 1)
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 只对特定的嵌入式蓝牙打印机有效
+ *
+ * @param buffer
+ * @param offset
+ * @param count
+ */
+ public static boolean EMBEDDED_WriteToUart(byte[] buffer, int offset,
+ int count) {
+
+ if (IO.PORT_BT == IO.GetCurPort()) {
+ byte[] header = { 0x1F, 'R', 0x00, 0x00 };
+ header[2] = (byte) ((count >> 8) & 0xFF);
+ header[3] = (byte) (count & 0xff);
+
+ byte[] data = new byte[header.length + count];
+ DataUtils.copyBytes(header, 0, data, 0, header.length);
+ DataUtils.copyBytes(buffer, offset, data, header.length, count);
+ if (IO.Write(data, 0, data.length) == data.length)
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/pos/Protocol.java b/app/src/main/java/com/lvrenyang/pos/Protocol.java
new file mode 100644
index 0000000..09ac458
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/pos/Protocol.java
@@ -0,0 +1,143 @@
+package com.lvrenyang.pos;
+
+import android.util.Log;
+
+import com.lvrenyang.rwbuf.ProtocolHandler;
+import com.lvrenyang.utils.DataUtils;
+
+/**
+ * 协议包
+ *
+ * @author Administrator
+ *
+ */
+public class Protocol {
+
+ private static final String TAG = "Protocol";
+
+ private static ProtocolHandler KCBuffer = new ProtocolHandler(0x1000);
+
+ /**
+ *
+ * @param cmd
+ * 0x20
+ * @param para
+ * 0x00
+ * @param sendlen
+ * 0x08
+ * @param psendbuf
+ * "DEVICE??"
+ * @param reclen
+ * @param precbuf
+ * @param timeout
+ * 1000
+ * @return
+ */
+ public static synchronized boolean ProtoPackage(int cmd, // {0x2e, 0x2e}
+ int para, // {0x0, 0x4}
+ int sendlen, // {0x100, 0x100}
+ byte psendbuf[], // {buf0, buf1}
+ int reclen[], // {0x0, 0x100} 返回的数据
+ byte precbuf[], // {null, buf2} 返回的数据
+ int timeout) {
+ int j;
+ int retry;
+ long time;
+ byte pcmdbuf[] = new byte[12 + sendlen];
+
+ pcmdbuf[0] = (byte) (KCBuffer.ProtoHeaderOut >> 8);
+ pcmdbuf[1] = (byte) (KCBuffer.ProtoHeaderOut);
+ pcmdbuf[2] = (byte) (cmd);
+ pcmdbuf[3] = (byte) (cmd >> 8);
+ pcmdbuf[4] = (byte) (para);
+ pcmdbuf[5] = (byte) (para >> 8);
+ pcmdbuf[6] = (byte) (para >> 16);
+ pcmdbuf[7] = (byte) (para >> 24);
+ pcmdbuf[8] = (byte) (sendlen);
+ pcmdbuf[9] = (byte) (sendlen >> 8);
+ pcmdbuf[10] = 0;
+ pcmdbuf[11] = 0;
+ for (j = 0; j < 10; j++)
+ pcmdbuf[10] ^= pcmdbuf[j];
+ for (j = 0; j < sendlen; j++) {
+ pcmdbuf[11] ^= psendbuf[j];
+ pcmdbuf[12 + j] = psendbuf[j];
+ }
+ reclen[0] = 0;
+
+ retry = 3;
+ while (retry > 0) {
+ retry--;
+
+ /**
+ * 数据接收和协议处理归零
+ */
+ KCBuffer.Count = 0;
+ IO.ClrRec();
+
+ if (!IO.IsOpened()) {
+ Log.v(TAG, "Socket is null pointer");
+ return false;
+ }
+
+ if (IO.Write(pcmdbuf, 0, 12 + sendlen) != 12 + sendlen) {
+ Log.v(TAG, "Socket not connected");
+ return false;
+ }
+ Log.v(TAG + " Send", DataUtils.bytesToStr(pcmdbuf, 0, 12)
+ .toString());
+ if (sendlen > 0)
+ Log.v(TAG + " Send", DataUtils.bytesToStr(pcmdbuf, 12, sendlen)
+ .toString());
+ /* 准备接收数据 */
+ time = System.currentTimeMillis();
+ while (true) {
+ if ((System.currentTimeMillis() - time) > timeout)
+ break;
+
+ KCBuffer.KcCmd = 0;
+ KCBuffer.KcPara = 0;
+ if (!IO.IsEmpty()) {
+ byte ch = IO.GetByte();
+ KCBuffer.HandleKcUartChar(ch);
+
+ if ((KCBuffer.KcCmd == cmd) && (KCBuffer.KcPara == para)) {
+ reclen[0] = (KCBuffer.Buffer[8] & 0xFF)
+ + (KCBuffer.Buffer[9] & 0xFF) * 0x100;
+ DataUtils.copyBytes(KCBuffer.Buffer, 12, precbuf, 0,
+ reclen[0]);
+
+ Log.v(TAG, "recv: cmd=" + cmd + " para=" + para);
+ Log.v(TAG + " Recv",
+ DataUtils.bytesToStr(KCBuffer.Buffer, 0, 12)
+ .toString());
+ if (reclen[0] > 0)
+ Log.v(TAG + " Recv",
+ DataUtils.bytesToStr(KCBuffer.Buffer, 12,
+ reclen[0]).toString());
+
+ KCBuffer.KcCmd = 0;
+ KCBuffer.KcPara = 0;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /* 通讯测试使用标准EPSON命令。1D 72 n,请参考Pos */
+ /*
+ * public static synchronized boolean Test() {
+ *
+ * String strTest = "DEVICE??"; int cmd = 0x20; int para = 0x00; byte[]
+ * psendbuf = strTest.getBytes(); int sendlen = psendbuf.length; int[]
+ * reclen = new int[1]; byte[] precbuf = new byte[512]; int timeout = 1000;
+ *
+ * return ProtoPackage(cmd, para, sendlen, psendbuf, reclen, precbuf,
+ * timeout);
+ *
+ * //return true; }
+ */
+}
diff --git a/app/src/main/java/com/lvrenyang/rwbt/BTHeartBeatThread.java b/app/src/main/java/com/lvrenyang/rwbt/BTHeartBeatThread.java
new file mode 100644
index 0000000..08c01d6
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwbt/BTHeartBeatThread.java
@@ -0,0 +1,161 @@
+package com.lvrenyang.rwbt;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+public class BTHeartBeatThread extends Thread {
+
+ public static final int MSG_BTHEARTBEATTHREAD_UPDATESTATUS = 200200;
+ private static volatile BTHeartBeatThread heartBeatThread = null;
+
+ private static final int HEARTBEATHANDLER_STARTUP = 1000;
+
+ private static Handler targetHandler = null;
+ private static Handler heartBeatHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ // private static final Object RWLOCK = new Object();
+ private static boolean pause = false;
+ private static final Lock iofinished = new ReentrantLock();
+
+ private static int StatusOK = 0;
+ private static int Status = 0;
+
+ public BTHeartBeatThread(Handler mHandler) {
+ targetHandler = mHandler;
+ }
+
+ public static BTHeartBeatThread InitInstant(Handler mHandler) {
+ if (heartBeatThread == null) {
+ synchronized (BTHeartBeatThread.class) {
+ if (heartBeatThread == null) {
+ heartBeatThread = new BTHeartBeatThread(mHandler);
+ }
+ }
+ }
+ return heartBeatThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ heartBeatHandler = new BTHeartBeatHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class BTHeartBeatHandler extends Handler {
+
+ private void SendOutStatus() {
+ Message smsg = targetHandler
+ .obtainMessage(MSG_BTHEARTBEATTHREAD_UPDATESTATUS);
+ smsg.arg1 = StatusOK;
+ smsg.arg2 = Status;
+ targetHandler.sendMessage(smsg);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ /**
+ * BT 做心跳数据包用10 04 01命令
+ */
+ case HEARTBEATHANDLER_STARTUP: {
+ byte[] buffer = { 0x10, 0x04, 0x01 };
+ int buffersize = 3;
+ int sendlen = 0;
+
+ byte[] rec = { 0x00 };
+ int reclen = 0;
+ int timeout = 2000;
+
+ int intertimeout = 2000;
+ final int threshold = 3;
+ int curUnrespond = 0;
+ while (true) {
+ try {
+ Thread.sleep(intertimeout);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ }
+ if (pause)
+ continue;
+
+ iofinished.lock();
+ BTRWThread.ClrRec();// 只调用clearrec也需要这个锁,调用read也需要这个锁
+ sendlen = BTRWThread.Write(buffer, 0, buffersize);
+ reclen = BTRWThread.Read(rec, 0, 1, timeout);
+ iofinished.unlock();
+
+ if (sendlen != buffersize) // 写出错,流的问题。直接break
+ {
+ StatusOK = 0;
+ Status = 0;
+ SendOutStatus();
+ break;
+ }
+
+ if (reclen == 1) {
+ curUnrespond = 0;
+ StatusOK = 1;
+ Status = rec[0];
+ } else {
+ curUnrespond++;
+ StatusOK = 0;
+ Status = 0;
+ }
+
+ SendOutStatus();
+
+ if (curUnrespond >= threshold)
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ public static void BeginHeartBeat() {
+ Message msg = heartBeatHandler.obtainMessage(HEARTBEATHANDLER_STARTUP);
+ heartBeatHandler.sendMessage(msg);
+ }
+
+ public static void PauseHeartBeat() {
+ pause = true;
+ iofinished.lock();
+ iofinished.unlock();
+ }
+
+ public static void ResumeHeartBeat() {
+ pause = false;
+ }
+
+ public static void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ heartBeatThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwbt/BTRWThread.java b/app/src/main/java/com/lvrenyang/rwbt/BTRWThread.java
new file mode 100644
index 0000000..f051f01
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwbt/BTRWThread.java
@@ -0,0 +1,422 @@
+package com.lvrenyang.rwbt;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+import com.lvrenyang.callback.RecvCallBack;
+import com.lvrenyang.rwbuf.RxBuffer;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+public class BTRWThread extends Thread {
+ private static final String TAG = "BTRWThread";
+ // private static final Object SLOCK = new Object(); // 所有对流的操作,都需要上锁。
+ private static volatile BTRWThread btRWThread = null;
+ private static boolean bThreadWait = false;
+ private static boolean bReadPaused = false;
+ private static final Object oThreadControl = new Object();
+
+ private static final int BTRWHANDLER_READ = 1000;
+ private static final UUID uuid = UUID
+ .fromString("00001101-0000-1000-8000-00805F9B34FB");
+
+ private static Handler btrwHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ private static BluetoothSocket s = null;
+ private static DataInputStream is = null;
+ private static DataOutputStream os = null;
+ private static boolean isOpened = false;
+
+ private static RecvCallBack callBack = null;
+ private static final Object NULLLOCK = new Object();
+ private static RxBuffer BTRXBuffer = new RxBuffer(0x1000);
+
+ private BTRWThread() {
+ threadInitOK = false;
+ }
+
+ public static BTRWThread InitInstant() {
+ if (btRWThread == null) {
+ synchronized (BTRWThread.class) {
+ if (btRWThread == null) {
+ btRWThread = new BTRWThread();
+ }
+ }
+ }
+ return btRWThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ btrwHandler = new BTRWHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class BTRWHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BTRWHANDLER_READ: {
+ byte[] buffer = new byte[0x1000];
+ int rec = 0;
+ Log.i(TAG, "start read");
+
+ try {
+ while (true) {
+ if (bThreadWait) {
+ bReadPaused = true;
+ synchronized (oThreadControl) {
+ oThreadControl.wait();
+ }
+ }
+ bReadPaused = false;
+
+ rec = ReadIsAvaliable(buffer, buffer.length);
+ if (rec > 0) {
+ for (int i = 0; i < rec; i++)
+ BTRXBuffer.PutByte(buffer[i]);
+ OnRecv(buffer, 0, rec);
+ }
+
+ Thread.sleep(100);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ Close();
+ break;
+ }
+ }
+ }
+ }
+
+ public static void PauseRead() {
+ bThreadWait = true;
+ while (!bReadPaused)
+ ;
+ }
+
+ public static void ResumeRead() {
+ bThreadWait = false;
+ synchronized (oThreadControl) {
+ oThreadControl.notifyAll();
+ }
+ }
+
+ public static boolean Open(String BTAddress) {
+ boolean result = false;
+ /* synchronized (SLOCK) */{
+ result = _Open(BTAddress);
+ }
+ return result;
+ }
+
+ private static boolean _Open(String BTAddress) {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter
+ .getDefaultAdapter();
+ if (bluetoothAdapter == null)
+ return false;
+
+ boolean valid = false;
+
+ BluetoothDevice device = bluetoothAdapter.getRemoteDevice(BTAddress);
+ Method m;
+ try {
+ m = device.getClass().getMethod("createRfcommSocket",
+ new Class[] { int.class });
+ try {
+ s = (BluetoothSocket) m.invoke(device, 1);
+ bluetoothAdapter.cancelDiscovery();
+ try {
+ s.connect();
+ os = new DataOutputStream(s.getOutputStream());
+ is = new DataInputStream(s.getInputStream());
+ valid = true;
+ Log.v("BTRWThread Open", "Connected to " + BTAddress);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ } catch (SecurityException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ // 如果成功了,则发起读命令
+ if (valid) {
+ isOpened = true;
+ Message msg = btrwHandler.obtainMessage(BTRWHANDLER_READ);
+ btrwHandler.sendMessage(msg);
+ } else {
+ _Close();
+ }
+
+ return valid;
+ }
+
+ public static boolean OpenOfficial(String BTAddress) {
+ boolean result = false;
+ /* synchronized (SLOCK) */{
+ result = _OpenOfficial(BTAddress);
+ }
+ return result;
+ }
+
+ private static boolean _OpenOfficial(String BTAddress) {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter
+ .getDefaultAdapter();
+ if (bluetoothAdapter == null)
+ return false;
+
+ boolean valid = false;
+
+ BluetoothDevice device = bluetoothAdapter.getRemoteDevice(BTAddress);
+ // Get a BluetoothSocket to connect with the given BluetoothDevice
+ try {
+ // MY_UUID is the app's UUID string, also used by the server code
+ s = device.createRfcommSocketToServiceRecord(uuid);
+ } catch (IOException e) {
+ }
+
+ bluetoothAdapter.cancelDiscovery();
+
+ try {
+ // Connect the device through the socket. This will block
+ // until it succeeds or throws an exception
+ s.connect();
+ os = new DataOutputStream(s.getOutputStream());
+ is = new DataInputStream(s.getInputStream());
+ valid = true;
+ Log.v("BTRWThread OpenOfficial", "Connected to " + BTAddress);
+ } catch (IOException connectException) {
+ // Unable to connect; close the socket and get out
+ try {
+ s.close();
+ } catch (IOException closeException) {
+ }
+ }
+
+ // 如果成功了,则发起读命令
+ if (valid) {
+ isOpened = true;
+ Message msg = btrwHandler.obtainMessage(BTRWHANDLER_READ);
+ btrwHandler.sendMessage(msg);
+ } else {
+ isOpened = false;
+ s = null;
+ }
+
+ return valid;
+ }
+
+ public static void Close() {
+ /* synchronized (SLOCK) */{
+ _Close();
+ }
+ }
+
+ private static void _Close() {
+ try {
+ if (is != null) {
+ is.close();
+ is = null;
+ }
+ if (os != null) {
+ os.close();
+ os = null;
+ }
+ if (null != s) {
+ s.close();
+ s = null;
+ }
+ Log.v("BTRWThread Close", "Close BluetoothSocket");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ isOpened = false;
+ }
+
+ public static boolean IsOpened() {
+ boolean ret = false;
+ /* synchronized (SLOCK) */{
+ ret = _IsOpened();
+ }
+ return ret;
+ }
+
+ private static boolean _IsOpened() {
+ return isOpened;
+ }
+
+ public static int Write(byte[] buffer, int offset, int count) {
+ int ret = 0;
+ /* synchronized (SLOCK) */{
+ ret = _Write(buffer, offset, count);
+ }
+ return ret;
+ }
+
+ private static int _Write(byte[] buffer, int offset, int count) {
+ int cnt = 0;
+ if (null != os) {
+ try {
+ os.write(buffer, offset, count);
+ os.flush();
+ cnt = count;
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ _Close();
+ }
+ }
+
+ return cnt;
+ }
+
+ /**
+ *
+ * @param buffer
+ * @param byteOffset
+ * @param byteCount
+ * @param timeout
+ * @return 返回实际读取的字节数
+ */
+ public static synchronized int Read(byte[] buffer, int byteOffset,
+ int byteCount, int timeout) {
+ int index = 0;
+ long time = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - time) < timeout) {
+ if (!IsEmpty()) {
+ buffer[index++] = GetByte();
+ }
+
+ if (index == byteCount)
+ break;
+ }
+
+ return index;
+ }
+
+ private static int ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int ret = 0;
+
+ ret = _ReadIsAvaliable(buffer, maxCount);
+
+ return ret;
+ }
+
+ private static int _ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int available = 0;
+ int rec = -1;
+
+ if (null != is) {
+ available = is.available();
+ if (available > 0) {
+ rec = is.read(buffer, 0, available > maxCount ? maxCount
+ : available);
+ }
+ }
+ return rec;
+ }
+
+ private static void OnRecv(byte[] buffer, int byteOffset, int byteCount) {
+ synchronized (NULLLOCK) {
+ if (null != callBack)
+ callBack.onRecv(buffer, byteOffset, byteCount);
+ }
+ }
+
+ public static void SetOnRecvCallBack(RecvCallBack callback) {
+ synchronized (NULLLOCK) {
+ callBack = callback;
+ }
+ }
+
+ public static boolean Request(byte sendbuf[], int sendlen, int requestlen,
+ byte recbuf[], Integer reclen, int timeout) {
+ int Retry = 3;
+
+ while ((Retry--) > 0) {
+ ClrRec();
+ Write(sendbuf, 0, sendlen);
+ reclen = Read(recbuf, 0, requestlen, timeout);
+ if (requestlen == reclen)
+ return true;
+ }
+ return false;
+ }
+
+ public static void ClrRec() {
+ BTRXBuffer.ClrRec();
+ }
+
+ public static boolean IsEmpty() {
+ return BTRXBuffer.IsEmpty();
+ }
+
+ public static byte GetByte() {
+ return BTRXBuffer.GetByte();
+ }
+
+ public static synchronized void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ btRWThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static DataInputStream GetInputStream() {
+ return is;
+ }
+
+ public static DataOutputStream GetOutputStream(){
+ return os;
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwbuf/ProtocolHandler.java b/app/src/main/java/com/lvrenyang/rwbuf/ProtocolHandler.java
new file mode 100644
index 0000000..302fd1f
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwbuf/ProtocolHandler.java
@@ -0,0 +1,61 @@
+package com.lvrenyang.rwbuf;
+
+public class ProtocolHandler {
+
+ public int Count;
+ public byte Buffer[];
+ int MaxSize;
+
+ public int ProtoHeaderOut = 0x03FF; //
+ public int ProtoHeaderIn = 0x03FE; //
+ public int KcCmd,KcPara;
+
+ public ProtocolHandler(int MAX_SIZE)
+ {
+ Count = KcCmd = KcPara = 0;
+ MaxSize = MAX_SIZE;
+ Buffer = new byte[MaxSize];
+ }
+
+ /* 数据完全无误的时候,才会设置KcCmd和KcPara,返回true表示成功解析一个命令,否则返回false */
+ public void HandleKcUartChar(byte ch)
+ {
+ if (Count == 0)
+ {
+ // Check is the start byte OK
+ if (ch == (byte)(ProtoHeaderIn >> 8))
+ {
+ Buffer[0] = (byte)(ProtoHeaderIn >> 8);
+ Count = 1;
+ }
+ }
+ else
+ { // Start to receive
+ if (Count >= MaxSize)
+ { // Package is too large, which is invalid
+ Count = 0;
+ }
+ else
+ {
+ Buffer[Count++] = ch;
+ }
+ if (Buffer[1] != (byte)(ProtoHeaderIn))
+ Count = 0;
+ if (Count >= 12)
+ { // package received OK?
+ int len;
+ len = (Buffer[8]&0xFF)+(Buffer[9]&0xFF)*0x100+12;
+
+ if (Count >= len)
+ { // package is ready?
+ // package is valid
+ KcCmd = (Buffer[2]&0xFF) | ((Buffer[3]&0xFF) << 8);
+ KcPara = (Buffer[4]&0xFF) | ((Buffer[5]&0xFF) << 8)
+ | ((Buffer[6]&0xFF) << 16) | ((Buffer[7]&0xFF) << 24);
+ Count = 0;
+ }
+ }
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwbuf/RxBuffer.java b/app/src/main/java/com/lvrenyang/rwbuf/RxBuffer.java
new file mode 100644
index 0000000..0650c8e
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwbuf/RxBuffer.java
@@ -0,0 +1,74 @@
+package com.lvrenyang.rwbuf;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 为了防止在读取或写入的时候,调用了清除,所以需要锁
+ *
+ * @author Administrator
+ *
+ */
+public class RxBuffer {
+
+ private final Lock BUFLOCK = new ReentrantLock();
+ int RxSize;
+ int Read, Write;
+ byte Buffer[];
+
+ public RxBuffer(int RX_SIZE) {
+ Read = Write = 0;
+ RxSize = RX_SIZE;
+ Buffer = new byte[RxSize];
+ }
+
+ public byte GetByte() {
+ byte ch;
+ BUFLOCK.lock();
+ ch = _GetByte();
+ BUFLOCK.unlock();
+ return ch;
+ }
+
+ public byte _GetByte() {
+ byte ch;
+ if (Read > (RxSize - 1))
+ Read = 0;
+ ch = Buffer[Read++];
+ return (ch);
+ }
+
+ public void PutByte(byte ch) {
+ BUFLOCK.lock();
+ _PutByte(ch);
+ BUFLOCK.unlock();
+ }
+
+ public void _PutByte(byte ch) {
+ if (Write > RxSize - 1)
+ Write = 0;
+ Buffer[Write++] = ch;
+ }
+
+ public void ClrRec() {
+ BUFLOCK.lock();
+ _ClrRec();
+ BUFLOCK.unlock();
+ }
+
+ public void _ClrRec() {
+ Write = Read = 0;
+ }
+
+ public boolean IsEmpty() {
+ boolean result;
+ BUFLOCK.lock();
+ result = _IsEmpty();
+ BUFLOCK.unlock();
+ return result;
+ }
+
+ public boolean _IsEmpty() {
+ return (Read == Write);
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwusb/PL2303Driver.java b/app/src/main/java/com/lvrenyang/rwusb/PL2303Driver.java
new file mode 100644
index 0000000..fd8a64a
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwusb/PL2303Driver.java
@@ -0,0 +1,384 @@
+package com.lvrenyang.rwusb;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.lvrenyang.rwusb.PL2303Driver.TTYTermios.FlowControl;
+import com.lvrenyang.rwusb.USBDriver;
+import com.lvrenyang.utils.FileUtils;
+
+public class PL2303Driver extends USBDriver {
+
+ String description = "Vitural PL2303 Device.";
+
+ public static USBDeviceId id[] = { new USBDeviceId(0x067b, 0x2303) };
+
+ private static final int SET_LINE_REQUEST_TYPE = 0x21;
+ private static final int SET_LINE_REQUEST = 0x20;
+
+ private static final int SET_CONTROL_REQUEST_TYPE = 0x21;
+ private static final int SET_CONTROL_REQUEST = 0x22;
+ private static final int CONTROL_DTR = 0x01;
+ private static final int CONTROL_RTS = 0x02;
+
+ private static final int GET_LINE_REQUEST_TYPE = 0xa1;
+ private static final int GET_LINE_REQUEST = 0x21;
+
+ private static final int VENDOR_WRITE_REQUEST_TYPE = 0x40;
+ private static final int VENDOR_WRITE_REQUEST = 0x01;
+
+ private static final int VENDOR_READ_REQUEST_TYPE = 0xc0;
+ private static final int VENDOR_READ_REQUEST = 0x01;
+
+ private enum pl2303_type {
+ type_0, /* don't know the difference between type 0 and */
+ type_1, /* type 1, until someone from prolific tells us... */
+ HX, /* HX version of the pl2303 chip */
+ };
+
+ private pl2303_type type = pl2303_type.HX;
+
+ private int pl2303_vendor_read(USBPort port, int value, int index,
+ byte[] buffer) {
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+ return ctl(port, VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value,
+ index, buffer, 1, 100);
+ }
+
+ private int pl2303_vendor_write(USBPort port, int value, int index) {
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+ return ctl(port, VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST,
+ value, index, null, 0, 100);
+ }
+
+ private int set_control_lines(USBPort port, int value) {
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+ return ctl(port, SET_CONTROL_REQUEST_TYPE, SET_CONTROL_REQUEST, value,
+ 0, null, 0, 100);
+ }
+
+ /**
+ * attach 和 release配套使用
+ *
+ * @param port
+ * @return
+ */
+ int attach(USBPort port) {
+ // TODO Auto-generated method stub
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+
+ type = pl2303_type.HX;
+ byte[] buf = new byte[256];
+ int ret = 0;
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8484, 0, buf);
+
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 0x0404, 0);
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8484, 0, buf);
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8383, 0, buf);
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8484, 0, buf);
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 0x0404, 1);
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8484, 0, buf);
+ if (ret >= 0)
+ ret = pl2303_vendor_read(port, 0x8383, 0, buf);
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 0, 1);
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 1, 0);
+ if (type == pl2303_type.HX) {
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 2, 0x44);
+ } else {
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 2, 0x24);
+ }
+
+ FileUtils.DebugAddToFile("usb attach "
+ + (ret >= 0 ? "success" : "failed") + " \r\n",
+ FileUtils.sdcard_dump_txt);
+
+ return ret >= 0 ? RTNCode.OK : RTNCode.ERROR;
+ }
+
+ /**
+ * release和attach配套使用
+ *
+ * @param port
+ * @return
+ */
+ int release(USBPort port) {
+ // TODO Auto-generated method stub
+ return RTNCode.OK;
+ }
+
+ /**
+ * open和close配套使用
+ *
+ * @param port
+ * @param serial
+ * @return
+ */
+ int open(USBPort port, TTYTermios serial) {
+ // TODO Auto-generated method stub
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+ if (null == serial)
+ return RTNCode.NULLPOINTER;
+
+ int ret = 0;
+ if (pl2303_type.HX == type) {
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 8, 0);
+ if (ret >= 0)
+ ret = pl2303_vendor_write(port, 9, 0);
+ }
+ if (ret >= 0) {
+ ret = set_termios(port, serial);
+ } else {
+ ret = RTNCode.ERROR;
+ }
+ FileUtils.DebugAddToFile("usb open "
+ + (ret == RTNCode.OK ? "success" : "failed") + " \r\n",
+ FileUtils.sdcard_dump_txt);
+ return ret;
+ }
+
+ /**
+ * close和open配套使用
+ *
+ * @param port
+ * @param serial
+ * @return
+ */
+ int close(USBPort port, TTYTermios serial) {
+ // TODO Auto-generated method stub
+
+ return 0;
+ }
+
+ /**
+ * 如果termiosnew不为空,那么会用termiosnew中的值设置2303 并且将serial中的termios改为termiosnew
+ */
+ private int set_termios(USBPort port, TTYTermios termiosnew) {
+ int i;
+ int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800,
+ 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400,
+ 460800, 614400, 921600, 1228800, 2457600, 3000000, 6000000 };
+
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+
+ if (null == termiosnew)
+ return RTNCode.NULLPOINTER;
+
+ byte[] buf = new byte[7];
+
+ ctl(port, GET_LINE_REQUEST_TYPE, GET_LINE_REQUEST, 0, 0, buf, 7, 100);
+
+ // 驱动里面会根据得到的数据和本身的选项来填充字段进行修改,这里
+ // 我直接根据termios里面的数据进行修改
+ switch (termiosnew.dataBits) {
+ case 5:
+ buf[6] = 5;
+ break;
+ case 6:
+ buf[6] = 6;
+ break;
+ case 7:
+ buf[6] = 7;
+ break;
+ default:
+ buf[6] = 8;
+ break;
+ }
+
+ for (i = 0; i < baud_sup.length; i++) {
+ if (baud_sup[i] == termiosnew.baudrate)
+ break;
+ }
+ if (i == baud_sup.length)
+ termiosnew.baudrate = 9600;
+ if (termiosnew.baudrate > 1228800) {
+ if (type != pl2303_type.HX)
+ termiosnew.baudrate = 1228800;
+ else if (termiosnew.baudrate > 6000000)
+ termiosnew.baudrate = termiosnew.baudrate;
+ }
+ if (termiosnew.baudrate <= 115200) {
+ buf[0] = (byte) (termiosnew.baudrate & 0xff);
+ buf[1] = (byte) ((termiosnew.baudrate >> 8) & 0xff);
+ buf[2] = (byte) ((termiosnew.baudrate >> 16) & 0xff);
+ buf[3] = (byte) ((termiosnew.baudrate >> 24) & 0xff);
+ } else {
+ long tmp = 12 * 1000 * 1000 * 32 / termiosnew.baudrate;
+ buf[3] = (byte) 0x80;
+ buf[2] = 0;
+ buf[1] = (byte) (tmp >= 256 ? 1 : 0);
+ while (tmp >= 256) {
+ tmp >>= 2;
+ buf[1] = (byte) ((buf[1] & 0xff) << 1);
+ }
+ if (tmp > 256) {
+ tmp %= 256;
+ }
+ buf[0] = (byte) tmp;
+ }
+ switch (termiosnew.stopBits) {
+ case ONE:
+ buf[4] = 0;
+ break;
+ case ONEPFIVE:
+ buf[4] = 1;
+ break;
+ case TWO:
+ buf[4] = 2;
+ break;
+ }
+
+ switch (termiosnew.parity) {
+ case NONE:
+ buf[5] = 0;
+ break;
+ case ODD:
+ buf[5] = 1;
+ break;
+ case EVEN:
+ buf[5] = 2;
+ break;
+ case MARK:
+ buf[5] = 3;
+ break;
+ case SPACE:
+ buf[5] = 4;
+ break;
+ }
+
+ ctl(port, SET_LINE_REQUEST_TYPE, SET_LINE_REQUEST, 0, 0, buf, 7, 100);
+
+ switch (termiosnew.flowControl) {
+ case NONE:
+ set_control_lines(port, 0);
+ break;
+ case DTR_RTS:
+ set_control_lines(port, CONTROL_DTR | CONTROL_RTS);
+ break;
+ }
+
+ buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
+
+ ctl(port, GET_LINE_REQUEST_TYPE, GET_LINE_REQUEST, 0, 0, buf, 7, 100);
+
+ if (termiosnew.flowControl == FlowControl.DTR_RTS) {
+ if (type == pl2303_type.HX)
+ pl2303_vendor_write(port, 0x0, 0x61);
+ else
+ pl2303_vendor_write(port, 0x0, 0x41);
+ } else {
+ pl2303_vendor_write(port, 0x0, 0x0);
+ }
+
+ return RTNCode.OK;
+ }
+
+ /**
+ * TTY终端参数,包括波特率,流控制,校验位,停止位,数据位等。
+ *
+ * @author Administrator
+ *
+ */
+ public static class TTYTermios implements Parcelable {
+ /**
+ * 波特率,只支持9600,19200,38400,57600,115200 但是,SDK里面并没有做检查,需要客户端程序自行检查
+ */
+ public int baudrate = 9600;
+
+ /**
+ * 流控制,NONE或者DTR_RTS
+ */
+ public FlowControl flowControl = FlowControl.NONE;
+
+ /**
+ * 校验位,支持无校验,奇校验,偶校验,表奇校验,空白校验
+ */
+ public Parity parity = Parity.NONE;
+
+ /**
+ * 停止位,1,1.5,2
+ */
+ public StopBits stopBits = StopBits.ONE;
+ /**
+ * 数据位,支持5,6,7,8,但是SDK里面并没有做检查,需要客户端程序自行检查
+ */
+ public int dataBits = 8;
+
+ public TTYTermios(int baudrate, FlowControl flowControl, Parity parity,
+ StopBits stopBits, int dataBits) {
+ this.baudrate = baudrate;
+ this.flowControl = flowControl;
+ this.parity = parity;
+ this.stopBits = stopBits;
+ this.dataBits = dataBits;
+ }
+
+ public enum FlowControl {
+ NONE, DTR_RTS
+ }
+
+ public enum Parity {
+ NONE, ODD, EVEN, SPACE, MARK
+ }
+
+ public enum StopBits {
+ ONE, ONEPFIVE, TWO
+ }
+
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flag) {
+ // TODO Auto-generated method stub
+ out.writeInt(baudrate);
+ out.writeValue(flowControl);
+ out.writeValue(parity);
+ out.writeValue(stopBits);
+ out.writeInt(dataBits);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Creator() {
+
+ @Override
+ public TTYTermios createFromParcel(Parcel in) {
+ return new TTYTermios(in);
+ }
+
+ @Override
+ public TTYTermios[] newArray(int size) {
+ // TODO Auto-generated method stub
+ return new TTYTermios[size];
+ }
+ };
+
+ public TTYTermios(Parcel in) {
+ baudrate = in.readInt();
+ flowControl = (FlowControl) in.readValue(FlowControl.class
+ .getClassLoader());
+ parity = (Parity) in.readValue(Parity.class.getClassLoader());
+ stopBits = (StopBits) in.readValue(StopBits.class.getClassLoader());
+ dataBits = in.readInt();
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwusb/USBDriver.java b/app/src/main/java/com/lvrenyang/rwusb/USBDriver.java
new file mode 100644
index 0000000..05c69b3
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwusb/USBDriver.java
@@ -0,0 +1,279 @@
+package com.lvrenyang.rwusb;
+
+import android.annotation.TargetApi;
+//import android.app.PendingIntent;
+//import android.content.Context;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+//import android.hardware.usb.UsbRequest;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.lvrenyang.utils.DataUtils;
+import com.lvrenyang.utils.FileUtils;
+
+/**
+ * 第一层,USB驱动 围绕着USBPort来进行
+ *
+ * @author Administrator
+ *
+ */
+@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
+public class USBDriver {
+
+ /**
+ * probe和disconnect配套使用
+ *
+ * @param port
+ * @param id
+ * @return
+ */
+ int probe(USBPort port, USBDeviceId id[]) {
+ if (null == port || null == id)
+ return RTNCode.NULLPOINTER;
+ if ((null == port.mUsbManager) || (null == port.mUsbDevice))
+ // || (null == port.mPermissionIntent))
+ return RTNCode.NULLPOINTER;
+
+ FileUtils.DebugAddToFile("usb probe start. \r\n",
+ FileUtils.sdcard_dump_txt);
+
+ for (int i = 0; i < id.length; i++)
+ if (id[i].idVendor == port.mUsbDevice.getVendorId()
+ && id[i].idProduct == port.mUsbDevice.getProductId()) {
+
+ if (!port.mUsbManager.hasPermission(port.mUsbDevice))
+ return RTNCode.NOPERMISSION;
+
+ // 枚举,把读写控制端口什么的给弄过来。然后set
+ FileUtils.DebugAddToFile(
+ "InterfaceCount:" + port.mUsbDevice.getInterfaceCount()
+ + " \r\n", FileUtils.sdcard_dump_txt);
+ outer: for (int k = 0; k < port.mUsbDevice.getInterfaceCount(); k++) {
+ port.mUsbInterface = port.mUsbDevice.getInterface(k);
+ port.mUsbEndpointOut = null;
+ port.mUsbEndpointIn = null;
+ FileUtils.DebugAddToFile("EndpointCount:"
+ + port.mUsbInterface.getEndpointCount() + " \r\n",
+ FileUtils.sdcard_dump_txt);
+ for (int j = 0; j < port.mUsbInterface.getEndpointCount(); j++) {
+ UsbEndpoint endpoint = port.mUsbInterface
+ .getEndpoint(j);
+ if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT
+ && endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
+ port.mUsbEndpointOut = endpoint;
+ FileUtils.DebugAddToFile("EndpointOut:" + "(" + j
+ + "," + k + ")" + "MaxPacketSize:"
+ + endpoint.getMaxPacketSize() + "\r\n",
+ FileUtils.sdcard_dump_txt);
+ } else if (endpoint.getDirection() == UsbConstants.USB_DIR_IN
+ && endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
+ port.mUsbEndpointIn = endpoint;
+ FileUtils.DebugAddToFile("EndpointIn:" + "(" + j
+ + "," + k + ") " + "MaxPacketSize:"
+ + endpoint.getMaxPacketSize() + "\r\n",
+ FileUtils.sdcard_dump_txt);
+ }
+
+ // 如果在第一个接口就找到了符合要求的端点,那么break;
+ if ((null != port.mUsbEndpointOut)
+ && (null != port.mUsbEndpointIn))
+ break outer;
+ }
+ }
+ if (null == port.mUsbInterface)
+ return RTNCode.NULLPOINTER;
+ if ((null == port.mUsbEndpointOut)
+ || (null == port.mUsbEndpointIn))
+ return RTNCode.NULLPOINTER;
+ port.mUsbDeviceConnection = port.mUsbManager
+ .openDevice(port.mUsbDevice);
+ if (null == port.mUsbDeviceConnection)
+ return RTNCode.NULLPOINTER;
+ port.mUsbDeviceConnection.claimInterface(port.mUsbInterface,
+ true);
+ FileUtils.DebugAddToFile("usb probe success. \r\n",
+ FileUtils.sdcard_dump_txt);
+ return RTNCode.OK;
+ }
+
+ return RTNCode.ERROR;
+ }
+
+ /**
+ * disconnect和probe配套使用
+ *
+ * @param port
+ */
+ void disconnect(USBPort port) {
+ if (null == port)
+ return;
+ if ((null != port.mUsbInterface) && (null != port.mUsbDeviceConnection)) {
+ port.mUsbDeviceConnection.releaseInterface(port.mUsbInterface);
+ port.mUsbDeviceConnection.close();
+ }
+ }
+
+ int write(USBPort port, byte[] buffer, int offset, int count, int timeout) {
+ if (null == port || null == buffer)
+ return RTNCode.NULLPOINTER;
+ if (null == port.mUsbEndpointOut)
+ return RTNCode.NULLPOINTER;
+ if (null == port.mUsbDeviceConnection)
+ return RTNCode.NULLPOINTER;
+ if (count < 0 || offset < 0 || timeout <= 0)
+ return RTNCode.INVALPARAM;
+ byte[] data = new byte[count];
+ DataUtils.copyBytes(buffer, offset, data, 0, count);
+ return port.mUsbDeviceConnection.bulkTransfer(port.mUsbEndpointOut,
+ data, data.length, timeout);
+ }
+
+ int read(USBPort port, byte[] buffer, int offset, int count, int timeout) {
+ if (null == port || null == buffer)
+ return RTNCode.NULLPOINTER;
+ if (null == port.mUsbEndpointIn)
+ return RTNCode.NULLPOINTER;
+ if (null == port.mUsbDeviceConnection)
+ return RTNCode.NULLPOINTER;
+ if (count < 0 || offset < 0 || timeout <= 0)
+ return RTNCode.INVALPARAM;
+
+ byte[] data = new byte[count];
+ int recnt = port.mUsbDeviceConnection.bulkTransfer(port.mUsbEndpointIn,
+ data, data.length, timeout);
+ DataUtils.copyBytes(data, 0, buffer, offset, recnt);
+ return recnt; // 返回读取的字节数
+ }
+
+ int ctl(USBPort port, int requestType, int request, int value, int index,
+ byte[] buffer, int length, int timeout) {
+ if (null == port)
+ return RTNCode.NULLPOINTER;
+ if (null == port.mUsbDeviceConnection)
+ return RTNCode.NULLPOINTER;
+
+ return port.mUsbDeviceConnection.controlTransfer(requestType, request,
+ value, index, buffer, length, timeout);
+ }
+
+ public static class RTNCode {
+
+ public static final int OK = 0;
+ public static final int ERROR = -1000;
+ /**
+ * 空指针错误
+ */
+ public static final int NULLPOINTER = -1001;
+ public static final int NOPERMISSION = -1002;
+
+ /**
+ * 参数不符合要求,如n需要大于等于0但给出的是小于0
+ */
+ public static final int INVALPARAM = -1003;
+
+ public static final int EXCEPTION = -1004;
+
+ public static final int NOTCONNECTED = -1005;
+
+ public static final int NOTOPENED = -1006;
+
+ public static final int NOTIMPLEMENTED = -1007;
+ }
+
+ public static class USBDeviceId {
+ int idVendor;
+ int idProduct;
+
+ public USBDeviceId(int vid, int pid) {
+ idVendor = vid;
+ idProduct = pid;
+ }
+ }
+
+ /**
+ * 该类只有一个构造函数和一些变量
+ *
+ * @author Administrator
+ *
+ */
+ public static class USBPort implements Parcelable {
+
+ UsbManager mUsbManager;
+ UsbDevice mUsbDevice;
+ // PendingIntent mPermissionIntent;
+
+ UsbInterface mUsbInterface;
+ UsbEndpoint mUsbEndpointOut, mUsbEndpointIn;
+ UsbDeviceConnection mUsbDeviceConnection;
+
+ // UsbRequest mUsbRequestIn;
+
+ public USBPort(UsbManager usbManager, UsbDevice usbDevice/*
+ * ,
+ * PendingIntent
+ * permissionIntent
+ */) {
+ this.mUsbManager = usbManager;
+ this.mUsbDevice = usbDevice;
+ // this.mPermissionIntent = permissionIntent;
+ }
+
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flag) {
+ // TODO Auto-generated method stub
+ out.writeValue(mUsbManager);
+ out.writeValue(mUsbDevice);
+ // out.writeValue(mPermissionIntent);
+ out.writeValue(mUsbInterface);
+ out.writeValue(mUsbEndpointOut);
+ out.writeValue(mUsbEndpointIn);
+ out.writeValue(mUsbDeviceConnection);
+ // out.writeValue(mUsbRequestIn);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Creator() {
+
+ @Override
+ public USBPort createFromParcel(Parcel in) {
+ return new USBPort(in);
+ }
+
+ @Override
+ public USBPort[] newArray(int size) {
+ // TODO Auto-generated method stub
+ return new USBPort[size];
+ }
+ };
+
+ public USBPort(Parcel in) {
+ mUsbManager = (UsbManager) in.readValue(UsbManager.class
+ .getClassLoader());
+ mUsbDevice = (UsbDevice) in.readValue(UsbDevice.class
+ .getClassLoader());
+ // mPermissionIntent = (PendingIntent) in
+ // .readValue(PendingIntent.class.getClassLoader());
+ mUsbInterface = (UsbInterface) in.readValue(UsbInterface.class
+ .getClassLoader());
+ mUsbEndpointOut = (UsbEndpoint) in.readValue(UsbEndpoint.class
+ .getClassLoader());
+ mUsbEndpointIn = (UsbEndpoint) in.readValue(UsbEndpoint.class
+ .getClassLoader());
+ mUsbDeviceConnection = (UsbDeviceConnection) in
+ .readValue(UsbDeviceConnection.class.getClassLoader());
+ // mUsbRequestIn = (UsbRequest) in.readValue(UsbRequest.class
+ // .getClassLoader());
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwusb/USBHeartBeatThread.java b/app/src/main/java/com/lvrenyang/rwusb/USBHeartBeatThread.java
new file mode 100644
index 0000000..6dab07c
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwusb/USBHeartBeatThread.java
@@ -0,0 +1,175 @@
+package com.lvrenyang.rwusb;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.lvrenyang.utils.FileUtils;
+import com.lvrenyang.utils.TimeUtils;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+public class USBHeartBeatThread extends Thread {
+
+ public static final int MSG_USBHEARTBEATTHREAD_UPDATESTATUS = 200300;
+ private static volatile USBHeartBeatThread heartBeatThread = null;
+
+ private static final int HEARTBEATHANDLER_STARTUP = 1000;
+
+ private static Handler targetHandler = null;
+ private static Handler heartBeatHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ private static boolean pause = false;
+ // private static boolean iofinished = false;
+ private static final Lock iofinished = new ReentrantLock();
+ // private static final Object heart = new Object();
+
+ private static int StatusOK = 0;
+ private static int Status = 0;
+
+ public USBHeartBeatThread(Handler mHandler) {
+ targetHandler = mHandler;
+ }
+
+ public static USBHeartBeatThread InitInstant(Handler mHandler) {
+ if (heartBeatThread == null) {
+ synchronized (USBHeartBeatThread.class) {
+ if (heartBeatThread == null) {
+ heartBeatThread = new USBHeartBeatThread(mHandler);
+ }
+ }
+ }
+ return heartBeatThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ heartBeatHandler = new USBHeartBeatHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class USBHeartBeatHandler extends Handler {
+
+ private void SendOutStatus() {
+ Message smsg = targetHandler
+ .obtainMessage(MSG_USBHEARTBEATTHREAD_UPDATESTATUS);
+ smsg.arg1 = StatusOK;
+ smsg.arg2 = Status;
+ targetHandler.sendMessage(smsg);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ /**
+ * BT 做心跳数据包用10 04 01命令
+ */
+ case HEARTBEATHANDLER_STARTUP: {
+ byte[] buffer = { 0x10, 0x04, 0x01 };
+ int buffersize = 3;
+ int sendlen = 0;
+
+ byte[] rec = { 0x00 };
+ int reclen = 0;
+ int timeout = 2000;
+
+ int intertimeout = 2000;
+ final int threshold = 3;
+ int curUnrespond = 0;
+
+ FileUtils.DebugAddToFile("usb heartbeat start\r\n",
+ FileUtils.sdcard_dump_txt);
+ while (true) {
+
+ TimeUtils.WaitMs(intertimeout);
+ if (pause) {
+ FileUtils.DebugAddToFile("paused\r\n",
+ FileUtils.sdcard_dump_txt);
+ continue;
+ }
+ FileUtils.DebugAddToFile("heart beating\r\n",
+ FileUtils.sdcard_dump_txt);
+
+ iofinished.lock();
+ USBRWThread.ClrRec();// 只调用clearrec也需要这个锁,调用read也需要这个锁
+ sendlen = USBRWThread.Write(buffer, 0, buffersize);
+ reclen = USBRWThread.Read(rec, 0, 1, timeout);
+ iofinished.unlock();
+
+ if (sendlen != buffersize) // 写出错,流的问题。直接break
+ {
+ StatusOK = 0;
+ Status = 0;
+ SendOutStatus();
+ break;
+ }
+
+ if (reclen == 1) {
+ curUnrespond = 0;
+ StatusOK = 1;
+ Status = rec[0];
+ } else {
+ curUnrespond++;
+ StatusOK = 0;
+ Status = 0;
+ }
+
+ SendOutStatus();
+
+ if (curUnrespond >= threshold)
+ break;
+ }
+
+ FileUtils.DebugAddToFile("usb heartbeat end\r\n",
+ FileUtils.sdcard_dump_txt);
+ break;
+ }
+ }
+ }
+ }
+
+ public static void BeginHeartBeat() {
+ Message msg = heartBeatHandler.obtainMessage(HEARTBEATHANDLER_STARTUP);
+ heartBeatHandler.sendMessage(msg);
+ }
+
+ public static void PauseHeartBeat() {
+ FileUtils
+ .DebugAddToFile("iofinished.lock()", FileUtils.sdcard_dump_txt);
+ pause = true;
+ iofinished.lock();
+ iofinished.unlock();
+ FileUtils.DebugAddToFile("iofinished.unlock()",
+ FileUtils.sdcard_dump_txt);
+
+ }
+
+ public static void ResumeHeartBeat() {
+ pause = false;
+ }
+
+ public static void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ heartBeatThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwusb/USBRWThread.java b/app/src/main/java/com/lvrenyang/rwusb/USBRWThread.java
new file mode 100644
index 0000000..f8bd338
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwusb/USBRWThread.java
@@ -0,0 +1,327 @@
+package com.lvrenyang.rwusb;
+
+import java.io.IOException;
+
+import com.lvrenyang.callback.RecvCallBack;
+import com.lvrenyang.rwbuf.RxBuffer;
+import com.lvrenyang.rwusb.PL2303Driver.TTYTermios;
+import com.lvrenyang.rwusb.USBDriver.RTNCode;
+import com.lvrenyang.rwusb.USBDriver.USBPort;
+import com.lvrenyang.utils.FileUtils;
+
+//import android.hardware.usb.UsbRequest;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * 这只是单纯处理读数据的线程,如果需要执行工作,还需要另外的线程
+ * 这里面启动心跳线程,构造函数的时候new,start的时候也start子线程,quit的时候也
+ *
+ * @author Administrator
+ *
+ */
+public class USBRWThread extends Thread {
+ private static final String TAG = "USBRWThread";
+ // private static final Lock SLOCK = new ReentrantLock(); // 读写互斥锁,内部使用。
+ private static volatile USBRWThread usbrwThread = null;
+ // private static boolean bThreadWait = false;
+ // private static boolean bReadPaused = false;
+ // private static final Object oThreadControl = new Object();
+
+ private static final int RWHANDLER_READ = 1000;
+
+ private static Handler usbrwHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ private static PL2303Driver pl2303 = new PL2303Driver();
+ private static USBPort port = null;
+ private static TTYTermios serial = null;
+ private static boolean isOpened = false;
+
+ private static RecvCallBack callBack = null;
+ private static final Object NULLLOCK = new Object();
+ public static RxBuffer USBRXBuffer = new RxBuffer(0x1000);
+
+ private USBRWThread() {
+ threadInitOK = false;
+ }
+
+ public static USBRWThread InitInstant() {
+ if (usbrwThread == null) {
+ synchronized (USBRWThread.class) {
+ if (usbrwThread == null) {
+ usbrwThread = new USBRWThread();
+ }
+ }
+ }
+ return usbrwThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ usbrwHandler = new RWHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class RWHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case RWHANDLER_READ: {
+ byte[] buffer = new byte[0x20];
+ int rec = 0;
+ Log.i(TAG, "start read");
+ FileUtils.DebugAddToFile("usb start read \r\n",
+ FileUtils.sdcard_dump_txt);
+ try {
+ while (true) {
+ /*
+ * if (bThreadWait) { bReadPaused = true; synchronized
+ * (oThreadControl) { oThreadControl.wait(); } }
+ * bReadPaused = false;
+ */
+ rec = ReadIsAvaliable(buffer, buffer.length);
+ if (rec > 0) {
+ for (int i = 0; i < rec; i++)
+ USBRXBuffer.PutByte(buffer[i]);
+ OnRecv(buffer, 0, rec);
+ } else if (rec < 0) {
+ FileUtils.DebugAddToFile(
+ "usb read error. ReadIsAvaliable return code:"
+ + rec + "\r\n",
+ FileUtils.sdcard_dump_txt);
+ break;
+ }
+
+ Thread.sleep(100);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ FileUtils.DebugAddToFile("usb stop read\r\n",
+ FileUtils.sdcard_dump_txt);
+ Close();
+ break;
+ }
+
+ }
+ }
+ }
+
+ /*
+ * public static void PauseRead() { bThreadWait = true; while (!bReadPaused)
+ * ; }
+ *
+ * public static void ResumeRead() { bThreadWait = false; synchronized
+ * (oThreadControl) { oThreadControl.notifyAll(); } }
+ */
+ public static boolean Open(USBPort port, TTYTermios serial) {
+ boolean result = false;
+ // SLOCK.lock();
+ result = _Open(port, serial);
+ // SLOCK.unlock();
+ return result;
+ }
+
+ private static boolean _Open(USBPort port, TTYTermios serial) {
+ boolean valid = false;
+ try {
+ if (pl2303.probe(port, PL2303Driver.id) == RTNCode.OK) {
+ if (pl2303.attach(port) == RTNCode.OK) {
+ if (pl2303.open(port, serial) == RTNCode.OK) {
+ USBRWThread.port = port;
+ USBRWThread.serial = serial;
+ valid = true;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ valid = false;
+ }
+
+ // 如果成功了,则发起读命令
+
+ if (valid) {
+ isOpened = true;
+ Message msg = usbrwHandler.obtainMessage(RWHANDLER_READ);
+ usbrwHandler.sendMessage(msg);
+ } else {
+ isOpened = false;
+ }
+
+ return valid;
+ }
+
+ public static void Close() {
+ // SLOCK.lock();
+ _Close();
+ // SLOCK.unlock();
+ }
+
+ private static void _Close() {
+ try {
+ pl2303.close(port, serial);
+ pl2303.release(port);
+ pl2303.disconnect(port);
+ port = null;
+ serial = null;
+ Log.v("USBRWThread Close", "Close Socket");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ isOpened = false;
+ }
+
+ public static boolean IsOpened() {
+ boolean ret = false;
+ // SLOCK.lock();
+ ret = _IsOpened();
+ // SLOCK.unlock();
+ return ret;
+ }
+
+ private static boolean _IsOpened() {
+ return isOpened;
+ }
+
+ public static int Write(byte[] buffer, int offset, int count) {
+ int ret = 0;
+ // SLOCK.lock();
+ ret = _Write(buffer, offset, count);
+ // SLOCK.unlock();
+ return ret;
+ }
+
+ private static int _Write(byte[] buffer, int offset, int count) {
+ int cnt = 0;
+ try {
+ cnt = pl2303.write(port, buffer, offset, count, 2000);
+ if (cnt < 0) {
+ cnt = 0;
+ throw new Exception("write error");
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ _Close();
+ }
+
+ return cnt;
+ }
+
+ /**
+ *
+ * @param buffer
+ * @param byteOffset
+ * @param byteCount
+ * @param timeout
+ * @return 返回实际读取的字节数
+ */
+ public static synchronized int Read(byte[] buffer, int byteOffset,
+ int byteCount, int timeout) {
+ int index = 0;
+ long time = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - time) < timeout) {
+ if (!IsEmpty()) {
+ buffer[index++] = GetByte();
+ }
+
+ if (index == byteCount)
+ break;
+ }
+
+ return index;
+ }
+
+ private static int ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int ret = 0;
+ // SLOCK.lock();
+ ret = _ReadIsAvaliable(buffer, maxCount);
+ // SLOCK.unlock();
+ return ret;
+ }
+
+ private static int _ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int rec;
+
+ rec = pl2303.read(port, buffer, 0, maxCount, 1);
+ if (-1 == rec)
+ rec = 0;
+
+ return rec;
+ }
+
+ private static void OnRecv(byte[] buffer, int byteOffset, int byteCount) {
+ synchronized (NULLLOCK) {
+ if (null != callBack)
+ callBack.onRecv(buffer, byteOffset, byteCount);
+ }
+ }
+
+ public static void SetOnRecvCallBack(RecvCallBack callback) {
+ synchronized (NULLLOCK) {
+ callBack = callback;
+ }
+ }
+
+ public static boolean Request(byte sendbuf[], int sendlen, int requestlen,
+ byte recbuf[], Integer reclen, int timeout) {
+ int Retry = 3;
+
+ while ((Retry--) > 0) {
+ ClrRec();
+ Write(sendbuf, 0, sendlen);
+ reclen = Read(recbuf, 0, requestlen, timeout);
+ if (requestlen == reclen)
+ return true;
+ }
+ return false;
+ }
+
+ public static void ClrRec() {
+ USBRXBuffer.ClrRec();
+ }
+
+ public static boolean IsEmpty() {
+ return USBRXBuffer.IsEmpty();
+ }
+
+ public static byte GetByte() {
+ return USBRXBuffer.GetByte();
+ }
+
+ public static synchronized void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ usbrwThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/rwwifi/NETHeartBeatThread.java b/app/src/main/java/com/lvrenyang/rwwifi/NETHeartBeatThread.java
new file mode 100644
index 0000000..1042d2d
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwwifi/NETHeartBeatThread.java
@@ -0,0 +1,175 @@
+package com.lvrenyang.rwwifi;
+
+import java.io.File;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * 网络心跳数据包线程 不断发送10 04 01 读取状态
+ *
+ * @author Administrator
+ *
+ */
+public class NETHeartBeatThread extends Thread {
+
+ public static final int MSG_NETHEARTBEATTHREAD_UPDATESTATUS = 200100;
+
+ public static final String dumpfile = Environment
+ .getExternalStorageDirectory().getAbsolutePath()
+ + File.separator
+ + "dump.txt";
+ private static volatile NETHeartBeatThread heartBeatThread = null;
+
+ private static final int HEARTBEATHANDLER_STARTUP = 1000;
+
+ private static Handler targetHandler = null;
+ private static Handler heartBeatHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ // private static final Object RWLOCK = new Object();
+ private static boolean pause = false;
+
+ private static final Lock iofinished = new ReentrantLock();
+
+ private static int StatusOK = 0;
+ private static int Status = 0;
+
+ private NETHeartBeatThread(Handler mHandler) {
+ targetHandler = mHandler;
+ }
+
+ public static NETHeartBeatThread InitInstant(Handler mHandler) {
+ if (heartBeatThread == null) {
+ synchronized (NETHeartBeatThread.class) {
+ if (heartBeatThread == null) {
+ heartBeatThread = new NETHeartBeatThread(mHandler);
+ }
+ }
+ }
+ return heartBeatThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ heartBeatHandler = new NETHeartBeatHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class NETHeartBeatHandler extends Handler {
+
+ private void SendOutStatus() {
+ Message smsg = targetHandler
+ .obtainMessage(MSG_NETHEARTBEATTHREAD_UPDATESTATUS);
+ smsg.arg1 = StatusOK;
+ smsg.arg2 = Status;
+ targetHandler.sendMessage(smsg);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ /**
+ * TCP 做心跳数据包用10 04 01命令
+ */
+ case HEARTBEATHANDLER_STARTUP: {
+ byte[] buffer = { 0x10, 0x04, 0x01 };
+ int buffersize = 3;
+ int sendlen = 0;
+
+ byte[] rec = { 0x00 };
+ int reclen = 0;
+ int timeout = 2000;
+
+ int intertimeout = 2000;
+ final int threshold = 3;
+ int curUnrespond = 0;
+ while (true) {
+ try {
+ Thread.sleep(intertimeout);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ }
+ if (pause)
+ continue;
+
+ iofinished.lock();
+ NETRWThread.ClrRec();// 只调用clearrec也需要这个锁,调用read也需要这个锁
+ sendlen = NETRWThread.Write(buffer, 0, buffersize);
+ reclen = NETRWThread.Read(rec, 0, 1, timeout);
+ iofinished.unlock();
+
+ if (sendlen != buffersize) // 写出错,流的问题。直接break
+ {
+ StatusOK = 0;
+ Status = 0;
+ SendOutStatus();
+ break;
+ }
+
+ if (reclen == 1) {
+ curUnrespond = 0;
+ StatusOK = 1;
+ Status = rec[0];
+ } else {
+ curUnrespond++;
+ StatusOK = 0;
+ Status = 0;
+ }
+
+ SendOutStatus();
+
+ if (curUnrespond >= threshold)
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ public static void BeginHeartBeat() {
+ Message msg = heartBeatHandler.obtainMessage(HEARTBEATHANDLER_STARTUP);
+ heartBeatHandler.sendMessage(msg);
+ }
+
+ public static void PauseHeartBeat() {
+ pause = true;
+ iofinished.lock();
+ iofinished.unlock();
+ }
+
+ public static void ResumeHeartBeat() {
+ pause = false;
+ }
+
+ public static void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ heartBeatThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/rwwifi/NETRWThread.java b/app/src/main/java/com/lvrenyang/rwwifi/NETRWThread.java
new file mode 100644
index 0000000..e1a6758
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/rwwifi/NETRWThread.java
@@ -0,0 +1,340 @@
+package com.lvrenyang.rwwifi;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+
+import com.lvrenyang.callback.RecvCallBack;
+import com.lvrenyang.rwbuf.RxBuffer;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * 这只是单纯处理读数据的线程,如果需要执行工作,还需要另外的线程
+ * 这里面启动心跳线程,构造函数的时候new,start的时候也start子线程,quit的时候也
+ *
+ * @author Administrator
+ *
+ */
+public class NETRWThread extends Thread {
+
+ //private static final Object SLOCK = new Object(); // 读写互斥锁,内部使用。
+ private static volatile NETRWThread netRWThread = null;
+
+ private static final int NETRWHANDLER_READ = 1000;
+
+ private static Handler netrwHandler = null;
+ private static Looper mLooper = null;
+ private static boolean threadInitOK = false;
+
+ private static Socket s = null;
+ public static DataInputStream is = null;
+ public static DataOutputStream os = null;
+ private static boolean isOpened = false;
+
+ private static RecvCallBack callBack = null;
+ private static final Object NULLLOCK = new Object();
+ public static RxBuffer NETRXBuffer = new RxBuffer(0x1000);
+
+ private NETRWThread() {
+ threadInitOK = false;
+ }
+
+ public static NETRWThread InitInstant() {
+ if (netRWThread == null) {
+ synchronized (NETRWThread.class) {
+ if (netRWThread == null) {
+ netRWThread = new NETRWThread();
+ }
+ }
+ }
+ return netRWThread;
+ }
+
+ @Override
+ public void start() {
+ super.start();
+ while (!threadInitOK)
+ ;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ netrwHandler = new NETRWHandler();
+ threadInitOK = true;
+ Looper.loop();
+ }
+
+ private static class NETRWHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case NETRWHANDLER_READ: {
+ byte[] buffer = new byte[0x1000];
+ int rec = 0;
+
+ while (true) {
+
+ try {
+ rec = ReadIsAvaliable(buffer, buffer.length);
+ if (rec > 0) {
+ for (int i = 0; i < rec; i++)
+ NETRXBuffer.PutByte(buffer[i]);
+ OnRecv(buffer, 0, rec);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ }
+
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ break;
+ }
+ }
+
+ Close();
+ break;
+ }
+
+ }
+ }
+ }
+
+ public static boolean Open(String IPAddress, int PortNumber) {
+ boolean result = false;
+ /*synchronized (SLOCK)*/ {
+ result = _Open(IPAddress, PortNumber);
+ }
+ return result;
+ }
+
+ public static boolean _Open(String IPAddress, int PortNumber) {
+ boolean valid = false;
+
+ try {
+
+ SocketAddress socketAddress = new InetSocketAddress(IPAddress,
+ PortNumber);
+ Socket socket = new Socket();
+ socket.connect(socketAddress, 10000);
+ s = socket;
+
+ // s = new Socket(IPAddress, PortNumber);
+ s.setKeepAlive(true);
+ os = new DataOutputStream(s.getOutputStream());
+ is = new DataInputStream(s.getInputStream());
+ valid = true;
+ } catch (UnknownHostException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ valid = false;
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ valid = false;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ valid = false;
+ }
+
+ // 如果成功了,则发起读命令
+ if (valid) {
+ isOpened = true;
+ Message msg = netrwHandler.obtainMessage(NETRWHANDLER_READ);
+ netrwHandler.sendMessage(msg);
+ } else {
+ isOpened = false;
+ s = null;
+ }
+
+ return valid;
+ }
+
+ public static void Close() {
+ /*synchronized (SLOCK)*/ {
+ _Close();
+ }
+ }
+
+ public static void _Close() {
+ try {
+ if (is != null) {
+ is.close();
+ is = null;
+ }
+ if (os != null) {
+ os.close();
+ os = null;
+ }
+ if (null != s) {
+ s.close();
+ s = null;
+ }
+ Log.v("NETRWThread Close", "Close Socket");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ isOpened = false;
+ }
+
+ public static boolean IsOpened() {
+ boolean ret = false;
+ /*synchronized (SLOCK)*/ {
+ ret = _IsOpened();
+ }
+ return ret;
+ }
+
+ private static boolean _IsOpened() {
+ return isOpened;
+ }
+
+ public static int Write(byte[] buffer, int offset, int count) {
+ int ret = 0;
+ /*synchronized (SLOCK)*/ {
+ ret = _Write(buffer, offset, count);
+ }
+ return ret;
+ }
+
+ private static int _Write(byte[] buffer, int offset, int count) {
+ int cnt = 0;
+ if (null != os) {
+ try {
+ os.write(buffer, offset, count);
+ os.flush();
+ cnt = count;
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ _Close();
+ }
+ }
+
+ return cnt;
+ }
+
+ /**
+ *
+ * @param buffer
+ * @param byteOffset
+ * @param byteCount
+ * @param timeout
+ * @return 返回实际读取的字节数
+ */
+ public static synchronized int Read(byte[] buffer, int byteOffset,
+ int byteCount, int timeout) {
+ int index = 0;
+ long time = System.currentTimeMillis();
+ while ((System.currentTimeMillis() - time) < timeout) {
+ if (!IsEmpty()) {
+ buffer[index++] = GetByte();
+ }
+
+ if (index == byteCount)
+ break;
+ }
+
+ return index;
+ }
+
+ private static int ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int ret = 0;
+ /*synchronized (SLOCK)*/ {
+ ret = _ReadIsAvaliable(buffer, maxCount);
+ }
+ return ret;
+ }
+
+ private static int _ReadIsAvaliable(byte[] buffer, int maxCount)
+ throws IOException {
+ int available = 0;
+ int rec = -1;
+
+ if (null != is) {
+ available = is.available();
+ if (available > 0) {
+ rec = is.read(buffer, 0, available > maxCount ? maxCount
+ : available);
+ }
+ }
+ return rec;
+ }
+
+ private static void OnRecv(byte[] buffer, int byteOffset, int byteCount) {
+ synchronized (NULLLOCK) {
+ if (null != callBack)
+ callBack.onRecv(buffer, byteOffset, byteCount);
+ }
+ }
+
+ public static void SetOnRecvCallBack(RecvCallBack callback) {
+ synchronized (NULLLOCK) {
+ callBack = callback;
+ }
+ }
+
+ public static boolean Request(byte sendbuf[], int sendlen, int requestlen,
+ byte recbuf[], Integer reclen, int timeout) {
+ int Retry = 3;
+
+ while ((Retry--) > 0) {
+ ClrRec();
+ Write(sendbuf, 0, sendlen);
+ reclen = Read(recbuf, 0, requestlen, timeout);
+ if (requestlen == reclen)
+ return true;
+ }
+ return false;
+ }
+
+ public static void ClrRec() {
+ NETRXBuffer.ClrRec();
+ }
+
+ public static boolean IsEmpty() {
+ return NETRXBuffer.IsEmpty();
+ }
+
+ public static byte GetByte() {
+ return NETRXBuffer.GetByte();
+ }
+
+ public static synchronized void Quit() {
+ try {
+ if (null != mLooper) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ netRWThread = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/utils/DataUtils.java b/app/src/main/java/com/lvrenyang/utils/DataUtils.java
new file mode 100644
index 0000000..a478e70
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/utils/DataUtils.java
@@ -0,0 +1,275 @@
+package com.lvrenyang.utils;
+
+import java.util.Locale;
+import java.util.Random;
+
+public class DataUtils {
+ public static boolean bytesEquals(byte[] d1, byte[] d2) {
+ if (d1 == null && d2 == null)
+ return true;
+ else if (d1 == null || d2 == null)
+ return false;
+
+ if (d1.length != d2.length)
+ return false;
+
+ for (int i = 0; i < d1.length; i++)
+ if (d1[i] != d2[i])
+ return false;
+
+ return true;
+ }
+
+ public static boolean bytesEquals(byte[] d1, int offset1, byte[] d2,
+ int offset2, int length) {
+ if (d1 == null || d2 == null)
+ return false;
+
+ if ((offset1 + length > d1.length) || (offset2 + length > d2.length))
+ return false;
+
+ for (int i = 0; i < length; i++)
+ if (d1[i + offset1] != d2[i + offset2])
+ return false;
+
+ return true;
+ }
+
+ public static char[] bytestochars(byte[] data) {
+ char[] cdata = new char[data.length];
+ for (int i = 0; i < cdata.length; i++)
+ cdata[i] = (char) (data[i] & 0xff);
+ return cdata;
+ }
+
+ public static byte[] getRandomByteArray(int nlength) {
+ byte[] data = new byte[nlength];
+ Random rmByte = new Random(System.currentTimeMillis());
+ for (int i = 0; i < nlength; i++) {
+ // 该方法的作用是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n
+ data[i] = (byte) rmByte.nextInt(256);
+ }
+ return data;
+ }
+
+ public static void blackWhiteReverse(byte data[]) {
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (byte) ~(data[i] & 0xff);
+ }
+ }
+
+ public static byte[] getSubBytes(byte[] org, int start, int length) {
+ byte[] ret = new byte[length];
+ for (int i = 0; i < length; i++) {
+ ret[i] = org[i + start];
+ }
+ return ret;
+ }
+
+ public static String bytesToStr(byte[] rcs) {
+ StringBuilder stringBuilder = new StringBuilder();
+ String tmp;
+ for (int i = 0; i < rcs.length; i++) {
+ tmp = Integer.toHexString(rcs[i] & 0xff);
+ tmp = tmp.toUpperCase(Locale.getDefault());
+ if (tmp.length() == 1) {
+ stringBuilder.append("0x0" + tmp);
+ } else {
+ stringBuilder.append("0x" + tmp);
+ }
+
+ if ((i % 16) != 15) {
+ stringBuilder.append(" ");
+ } else {
+ stringBuilder.append("\n");
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ public static byte[] cloneBytes(byte[] data) {
+ byte[] ret = new byte[data.length];
+ for (int i = 0; i < data.length; i++)
+ ret[i] = data[i];
+ return ret;
+ }
+
+ public static byte bytesToXor(byte[] data, int start, int length) {
+ if (length == 0)
+ return 0;
+ else if (length == 1)
+ return data[start];
+ else {
+ int result = data[start] ^ data[start + 1];
+ for (int i = start + 2; i < start + length; i++)
+ result ^= data[i];
+ return (byte) result;
+ }
+ }
+
+ /**
+ * 将多个字节数组按顺序合并
+ *
+ * @param data
+ * @return
+ */
+ public static byte[] byteArraysToBytes(byte[][] data) {
+
+ int length = 0;
+ for (int i = 0; i < data.length; i++)
+ length += data[i].length;
+ byte[] send = new byte[length];
+ int k = 0;
+ for (int i = 0; i < data.length; i++)
+ for (int j = 0; j < data[i].length; j++)
+ send[k++] = data[i][j];
+ return send;
+ }
+
+ /**
+ *
+ * @param orgdata
+ * @param orgstart
+ * @param desdata
+ * @param desstart
+ * @param copylen
+ */
+ public static void copyBytes(byte[] orgdata, int orgstart, byte[] desdata,
+ int desstart, int copylen) {
+ for (int i = 0; i < copylen; i++) {
+ desdata[desstart + i] = orgdata[orgstart + i];
+ }
+ }
+
+ public static String bytesToStr(byte[] rcs, int offset, int count) {
+ StringBuilder stringBuilder = new StringBuilder();
+ String tmp;
+ for (int i = 0; i < count; i++) {
+ tmp = Integer.toHexString(rcs[i + offset] & 0xff);
+ tmp = tmp.toUpperCase(Locale.getDefault());
+ if (tmp.length() == 1) {
+ stringBuilder.append("0x0" + tmp);
+ } else {
+ stringBuilder.append("0x" + tmp);
+ }
+
+ if ((i % 16) != 15) {
+ stringBuilder.append(" ");
+ } else {
+ stringBuilder.append("\r\n");
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ private static final byte chartobyte[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 0, 0, 0, 0, 0, 0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
+ private static final char bytetochar[] = { '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ /**
+ * 必须保证传进来的ch1和ch2都是数字或者大写ABCDEF
+ *
+ * @param ch1
+ * @param ch2
+ * @return
+ */
+ public static byte HexCharsToByte(char ch, char cl) {
+
+ byte b = (byte) (((chartobyte[ch - '0'] << 4) & 0xF0) | ((chartobyte[cl - '0']) & 0xF));
+
+ return b;
+ }
+
+ public static char[] ByteToHexChars(byte b) {
+ char chs[] = { '0', '0' };
+ chs[0] = bytetochar[(b >> 4) & 0xF];
+ chs[1] = bytetochar[(b) & 0xF];
+ return chs;
+ }
+
+ public static boolean IsHexChar(char c) {
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F'))
+ return true;
+ else
+ return false;
+ }
+
+ public static byte[] HexStringToBytes(String str) {
+ int count = str.length();
+ byte[] data = null;
+ if (count % 2 == 0) {
+ data = new byte[count / 2];
+
+ for (int i = 0; i < count; i += 2) {
+ char ch = str.charAt(i);
+ char cl = str.charAt(i + 1);
+
+ if (IsHexChar(ch) && IsHexChar(cl)) {
+ if (ch >= 'a')
+ ch -= 0x20;
+ if (cl >= 'a')
+ cl -= 0x20;
+ data[i / 2] = HexCharsToByte(ch, cl);
+ } else {
+ data = null;
+ break;
+ }
+ }
+ }
+ return data;
+ }
+
+ public static StringBuilder BytesToHexStr(byte[] data, int offset, int count) {
+ StringBuilder str = new StringBuilder();
+ for (int i = offset; i < offset + count; i++) {
+ str.append(ByteToHexChars(data[i]));
+ }
+ return str;
+ }
+
+ public static StringBuilder RemoveChar(String str, char c) {
+ StringBuilder sb = new StringBuilder();
+ int length = str.length();
+ char tmp;
+ for (int i = 0; i < length; i++) {
+ tmp = str.charAt(i);
+ if (tmp != c)
+ sb.append(tmp);
+ }
+ return sb;
+ }
+
+ public static String byteToStr(byte rc) {
+ String rec;
+ String tmp = Integer.toHexString(rc & 0xff);
+ tmp = tmp.toUpperCase(Locale.getDefault());
+
+ if (tmp.length() == 1) {
+ rec = "0x0" + tmp;
+ } else {
+ rec = "0x" + tmp;
+ }
+
+ return rec;
+ }
+
+ /**
+ * 获取byte的idx处的位 位和索引对应关系为 10001000 76543210
+ *
+ * @param ch
+ * @param idx
+ * @return
+ */
+ public static final int getBit(byte ch, int idx) {
+ return 0x1 & (ch >> idx);
+ }
+
+ public static void BytesArrayFill(byte[] data, int offset, int count,
+ byte value) {
+ for (int i = offset; i < offset + count; ++i)
+ data[i] = value;
+
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/utils/ErrorCode.java b/app/src/main/java/com/lvrenyang/utils/ErrorCode.java
new file mode 100644
index 0000000..c3e4e7f
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/utils/ErrorCode.java
@@ -0,0 +1,48 @@
+package com.lvrenyang.utils;
+
+public class ErrorCode {
+ /**
+ * 其他错误
+ */
+ public static final int ERROR = -1000;
+
+ /**
+ * 空指针错误
+ */
+ public static final int NULLPOINTER = -1001;
+
+ /**
+ * 没有权限
+ */
+ public static final int NOPERMISSION = -1002;
+
+ /**
+ * 参数不符合要求,如n需要大于等于0但给出的是小于0
+ */
+ public static final int INVALPARAM = -1003;
+
+ /**
+ * 出现异常,捕捉之后返回该值
+ */
+ public static final int EXCEPTION = -1004;
+
+ /**
+ * 未连接
+ */
+ public static final int NOTCONNECTED = -1005;
+
+ /**
+ * 未打开
+ */
+ public static final int NOTOPENED = -1006;
+
+ /**
+ * 未实现,这是框架层返回的,如果实现了自己的函数将其覆盖,则不会返回该错误
+ */
+ public static final int NOTIMPLEMENTED = -1007;
+
+ /**
+ * 机器没有蓝牙
+ */
+ public static final int NOBLUETOOTH = -1008;
+}
diff --git a/app/src/main/java/com/lvrenyang/utils/FileUtils.java b/app/src/main/java/com/lvrenyang/utils/FileUtils.java
new file mode 100644
index 0000000..970cebb
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/utils/FileUtils.java
@@ -0,0 +1,146 @@
+package com.lvrenyang.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import android.os.Environment;
+
+public class FileUtils {
+
+ public static final String external_sd_dump_txt = Environment.getExternalStorageDirectory() +
+ File.separator + "dump.txt";
+ public static final String sdcard_dump_txt = "sdcard" + File.separator
+ + "dump.txt";
+
+ public static final boolean debug = true;
+
+ public static void DebugAddToFile(byte[] buffer, int byteOffset, int byteCount,
+ String dumpfile){
+ if(debug)
+ AddToFile(buffer, byteOffset, byteCount , dumpfile);
+ }
+
+ public static void DebugAddToFile(String text, String dumpfile)
+ {
+ if(debug)
+ AddToFile(text, dumpfile);
+ }
+
+ public static void DebugSaveToFile(String text, String dumpfile) {
+ if(debug)
+ SaveToFile(text,dumpfile);
+ }
+
+ /**
+ * 将数据存到文件
+ */
+ public static void AddToFile(byte[] buffer, int byteOffset, int byteCount,
+ String dumpfile) {
+ if (null == dumpfile)
+ return;
+ if (null == buffer)
+ return;
+ if (byteOffset < 0 || byteCount <= 0)
+ return;
+
+ try {
+ File file = new File(dumpfile);
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.seek(file.length());
+ raf.write(buffer, byteOffset, byteCount);
+ raf.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void AddToFile(String text, String dumpfile) {
+ if (null == dumpfile)
+ return;
+ if (null == text)
+ return;
+ if ("".equals(text))
+ return;
+
+ try {
+ File file = new File(dumpfile);
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.seek(file.length());
+ raf.write(text.getBytes());
+ raf.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void SaveToFile(String text, String dumpfile) {
+ if (null == dumpfile)
+ return;
+ if (null == text)
+ return;
+
+ try {
+ File file = new File(dumpfile);
+ if (file.exists())
+ file.delete();
+
+ file.createNewFile();
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ raf.seek(0);
+ raf.write(text.getBytes());
+ raf.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String ReadToString(String filePathName) {
+
+ File file = new File(filePathName);
+ if (!file.exists())
+ return null;
+
+ Long filelength = file.length();
+ byte[] filecontent = new byte[filelength.intValue()];
+ try {
+ FileInputStream in = new FileInputStream(file);
+ in.read(filecontent);
+ in.close();
+ return new String(filecontent);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static byte[] ReadToMem(String filePathName) {
+ File file = new File(filePathName);
+ if (!file.exists())
+ return null;
+
+ Long filelength = file.length();
+ byte[] filecontent = new byte[filelength.intValue()];
+ try {
+ FileInputStream in = new FileInputStream(file);
+ in.read(filecontent);
+ in.close();
+ return filecontent;
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/lvrenyang/utils/IPString.java b/app/src/main/java/com/lvrenyang/utils/IPString.java
new file mode 100644
index 0000000..9c4ea10
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/utils/IPString.java
@@ -0,0 +1,41 @@
+package com.lvrenyang.utils;
+
+public class IPString {
+
+ public static byte[] IsIPValid(String ip)
+ {
+ byte[] ipbytes = new byte[4];
+ int valid = 0;
+ int s,e;
+ String ipstr = ip + ".";
+ s = 0;
+ for(e = 0; e < ipstr.length(); e++)
+ {
+ if ('.' == ipstr.charAt(e))
+ {
+ if ((e - s > 3) || (e - s) <= 0) // 最长3个字符
+ return null;
+
+ int ipbyte = -1;
+ try{
+ ipbyte = Integer.parseInt(ipstr.substring(s, e));
+ if (ipbyte < 0 || ipbyte > 255)
+ return null;
+ else
+ ipbytes[valid] = (byte) ipbyte;
+ }
+ catch(NumberFormatException exce)
+ {
+ return null;
+ }
+ s = e + 1;
+ valid++;
+ }
+ }
+ if (valid == 4)
+ return ipbytes;
+ else
+ return null;
+ }
+
+}
diff --git a/app/src/main/java/com/lvrenyang/utils/TimeUtils.java b/app/src/main/java/com/lvrenyang/utils/TimeUtils.java
new file mode 100644
index 0000000..4d7fc0d
--- /dev/null
+++ b/app/src/main/java/com/lvrenyang/utils/TimeUtils.java
@@ -0,0 +1,10 @@
+package com.lvrenyang.utils;
+
+public class TimeUtils {
+
+ public static void WaitMs(long ms) {
+ long time = System.currentTimeMillis();
+ while (System.currentTimeMillis() - time < ms)
+ ;
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..8585242
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,15 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.0'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..599797f
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jul 06 16:11:19 SGT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/import-summary.txt b/import-summary.txt
new file mode 100644
index 0000000..4073702
--- /dev/null
+++ b/import-summary.txt
@@ -0,0 +1,59 @@
+ECLIPSE ANDROID PROJECT IMPORT SUMMARY
+======================================
+
+Ignored Files:
+--------------
+The following files were *not* copied into the new Gradle project; you
+should evaluate whether these are still needed in your project and if
+so manually move them:
+
+* .idea\
+* .idea\.name
+* .idea\PrinterLibs.iml
+* .idea\compiler.xml
+* .idea\copyright\
+* .idea\copyright\profiles_settings.xml
+* .idea\encodings.xml
+* .idea\misc.xml
+* .idea\modules.xml
+* .idea\scopes\
+* .idea\scopes\scope_settings.xml
+* .idea\vcs.xml
+* .idea\workspace.xml
+* proguard-project.txt
+
+Replaced Jars with Dependencies:
+--------------------------------
+The importer recognized the following .jar files as third party
+libraries and replaced them with Gradle dependencies instead. This has
+the advantage that more explicit version information is known, and the
+libraries can be updated automatically. However, it is possible that
+the .jar file in your project was of an older version than the
+dependency we picked, which could render the project not compileable.
+You can disable the jar replacement in the import wizard and try again:
+
+android-support-v4.jar => com.android.support:support-v4:18.0.0
+
+Moved Files:
+------------
+Android Gradle projects use a different directory structure than ADT
+Eclipse projects. Here's how the projects were restructured:
+
+* AndroidManifest.xml => app\src\main\AndroidManifest.xml
+* res\ => app\src\main\res
+* src\ => app\src\main\java\
+
+Next Steps:
+-----------
+You can now build the project. The Gradle project needs network
+connectivity to download dependencies.
+
+Bugs:
+-----
+If for some reason your project does not build, and you determine that
+it is due to a bug or limitation of the Eclipse to Gradle importer,
+please file a bug at http://b.android.com with category
+Component-Tools.
+
+(This import summary is for your information only, and can be deleted
+after import once you are satisfied with the results.)
diff --git a/local.properties b/local.properties
new file mode 100644
index 0000000..3a26cd8
--- /dev/null
+++ b/local.properties
@@ -0,0 +1,7 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+#
+#Fri Jul 06 16:11:10 SGT 2018
+sdk.dir=C\:\\Users\\Hoan\\AppData\\Local\\Android\\Sdk
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'