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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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'