mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-17 16:36:03 +08:00
添加安卓端基本功能
This commit is contained in:
1
android/esptouch/.gitignore
vendored
Normal file
1
android/esptouch/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
42
android/esptouch/README.md
Normal file
42
android/esptouch/README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# EspTouch
|
||||
[example](../app/src/main/java/com/espressif/esptouch/android/v1)
|
||||
|
||||
- Create task instance
|
||||
```java
|
||||
Context context; // Set Applicatioin context
|
||||
byte[] apSsid = {}; // Set AP's SSID
|
||||
byte[] apBssid = {}; // Set AP's BSSID
|
||||
byte[] apPassword = {}; // Set AP's password
|
||||
|
||||
EsptouchTask task = new EsptouchTask(apSsid, apBssid, apPassword, context);
|
||||
task.setPackageBroadcast(true); // if true send broadcast packets, else send multicast packets
|
||||
```
|
||||
|
||||
- Set result callback
|
||||
```java
|
||||
task.setEsptouchListener(new IEsptouchListener() {
|
||||
@Override
|
||||
public void onEsptouchResultAdded(IEsptouchResult result) {
|
||||
// Result callback
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- Execute task
|
||||
```java
|
||||
int expectResultCount = 1;
|
||||
List<IEsptouchResult> results = task.executeForResults(expectResultCount);
|
||||
IEsptouchResult first = results.get(0);
|
||||
if (first.isCancelled()) {
|
||||
// User cancel the task
|
||||
return;
|
||||
}
|
||||
if (first.isSuc()) {
|
||||
// EspTouch successfully
|
||||
}
|
||||
```
|
||||
|
||||
- Cancel task
|
||||
```java
|
||||
task.interrupt();
|
||||
```
|
||||
31
android/esptouch/build.gradle
Normal file
31
android/esptouch/build.gradle
Normal file
@@ -0,0 +1,31 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 29
|
||||
versionCode 8
|
||||
versionName "v0.3.7.2"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
21
android/esptouch/proguard-rules.pro
vendored
Normal file
21
android/esptouch/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
7
android/esptouch/src/main/AndroidManifest.xml
Normal file
7
android/esptouch/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.espressif.iot.esptouch" >
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.espressif.iot.esptouch;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class EsptouchResult implements IEsptouchResult {
|
||||
|
||||
private final boolean mIsSuc;
|
||||
private final String mBssid;
|
||||
private final InetAddress mInetAddress;
|
||||
private AtomicBoolean mIsCancelled;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchResult
|
||||
*
|
||||
* @param isSuc whether the esptouch task is executed suc
|
||||
* @param bssid the device's bssid
|
||||
* @param inetAddress the device's ip address
|
||||
*/
|
||||
public EsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) {
|
||||
this.mIsSuc = isSuc;
|
||||
this.mBssid = bssid;
|
||||
this.mInetAddress = inetAddress;
|
||||
this.mIsCancelled = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuc() {
|
||||
return this.mIsSuc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBssid() {
|
||||
return this.mBssid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return mIsCancelled.get();
|
||||
}
|
||||
|
||||
public void setIsCancelled(boolean isCancelled) {
|
||||
this.mIsCancelled.set(isCancelled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
return this.mInetAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("bssid=%s, address=%s, suc=%b, cancel=%b", mBssid,
|
||||
mInetAddress == null ? null : mInetAddress.getHostAddress(), mIsSuc, mIsCancelled.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.espressif.iot.esptouch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.espressif.iot.esptouch.protocol.TouchData;
|
||||
import com.espressif.iot.esptouch.security.ITouchEncryptor;
|
||||
import com.espressif.iot.esptouch.task.EsptouchTaskParameter;
|
||||
import com.espressif.iot.esptouch.task.__EsptouchTask;
|
||||
import com.espressif.iot.esptouch.util.TouchNetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EsptouchTask implements IEsptouchTask {
|
||||
private __EsptouchTask _mEsptouchTask;
|
||||
private EsptouchTaskParameter _mParameter;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchTask
|
||||
*
|
||||
* @param apSsid the Ap's ssid
|
||||
* @param apBssid the Ap's bssid
|
||||
* @param apPassword the Ap's password
|
||||
* @param context the {@link Context} of the Application
|
||||
*/
|
||||
public EsptouchTask(String apSsid, String apBssid, String apPassword, Context context) {
|
||||
this(apSsid, apBssid, apPassword, null, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchTask
|
||||
*
|
||||
* @param apSsid the Ap's ssid
|
||||
* @param apBssid the Ap's bssid
|
||||
* @param apPassword the Ap's password
|
||||
* @param context the {@link Context} of the Application
|
||||
*/
|
||||
public EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, Context context) {
|
||||
this(apSsid, apBssid, apPassword, null, context);
|
||||
}
|
||||
|
||||
private EsptouchTask(String apSsid, String apBssid, String apPassword, ITouchEncryptor encryptor, Context context) {
|
||||
if (TextUtils.isEmpty(apSsid)) {
|
||||
throw new NullPointerException("SSID can't be empty");
|
||||
}
|
||||
if (TextUtils.isEmpty(apBssid)) {
|
||||
throw new NullPointerException("BSSID can't be empty");
|
||||
}
|
||||
if (apPassword == null) {
|
||||
apPassword = "";
|
||||
}
|
||||
TouchData ssid = new TouchData(apSsid);
|
||||
TouchData bssid = new TouchData(TouchNetUtil.parseBssid2bytes(apBssid));
|
||||
if (bssid.getData().length != 6) {
|
||||
throw new IllegalArgumentException("Bssid format must be aa:bb:cc:dd:ee:ff");
|
||||
}
|
||||
TouchData password = new TouchData(apPassword);
|
||||
init(context, ssid, bssid, password, encryptor);
|
||||
}
|
||||
|
||||
private EsptouchTask(byte[] apSsid, byte[] apBssid, byte[] apPassword, ITouchEncryptor encryptor, Context context) {
|
||||
if (apSsid == null || apSsid.length == 0) {
|
||||
throw new NullPointerException("SSID can't be empty");
|
||||
}
|
||||
if (apBssid == null || apBssid.length != 6) {
|
||||
throw new NullPointerException("BSSID is empty or length is not 6");
|
||||
}
|
||||
if (apPassword == null) {
|
||||
apPassword = new byte[0];
|
||||
}
|
||||
TouchData ssid = new TouchData(apSsid);
|
||||
TouchData bssid = new TouchData(apBssid);
|
||||
TouchData password = new TouchData(apPassword);
|
||||
init(context, ssid, bssid, password, encryptor);
|
||||
}
|
||||
|
||||
private void init(Context context, TouchData ssid, TouchData bssid, TouchData password, ITouchEncryptor encryptor) {
|
||||
_mParameter = new EsptouchTaskParameter();
|
||||
_mEsptouchTask = new __EsptouchTask(context, ssid, bssid, password, encryptor, _mParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
_mEsptouchTask.interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEsptouchResult executeForResult() throws RuntimeException {
|
||||
return _mEsptouchTask.executeForResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return _mEsptouchTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IEsptouchResult> executeForResults(int expectTaskResultCount)
|
||||
throws RuntimeException {
|
||||
if (expectTaskResultCount <= 0) {
|
||||
expectTaskResultCount = Integer.MAX_VALUE;
|
||||
}
|
||||
return _mEsptouchTask.executeForResults(expectTaskResultCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEsptouchListener(IEsptouchListener esptouchListener) {
|
||||
_mEsptouchTask.setEsptouchListener(esptouchListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPackageBroadcast(boolean broadcast) {
|
||||
_mParameter.setBroadcast(broadcast);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.espressif.iot.esptouch;
|
||||
|
||||
public interface IEsptouchListener {
|
||||
/**
|
||||
* when new esptouch result is added, the listener will call
|
||||
* onEsptouchResultAdded callback
|
||||
*
|
||||
* @param result the Esptouch result
|
||||
*/
|
||||
void onEsptouchResultAdded(IEsptouchResult result);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.espressif.iot.esptouch;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface IEsptouchResult {
|
||||
|
||||
/**
|
||||
* check whether the esptouch task is executed suc
|
||||
*
|
||||
* @return whether the esptouch task is executed suc
|
||||
*/
|
||||
boolean isSuc();
|
||||
|
||||
/**
|
||||
* get the device's bssid
|
||||
*
|
||||
* @return the device's bssid
|
||||
*/
|
||||
String getBssid();
|
||||
|
||||
/**
|
||||
* check whether the esptouch task is cancelled by user
|
||||
*
|
||||
* @return whether the esptouch task is cancelled by user
|
||||
*/
|
||||
boolean isCancelled();
|
||||
|
||||
/**
|
||||
* get the ip address of the device
|
||||
*
|
||||
* @return the ip device of the device
|
||||
*/
|
||||
InetAddress getInetAddress();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.espressif.iot.esptouch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IEsptouchTask {
|
||||
String ESPTOUCH_VERSION = BuildConfig.VERSION_NAME;
|
||||
|
||||
/**
|
||||
* set the esptouch listener, when one device is connected to the Ap, it will be called back
|
||||
*
|
||||
* @param esptouchListener when one device is connected to the Ap, it will be called back
|
||||
*/
|
||||
void setEsptouchListener(IEsptouchListener esptouchListener);
|
||||
|
||||
/**
|
||||
* Interrupt the Esptouch Task when User tap back or close the Application.
|
||||
*/
|
||||
void interrupt();
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||
* be thrown Execute the Esptouch Task and return the result
|
||||
* <p>
|
||||
* Smart Config v2.4 support the API
|
||||
*
|
||||
* @return the IEsptouchResult
|
||||
*/
|
||||
IEsptouchResult executeForResult() throws RuntimeException;
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||
* be thrown Execute the Esptouch Task and return the result
|
||||
* <p>
|
||||
* Smart Config v2.4 support the API
|
||||
* <p>
|
||||
* It will be blocked until the client receive result count >= expectTaskResultCount.
|
||||
* If it fail, it will return one fail result will be returned in the list.
|
||||
* If it is cancelled while executing,
|
||||
* if it has received some results, all of them will be returned in the list.
|
||||
* if it hasn't received any results, one cancel result will be returned in the list.
|
||||
*
|
||||
* @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0,
|
||||
* expectTaskResultCount = Integer.MAX_VALUE)
|
||||
* @return the list of IEsptouchResult
|
||||
*/
|
||||
List<IEsptouchResult> executeForResults(int expectTaskResultCount) throws RuntimeException;
|
||||
|
||||
/**
|
||||
* check whether the task is cancelled by user
|
||||
*
|
||||
* @return whether the task is cancelled by user
|
||||
*/
|
||||
boolean isCancelled();
|
||||
|
||||
/**
|
||||
* Set broadcast or multicast when post configure info
|
||||
*
|
||||
* @param broadcast true is broadcast, false is multicast
|
||||
*/
|
||||
void setPackageBroadcast(boolean broadcast);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.espressif.iot.esptouch.protocol;
|
||||
|
||||
import com.espressif.iot.esptouch.task.ICodeData;
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
import com.espressif.iot.esptouch.util.CRC8;
|
||||
|
||||
/**
|
||||
* one data format:(data code should have 2 to 65 data)
|
||||
* <p>
|
||||
* control byte high 4 bits low 4 bits
|
||||
* 1st 9bits: 0x0 crc(high) data(high)
|
||||
* 2nd 9bits: 0x1 sequence header
|
||||
* 3rd 9bits: 0x0 crc(low) data(low)
|
||||
* <p>
|
||||
* sequence header: 0,1,2,...
|
||||
*
|
||||
* @author afunx
|
||||
*/
|
||||
public class DataCode implements ICodeData {
|
||||
|
||||
public static final int DATA_CODE_LEN = 6;
|
||||
|
||||
private static final int INDEX_MAX = 127;
|
||||
|
||||
private final byte mSeqHeader;
|
||||
private final byte mDataHigh;
|
||||
private final byte mDataLow;
|
||||
// the crc here means the crc of the data and sequence header be transformed
|
||||
// it is calculated by index and data to be transformed
|
||||
private final byte mCrcHigh;
|
||||
private final byte mCrcLow;
|
||||
|
||||
/**
|
||||
* Constructor of DataCode
|
||||
*
|
||||
* @param u8 the character to be transformed
|
||||
* @param index the index of the char
|
||||
*/
|
||||
public DataCode(char u8, int index) {
|
||||
if (index > INDEX_MAX) {
|
||||
throw new RuntimeException("index > INDEX_MAX");
|
||||
}
|
||||
byte[] dataBytes = ByteUtil.splitUint8To2bytes(u8);
|
||||
mDataHigh = dataBytes[0];
|
||||
mDataLow = dataBytes[1];
|
||||
CRC8 crc8 = new CRC8();
|
||||
crc8.update(ByteUtil.convertUint8toByte(u8));
|
||||
crc8.update(index);
|
||||
byte[] crcBytes = ByteUtil.splitUint8To2bytes((char) crc8.getValue());
|
||||
mCrcHigh = crcBytes[0];
|
||||
mCrcLow = crcBytes[1];
|
||||
mSeqHeader = (byte) index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
byte[] dataBytes = new byte[DATA_CODE_LEN];
|
||||
dataBytes[0] = 0x00;
|
||||
dataBytes[1] = ByteUtil.combine2bytesToOne(mCrcHigh, mDataHigh);
|
||||
dataBytes[2] = 0x01;
|
||||
dataBytes[3] = mSeqHeader;
|
||||
dataBytes[4] = 0x00;
|
||||
dataBytes[5] = ByteUtil.combine2bytesToOne(mCrcLow, mDataLow);
|
||||
return dataBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] dataBytes = getBytes();
|
||||
for (int i = 0; i < DATA_CODE_LEN; i++) {
|
||||
String hexString = ByteUtil.convertByte2HexString(dataBytes[i]);
|
||||
sb.append("0x");
|
||||
if (hexString.length() == 1) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(hexString).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getU8s() {
|
||||
throw new RuntimeException("DataCode don't support getU8s()");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.espressif.iot.esptouch.protocol;
|
||||
|
||||
import com.espressif.iot.esptouch.security.ITouchEncryptor;
|
||||
import com.espressif.iot.esptouch.task.ICodeData;
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
import com.espressif.iot.esptouch.util.CRC8;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class DatumCode implements ICodeData {
|
||||
|
||||
// define by the Esptouch protocol, all of the datum code should add 1 at last to prevent 0
|
||||
private static final int EXTRA_LEN = 40;
|
||||
private static final int EXTRA_HEAD_LEN = 5;
|
||||
|
||||
private final LinkedList<DataCode> mDataCodes;
|
||||
|
||||
/**
|
||||
* Constructor of DatumCode
|
||||
*
|
||||
* @param apSsid the Ap's ssid
|
||||
* @param apBssid the Ap's bssid
|
||||
* @param apPassword the Ap's password
|
||||
* @param ipAddress the ip address of the phone or pad
|
||||
* @param encryptor null use origin data, not null use encrypted data
|
||||
*/
|
||||
public DatumCode(byte[] apSsid, byte[] apBssid, byte[] apPassword,
|
||||
InetAddress ipAddress, ITouchEncryptor encryptor) {
|
||||
// Data = total len(1 byte) + apPwd len(1 byte) + SSID CRC(1 byte) +
|
||||
// BSSID CRC(1 byte) + TOTAL XOR(1 byte)+ ipAddress(4 byte) + apPwd + apSsid apPwdLen <=
|
||||
// 105 at the moment
|
||||
|
||||
// total xor
|
||||
char totalXor = 0;
|
||||
|
||||
char apPwdLen = (char) apPassword.length;
|
||||
CRC8 crc = new CRC8();
|
||||
crc.update(apSsid);
|
||||
char apSsidCrc = (char) crc.getValue();
|
||||
|
||||
crc.reset();
|
||||
crc.update(apBssid);
|
||||
char apBssidCrc = (char) crc.getValue();
|
||||
|
||||
char apSsidLen = (char) apSsid.length;
|
||||
|
||||
byte[] ipBytes = ipAddress.getAddress();
|
||||
int ipLen = ipBytes.length;
|
||||
|
||||
char totalLen = (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen);
|
||||
|
||||
// build data codes
|
||||
mDataCodes = new LinkedList<>();
|
||||
mDataCodes.add(new DataCode(totalLen, 0));
|
||||
totalXor ^= totalLen;
|
||||
mDataCodes.add(new DataCode(apPwdLen, 1));
|
||||
totalXor ^= apPwdLen;
|
||||
mDataCodes.add(new DataCode(apSsidCrc, 2));
|
||||
totalXor ^= apSsidCrc;
|
||||
mDataCodes.add(new DataCode(apBssidCrc, 3));
|
||||
totalXor ^= apBssidCrc;
|
||||
// ESPDataCode 4 is null
|
||||
for (int i = 0; i < ipLen; ++i) {
|
||||
char c = ByteUtil.convertByte2Uint8(ipBytes[i]);
|
||||
totalXor ^= c;
|
||||
mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN));
|
||||
}
|
||||
|
||||
for (int i = 0; i < apPassword.length; i++) {
|
||||
char c = ByteUtil.convertByte2Uint8(apPassword[i]);
|
||||
totalXor ^= c;
|
||||
mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN + ipLen));
|
||||
}
|
||||
|
||||
// totalXor will xor apSsidChars no matter whether the ssid is hidden
|
||||
for (int i = 0; i < apSsid.length; i++) {
|
||||
char c = ByteUtil.convertByte2Uint8(apSsid[i]);
|
||||
totalXor ^= c;
|
||||
mDataCodes.add(new DataCode(c, i + EXTRA_HEAD_LEN + ipLen + apPwdLen));
|
||||
}
|
||||
|
||||
// add total xor last
|
||||
mDataCodes.add(4, new DataCode(totalXor, 4));
|
||||
|
||||
// add bssid
|
||||
int bssidInsertIndex = EXTRA_HEAD_LEN;
|
||||
for (int i = 0; i < apBssid.length; i++) {
|
||||
int index = totalLen + i;
|
||||
char c = ByteUtil.convertByte2Uint8(apBssid[i]);
|
||||
DataCode dc = new DataCode(c, index);
|
||||
if (bssidInsertIndex >= mDataCodes.size()) {
|
||||
mDataCodes.add(dc);
|
||||
} else {
|
||||
mDataCodes.add(bssidInsertIndex, dc);
|
||||
}
|
||||
bssidInsertIndex += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
byte[] datumCode = new byte[mDataCodes.size() * DataCode.DATA_CODE_LEN];
|
||||
int index = 0;
|
||||
for (DataCode dc : mDataCodes) {
|
||||
for (byte b : dc.getBytes()) {
|
||||
datumCode[index++] = b;
|
||||
}
|
||||
}
|
||||
return datumCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] dataBytes = getBytes();
|
||||
for (byte dataByte : dataBytes) {
|
||||
String hexString = ByteUtil.convertByte2HexString(dataByte);
|
||||
sb.append("0x");
|
||||
if (hexString.length() == 1) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(hexString).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getU8s() {
|
||||
byte[] dataBytes = getBytes();
|
||||
int len = dataBytes.length / 2;
|
||||
char[] dataU8s = new char[len];
|
||||
byte high, low;
|
||||
for (int i = 0; i < len; i++) {
|
||||
high = dataBytes[i * 2];
|
||||
low = dataBytes[i * 2 + 1];
|
||||
dataU8s[i] = (char) (ByteUtil.combine2bytesToU16(high, low) + EXTRA_LEN);
|
||||
}
|
||||
return dataU8s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.espressif.iot.esptouch.protocol;
|
||||
|
||||
import com.espressif.iot.esptouch.security.ITouchEncryptor;
|
||||
import com.espressif.iot.esptouch.task.IEsptouchGenerator;
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class EsptouchGenerator implements IEsptouchGenerator {
|
||||
|
||||
private final byte[][] mGcBytes2;
|
||||
private final byte[][] mDcBytes2;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchGenerator, it will cost some time(maybe a bit
|
||||
* much)
|
||||
*
|
||||
* @param apSsid the Ap's ssid
|
||||
* @param apBssid the Ap's bssid
|
||||
* @param apPassword the Ap's password
|
||||
* @param inetAddress the phone's or pad's local ip address allocated by Ap
|
||||
*/
|
||||
public EsptouchGenerator(byte[] apSsid, byte[] apBssid, byte[] apPassword, InetAddress inetAddress,
|
||||
ITouchEncryptor encryptor) {
|
||||
// generate guide code
|
||||
GuideCode gc = new GuideCode();
|
||||
char[] gcU81 = gc.getU8s();
|
||||
mGcBytes2 = new byte[gcU81.length][];
|
||||
|
||||
for (int i = 0; i < mGcBytes2.length; i++) {
|
||||
mGcBytes2[i] = ByteUtil.genSpecBytes(gcU81[i]);
|
||||
}
|
||||
|
||||
// generate data code
|
||||
DatumCode dc = new DatumCode(apSsid, apBssid, apPassword, inetAddress, encryptor);
|
||||
char[] dcU81 = dc.getU8s();
|
||||
mDcBytes2 = new byte[dcU81.length][];
|
||||
|
||||
for (int i = 0; i < mDcBytes2.length; i++) {
|
||||
mDcBytes2[i] = ByteUtil.genSpecBytes(dcU81[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[][] getGCBytes2() {
|
||||
return mGcBytes2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[][] getDCBytes2() {
|
||||
return mDcBytes2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.espressif.iot.esptouch.protocol;
|
||||
|
||||
import com.espressif.iot.esptouch.task.ICodeData;
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
|
||||
public class GuideCode implements ICodeData {
|
||||
|
||||
public static final int GUIDE_CODE_LEN = 4;
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
throw new RuntimeException("DataCode don't support getBytes()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] dataU8s = getU8s();
|
||||
for (int i = 0; i < GUIDE_CODE_LEN; i++) {
|
||||
String hexString = ByteUtil.convertU8ToHexString(dataU8s[i]);
|
||||
sb.append("0x");
|
||||
if (hexString.length() == 1) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(hexString).append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getU8s() {
|
||||
char[] guidesU8s = new char[GUIDE_CODE_LEN];
|
||||
guidesU8s[0] = 515;
|
||||
guidesU8s[1] = 514;
|
||||
guidesU8s[2] = 513;
|
||||
guidesU8s[3] = 512;
|
||||
return guidesU8s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.espressif.iot.esptouch.protocol;
|
||||
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
|
||||
public class TouchData {
|
||||
private final byte[] mData;
|
||||
|
||||
public TouchData(String string) {
|
||||
mData = ByteUtil.getBytesByString(string);
|
||||
}
|
||||
|
||||
public TouchData(byte[] data) {
|
||||
if (data == null) {
|
||||
throw new NullPointerException("data can't be null");
|
||||
}
|
||||
mData = data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return mData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.espressif.iot.esptouch.security;
|
||||
|
||||
public interface ITouchEncryptor {
|
||||
byte[] encrypt(byte[] src);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.espressif.iot.esptouch.security;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class TouchAES implements ITouchEncryptor {
|
||||
private static final String TRANSFORMATION_DEFAULT = "AES/ECB/PKCS5Padding";
|
||||
|
||||
private final byte[] mKey;
|
||||
private final byte[] mIV;
|
||||
private final String mTransformation;
|
||||
private Cipher mEncryptCipher;
|
||||
private Cipher mDecryptCipher;
|
||||
|
||||
public TouchAES(byte[] key) {
|
||||
this(key, null, TRANSFORMATION_DEFAULT);
|
||||
}
|
||||
|
||||
public TouchAES(byte[] key, String transformation) {
|
||||
this(key, null, transformation);
|
||||
}
|
||||
|
||||
public TouchAES(byte[] key, byte[] iv) {
|
||||
this(key, iv, TRANSFORMATION_DEFAULT);
|
||||
}
|
||||
|
||||
public TouchAES(byte[] key, byte[] iv, String transformation) {
|
||||
mKey = key;
|
||||
mIV = iv;
|
||||
mTransformation = transformation;
|
||||
|
||||
mEncryptCipher = createEncryptCipher();
|
||||
mDecryptCipher = createDecryptCipher();
|
||||
}
|
||||
|
||||
private Cipher createEncryptCipher() {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(mTransformation);
|
||||
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES");
|
||||
if (mIV == null) {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||
} else {
|
||||
IvParameterSpec parameterSpec = new IvParameterSpec(mIV);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameterSpec);
|
||||
}
|
||||
|
||||
return cipher;
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
|
||||
e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Cipher createDecryptCipher() {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(mTransformation);
|
||||
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(mKey, "AES");
|
||||
if (mIV == null) {
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||
} else {
|
||||
IvParameterSpec parameterSpec = new IvParameterSpec(mIV);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, parameterSpec);
|
||||
}
|
||||
|
||||
return cipher;
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
|
||||
e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] content) {
|
||||
try {
|
||||
return mEncryptCipher.doFinal(content);
|
||||
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] content) {
|
||||
try {
|
||||
return mDecryptCipher.doFinal(content);
|
||||
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
public class EsptouchTaskParameter implements IEsptouchTaskParameter {
|
||||
|
||||
private static int _datagramCount = 0;
|
||||
private long mIntervalGuideCodeMillisecond;
|
||||
private long mIntervalDataCodeMillisecond;
|
||||
private long mTimeoutGuideCodeMillisecond;
|
||||
private long mTimeoutDataCodeMillisecond;
|
||||
private int mTotalRepeatTime;
|
||||
private int mEsptouchResultOneLen;
|
||||
private int mEsptouchResultMacLen;
|
||||
private int mEsptouchResultIpLen;
|
||||
private int mEsptouchResultTotalLen;
|
||||
private int mPortListening;
|
||||
private int mTargetPort;
|
||||
private int mWaitUdpReceivingMilliseond;
|
||||
private int mWaitUdpSendingMillisecond;
|
||||
private int mThresholdSucBroadcastCount;
|
||||
private int mExpectTaskResultCount;
|
||||
private boolean mBroadcast = true;
|
||||
|
||||
public EsptouchTaskParameter() {
|
||||
mIntervalGuideCodeMillisecond = 8;
|
||||
mIntervalDataCodeMillisecond = 8;
|
||||
mTimeoutGuideCodeMillisecond = 2000;
|
||||
mTimeoutDataCodeMillisecond = 4000;
|
||||
mTotalRepeatTime = 1;
|
||||
mEsptouchResultOneLen = 1;
|
||||
mEsptouchResultMacLen = 6;
|
||||
mEsptouchResultIpLen = 4;
|
||||
mEsptouchResultTotalLen = 1 + 6 + 4;
|
||||
mPortListening = 18266;
|
||||
mTargetPort = 7001;
|
||||
mWaitUdpReceivingMilliseond = 15000;
|
||||
mWaitUdpSendingMillisecond = 45000;
|
||||
mThresholdSucBroadcastCount = 1;
|
||||
mExpectTaskResultCount = 1;
|
||||
}
|
||||
|
||||
// the range of the result should be 1-100
|
||||
private static int __getNextDatagramCount() {
|
||||
return 1 + (_datagramCount++) % 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIntervalGuideCodeMillisecond() {
|
||||
return mIntervalGuideCodeMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIntervalDataCodeMillisecond() {
|
||||
return mIntervalDataCodeMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeoutGuideCodeMillisecond() {
|
||||
return mTimeoutGuideCodeMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeoutDataCodeMillisecond() {
|
||||
return mTimeoutDataCodeMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeoutTotalCodeMillisecond() {
|
||||
return mTimeoutGuideCodeMillisecond + mTimeoutDataCodeMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalRepeatTime() {
|
||||
return mTotalRepeatTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEsptouchResultOneLen() {
|
||||
return mEsptouchResultOneLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEsptouchResultMacLen() {
|
||||
return mEsptouchResultMacLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEsptouchResultIpLen() {
|
||||
return mEsptouchResultIpLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEsptouchResultTotalLen() {
|
||||
return mEsptouchResultTotalLen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPortListening() {
|
||||
return mPortListening;
|
||||
}
|
||||
|
||||
// target hostname is : 234.1.1.1, 234.2.2.2, 234.3.3.3 to 234.100.100.100
|
||||
@Override
|
||||
public String getTargetHostname() {
|
||||
if (mBroadcast) {
|
||||
return "255.255.255.255";
|
||||
} else {
|
||||
int count = __getNextDatagramCount();
|
||||
return "234." + count + "." + count + "." + count;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetPort() {
|
||||
return mTargetPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWaitUdpReceivingMillisecond() {
|
||||
return mWaitUdpReceivingMilliseond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWaitUdpSendingMillisecond() {
|
||||
return mWaitUdpSendingMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWaitUdpTotalMillisecond() {
|
||||
return mWaitUdpReceivingMilliseond + mWaitUdpSendingMillisecond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond) {
|
||||
if (waitUdpTotalMillisecond < mWaitUdpReceivingMilliseond
|
||||
+ getTimeoutTotalCodeMillisecond()) {
|
||||
// if it happen, even one turn about sending udp broadcast can't be
|
||||
// completed
|
||||
throw new IllegalArgumentException(
|
||||
"waitUdpTotalMillisecod is invalid, "
|
||||
+ "it is less than mWaitUdpReceivingMilliseond + getTimeoutTotalCodeMillisecond()");
|
||||
}
|
||||
mWaitUdpSendingMillisecond = waitUdpTotalMillisecond
|
||||
- mWaitUdpReceivingMilliseond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThresholdSucBroadcastCount() {
|
||||
return mThresholdSucBroadcastCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExpectTaskResultCount() {
|
||||
return this.mExpectTaskResultCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectTaskResultCount(int expectTaskResultCount) {
|
||||
this.mExpectTaskResultCount = expectTaskResultCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBroadcast(boolean broadcast) {
|
||||
mBroadcast = broadcast;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
/**
|
||||
* the class used to represent some code to be transformed by UDP socket should implement the interface
|
||||
*
|
||||
* @author afunx
|
||||
*/
|
||||
public interface ICodeData {
|
||||
/**
|
||||
* Get the byte[] to be transformed.
|
||||
*
|
||||
* @return the byte[] to be transfromed
|
||||
*/
|
||||
byte[] getBytes();
|
||||
|
||||
/**
|
||||
* Get the char[](u8[]) to be transfromed.
|
||||
*
|
||||
* @return the char[](u8) to be transformed
|
||||
*/
|
||||
char[] getU8s();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
public interface IEsptouchGenerator {
|
||||
/**
|
||||
* Get guide code by the format of byte[][]
|
||||
*
|
||||
* @return guide code by the format of byte[][]
|
||||
*/
|
||||
byte[][] getGCBytes2();
|
||||
|
||||
/**
|
||||
* Get data code by the format of byte[][]
|
||||
*
|
||||
* @return data code by the format of byte[][]
|
||||
*/
|
||||
byte[][] getDCBytes2();
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
public interface IEsptouchTaskParameter {
|
||||
|
||||
/**
|
||||
* get interval millisecond for guide code(the time between each guide code sending)
|
||||
*
|
||||
* @return interval millisecond for guide code(the time between each guide code sending)
|
||||
*/
|
||||
long getIntervalGuideCodeMillisecond();
|
||||
|
||||
/**
|
||||
* get interval millisecond for data code(the time between each data code sending)
|
||||
*
|
||||
* @return interval millisecond for data code(the time between each data code sending)
|
||||
*/
|
||||
long getIntervalDataCodeMillisecond();
|
||||
|
||||
/**
|
||||
* get timeout millisecond for guide code(the time how much the guide code sending)
|
||||
*
|
||||
* @return timeout millisecond for guide code(the time how much the guide code sending)
|
||||
*/
|
||||
long getTimeoutGuideCodeMillisecond();
|
||||
|
||||
/**
|
||||
* get timeout millisecond for data code(the time how much the data code sending)
|
||||
*
|
||||
* @return timeout millisecond for data code(the time how much the data code sending)
|
||||
*/
|
||||
long getTimeoutDataCodeMillisecond();
|
||||
|
||||
/**
|
||||
* get timeout millisecond for total code(guide code and data code altogether)
|
||||
*
|
||||
* @return timeout millisecond for total code(guide code and data code altogether)
|
||||
*/
|
||||
long getTimeoutTotalCodeMillisecond();
|
||||
|
||||
/**
|
||||
* get total repeat time for executing esptouch task
|
||||
*
|
||||
* @return total repeat time for executing esptouch task
|
||||
*/
|
||||
int getTotalRepeatTime();
|
||||
|
||||
/**
|
||||
* the length of the Esptouch result 1st byte is the total length of ssid and
|
||||
* password, the other 6 bytes are the device's bssid
|
||||
*/
|
||||
|
||||
/**
|
||||
* get esptouchResult length of one
|
||||
*
|
||||
* @return length of one
|
||||
*/
|
||||
int getEsptouchResultOneLen();
|
||||
|
||||
/**
|
||||
* get esptouchResult length of mac
|
||||
*
|
||||
* @return length of mac
|
||||
*/
|
||||
int getEsptouchResultMacLen();
|
||||
|
||||
/**
|
||||
* get esptouchResult length of ip
|
||||
*
|
||||
* @return length of ip
|
||||
*/
|
||||
int getEsptouchResultIpLen();
|
||||
|
||||
/**
|
||||
* get esptouchResult total length
|
||||
*
|
||||
* @return total length
|
||||
*/
|
||||
int getEsptouchResultTotalLen();
|
||||
|
||||
/**
|
||||
* get port for listening(used by server)
|
||||
*
|
||||
* @return port for listening(used by server)
|
||||
*/
|
||||
int getPortListening();
|
||||
|
||||
/**
|
||||
* get target hostname
|
||||
*
|
||||
* @return target hostame(used by client)
|
||||
*/
|
||||
String getTargetHostname();
|
||||
|
||||
/**
|
||||
* get target port
|
||||
*
|
||||
* @return target port(used by client)
|
||||
*/
|
||||
int getTargetPort();
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp receiving(receiving without sending)
|
||||
*
|
||||
* @return millisecond for waiting udp receiving(receiving without sending)
|
||||
*/
|
||||
int getWaitUdpReceivingMillisecond();
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp sending(sending including receiving)
|
||||
*
|
||||
* @return millisecond for waiting udep sending(sending including receiving)
|
||||
*/
|
||||
int getWaitUdpSendingMillisecond();
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp sending and receiving
|
||||
*
|
||||
* @return millisecond for waiting udp sending and receiving
|
||||
*/
|
||||
int getWaitUdpTotalMillisecond();
|
||||
|
||||
/**
|
||||
* set the millisecond for waiting udp sending and receiving
|
||||
*
|
||||
* @param waitUdpTotalMillisecond the millisecond for waiting udp sending and receiving
|
||||
*/
|
||||
void setWaitUdpTotalMillisecond(int waitUdpTotalMillisecond);
|
||||
|
||||
/**
|
||||
* get the threshold for how many correct broadcast should be received
|
||||
*
|
||||
* @return the threshold for how many correct broadcast should be received
|
||||
*/
|
||||
int getThresholdSucBroadcastCount();
|
||||
|
||||
/**
|
||||
* get the count of expect task results
|
||||
*
|
||||
* @return the count of expect task results
|
||||
*/
|
||||
int getExpectTaskResultCount();
|
||||
|
||||
/**
|
||||
* set the count of expect task results
|
||||
*
|
||||
* @param expectTaskResultCount the count of expect task results
|
||||
*/
|
||||
void setExpectTaskResultCount(int expectTaskResultCount);
|
||||
|
||||
/**
|
||||
* Set broadcast or multicast
|
||||
*
|
||||
* @param broadcast true is broadcast, false is multicast
|
||||
*/
|
||||
void setBroadcast(boolean broadcast);
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.espressif.iot.esptouch.EsptouchResult;
|
||||
import com.espressif.iot.esptouch.IEsptouchListener;
|
||||
import com.espressif.iot.esptouch.IEsptouchResult;
|
||||
import com.espressif.iot.esptouch.IEsptouchTask;
|
||||
import com.espressif.iot.esptouch.protocol.EsptouchGenerator;
|
||||
import com.espressif.iot.esptouch.protocol.TouchData;
|
||||
import com.espressif.iot.esptouch.security.ITouchEncryptor;
|
||||
import com.espressif.iot.esptouch.udp.UDPSocketClient;
|
||||
import com.espressif.iot.esptouch.udp.UDPSocketServer;
|
||||
import com.espressif.iot.esptouch.util.ByteUtil;
|
||||
import com.espressif.iot.esptouch.util.TouchNetUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class __EsptouchTask implements __IEsptouchTask {
|
||||
/**
|
||||
* one indivisible data contain 3 9bits info
|
||||
*/
|
||||
private static final int ONE_DATA_LEN = 3;
|
||||
|
||||
private static final String TAG = "__EsptouchTask";
|
||||
|
||||
private final UDPSocketClient mSocketClient;
|
||||
private final UDPSocketServer mSocketServer;
|
||||
private final byte[] mApSsid;
|
||||
private final byte[] mApPassword;
|
||||
private final byte[] mApBssid;
|
||||
private final ITouchEncryptor mEncryptor;
|
||||
private final Context mContext;
|
||||
private final List<IEsptouchResult> mEsptouchResultList;
|
||||
private volatile boolean mIsSuc = false;
|
||||
private volatile boolean mIsInterrupt = false;
|
||||
private volatile boolean mIsExecuted = false;
|
||||
private AtomicBoolean mIsCancelled;
|
||||
private IEsptouchTaskParameter mParameter;
|
||||
private volatile Map<String, Integer> mBssidTaskSucCountMap;
|
||||
private IEsptouchListener mEsptouchListener;
|
||||
private Thread mTask;
|
||||
|
||||
public __EsptouchTask(Context context, TouchData apSsid, TouchData apBssid, TouchData apPassword,
|
||||
ITouchEncryptor encryptor, IEsptouchTaskParameter parameter) {
|
||||
Log.i(TAG, "Welcome Esptouch " + IEsptouchTask.ESPTOUCH_VERSION);
|
||||
mContext = context;
|
||||
mEncryptor = encryptor;
|
||||
mApSsid = apSsid.getData();
|
||||
mApPassword = apPassword.getData();
|
||||
mApBssid = apBssid.getData();
|
||||
mIsCancelled = new AtomicBoolean(false);
|
||||
mSocketClient = new UDPSocketClient();
|
||||
mParameter = parameter;
|
||||
mSocketServer = new UDPSocketServer(mParameter.getPortListening(),
|
||||
mParameter.getWaitUdpTotalMillisecond(), context);
|
||||
mEsptouchResultList = new ArrayList<>();
|
||||
mBssidTaskSucCountMap = new HashMap<>();
|
||||
}
|
||||
|
||||
private void __putEsptouchResult(boolean isSuc, String bssid, InetAddress inetAddress) {
|
||||
synchronized (mEsptouchResultList) {
|
||||
// check whether the result receive enough UDP response
|
||||
boolean isTaskSucCountEnough = false;
|
||||
Integer count = mBssidTaskSucCountMap.get(bssid);
|
||||
if (count == null) {
|
||||
count = 0;
|
||||
}
|
||||
++count;
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "__putEsptouchResult(): count = " + count);
|
||||
}
|
||||
mBssidTaskSucCountMap.put(bssid, count);
|
||||
isTaskSucCountEnough = count >= mParameter
|
||||
.getThresholdSucBroadcastCount();
|
||||
if (!isTaskSucCountEnough) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "__putEsptouchResult(): count = " + count
|
||||
+ ", isn't enough");
|
||||
}
|
||||
return;
|
||||
}
|
||||
// check whether the result is in the mEsptouchResultList already
|
||||
boolean isExist = false;
|
||||
for (IEsptouchResult esptouchResultInList : mEsptouchResultList) {
|
||||
if (esptouchResultInList.getBssid().equals(bssid)) {
|
||||
isExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// only add the result who isn't in the mEsptouchResultList
|
||||
if (!isExist) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "__putEsptouchResult(): put one more result " +
|
||||
"bssid = " + bssid + " , address = " + inetAddress);
|
||||
}
|
||||
final IEsptouchResult esptouchResult = new EsptouchResult(isSuc,
|
||||
bssid, inetAddress);
|
||||
mEsptouchResultList.add(esptouchResult);
|
||||
if (mEsptouchListener != null) {
|
||||
mEsptouchListener.onEsptouchResultAdded(esptouchResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<IEsptouchResult> __getEsptouchResultList() {
|
||||
synchronized (mEsptouchResultList) {
|
||||
if (mEsptouchResultList.isEmpty()) {
|
||||
EsptouchResult esptouchResultFail = new EsptouchResult(false,
|
||||
null, null);
|
||||
esptouchResultFail.setIsCancelled(mIsCancelled.get());
|
||||
mEsptouchResultList.add(esptouchResultFail);
|
||||
}
|
||||
|
||||
return mEsptouchResultList;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void __interrupt() {
|
||||
if (!mIsInterrupt) {
|
||||
mIsInterrupt = true;
|
||||
mSocketClient.interrupt();
|
||||
mSocketServer.interrupt();
|
||||
// interrupt the current Thread which is used to wait for udp response
|
||||
if (mTask != null) {
|
||||
mTask.interrupt();
|
||||
mTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "interrupt()");
|
||||
}
|
||||
mIsCancelled.set(true);
|
||||
__interrupt();
|
||||
}
|
||||
|
||||
private void __listenAsyn(final int expectDataLen) {
|
||||
mTask = new Thread() {
|
||||
public void run() {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "__listenAsyn() start");
|
||||
}
|
||||
long startTimestamp = System.currentTimeMillis();
|
||||
// byte[] apSsidAndPassword = ByteUtil.getBytesByString(mApSsid
|
||||
// + mApPassword);
|
||||
byte expectOneByte = (byte) (mApSsid.length + mApPassword.length + 9);
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "expectOneByte: " + expectOneByte);
|
||||
}
|
||||
byte receiveOneByte = -1;
|
||||
byte[] receiveBytes = null;
|
||||
while (mEsptouchResultList.size() < mParameter
|
||||
.getExpectTaskResultCount() && !mIsInterrupt) {
|
||||
receiveBytes = mSocketServer
|
||||
.receiveSpecLenBytes(expectDataLen);
|
||||
if (receiveBytes != null) {
|
||||
receiveOneByte = receiveBytes[0];
|
||||
} else {
|
||||
receiveOneByte = -1;
|
||||
}
|
||||
if (receiveOneByte == expectOneByte) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "receive correct broadcast");
|
||||
}
|
||||
// change the socket's timeout
|
||||
long consume = System.currentTimeMillis()
|
||||
- startTimestamp;
|
||||
int timeout = (int) (mParameter
|
||||
.getWaitUdpTotalMillisecond() - consume);
|
||||
if (timeout < 0) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "esptouch timeout");
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "mSocketServer's new timeout is "
|
||||
+ timeout + " milliseconds");
|
||||
}
|
||||
mSocketServer.setSoTimeout(timeout);
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "receive correct broadcast");
|
||||
}
|
||||
if (receiveBytes != null) {
|
||||
String bssid = ByteUtil.parseBssid(
|
||||
receiveBytes,
|
||||
mParameter.getEsptouchResultOneLen(),
|
||||
mParameter.getEsptouchResultMacLen());
|
||||
InetAddress inetAddress = TouchNetUtil
|
||||
.parseInetAddr(
|
||||
receiveBytes,
|
||||
mParameter
|
||||
.getEsptouchResultOneLen()
|
||||
+ mParameter
|
||||
.getEsptouchResultMacLen(),
|
||||
mParameter
|
||||
.getEsptouchResultIpLen());
|
||||
__putEsptouchResult(true, bssid, inetAddress);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "receive rubbish message, just ignore");
|
||||
}
|
||||
}
|
||||
}
|
||||
mIsSuc = mEsptouchResultList.size() >= mParameter
|
||||
.getExpectTaskResultCount();
|
||||
__EsptouchTask.this.__interrupt();
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "__listenAsyn() finish");
|
||||
}
|
||||
}
|
||||
};
|
||||
mTask.start();
|
||||
}
|
||||
|
||||
private boolean __execute(IEsptouchGenerator generator) {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
long currentTime = startTime;
|
||||
long lastTime = currentTime - mParameter.getTimeoutTotalCodeMillisecond();
|
||||
|
||||
byte[][] gcBytes2 = generator.getGCBytes2();
|
||||
byte[][] dcBytes2 = generator.getDCBytes2();
|
||||
|
||||
int index = 0;
|
||||
while (!mIsInterrupt) {
|
||||
if (currentTime - lastTime >= mParameter.getTimeoutTotalCodeMillisecond()) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "send gc code ");
|
||||
}
|
||||
// send guide code
|
||||
while (!mIsInterrupt
|
||||
&& System.currentTimeMillis() - currentTime < mParameter
|
||||
.getTimeoutGuideCodeMillisecond()) {
|
||||
mSocketClient.sendData(gcBytes2,
|
||||
mParameter.getTargetHostname(),
|
||||
mParameter.getTargetPort(),
|
||||
mParameter.getIntervalGuideCodeMillisecond());
|
||||
// check whether the udp is send enough time
|
||||
if (System.currentTimeMillis() - startTime > mParameter.getWaitUdpSendingMillisecond()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastTime = currentTime;
|
||||
} else {
|
||||
mSocketClient.sendData(dcBytes2, index, ONE_DATA_LEN,
|
||||
mParameter.getTargetHostname(),
|
||||
mParameter.getTargetPort(),
|
||||
mParameter.getIntervalDataCodeMillisecond());
|
||||
index = (index + ONE_DATA_LEN) % dcBytes2.length;
|
||||
}
|
||||
currentTime = System.currentTimeMillis();
|
||||
// check whether the udp is send enough time
|
||||
if (currentTime - startTime > mParameter.getWaitUdpSendingMillisecond()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mIsSuc;
|
||||
}
|
||||
|
||||
private void __checkTaskValid() {
|
||||
// !!!NOTE: the esptouch task could be executed only once
|
||||
if (this.mIsExecuted) {
|
||||
throw new IllegalStateException(
|
||||
"the Esptouch task could be executed only once");
|
||||
}
|
||||
this.mIsExecuted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IEsptouchResult executeForResult() throws RuntimeException {
|
||||
return executeForResults(1).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.mIsCancelled.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IEsptouchResult> executeForResults(int expectTaskResultCount)
|
||||
throws RuntimeException {
|
||||
__checkTaskValid();
|
||||
|
||||
mParameter.setExpectTaskResultCount(expectTaskResultCount);
|
||||
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.d(TAG, "execute()");
|
||||
}
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
throw new RuntimeException(
|
||||
"Don't call the esptouch Task at Main(UI) thread directly.");
|
||||
}
|
||||
InetAddress localInetAddress = TouchNetUtil.getLocalInetAddress(mContext);
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "localInetAddress: " + localInetAddress);
|
||||
}
|
||||
// generator the esptouch byte[][] to be transformed, which will cost
|
||||
// some time(maybe a bit much)
|
||||
IEsptouchGenerator generator = new EsptouchGenerator(mApSsid, mApBssid,
|
||||
mApPassword, localInetAddress, mEncryptor);
|
||||
// listen the esptouch result asyn
|
||||
__listenAsyn(mParameter.getEsptouchResultTotalLen());
|
||||
boolean isSuc = false;
|
||||
for (int i = 0; i < mParameter.getTotalRepeatTime(); i++) {
|
||||
isSuc = __execute(generator);
|
||||
if (isSuc) {
|
||||
return __getEsptouchResultList();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mIsInterrupt) {
|
||||
// wait the udp response without sending udp broadcast
|
||||
try {
|
||||
Thread.sleep(mParameter.getWaitUdpReceivingMillisecond());
|
||||
} catch (InterruptedException e) {
|
||||
// receive the udp broadcast or the user interrupt the task
|
||||
if (this.mIsSuc) {
|
||||
return __getEsptouchResultList();
|
||||
} else {
|
||||
this.__interrupt();
|
||||
return __getEsptouchResultList();
|
||||
}
|
||||
}
|
||||
this.__interrupt();
|
||||
}
|
||||
|
||||
return __getEsptouchResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEsptouchListener(IEsptouchListener esptouchListener) {
|
||||
mEsptouchListener = esptouchListener;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.espressif.iot.esptouch.task;
|
||||
|
||||
import com.espressif.iot.esptouch.IEsptouchListener;
|
||||
import com.espressif.iot.esptouch.IEsptouchResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IEsptouchTask defined the task of esptouch should offer. INTERVAL here means
|
||||
* the milliseconds of interval of the step. REPEAT here means the repeat times
|
||||
* of the step.
|
||||
*
|
||||
* @author afunx
|
||||
*/
|
||||
public interface __IEsptouchTask {
|
||||
|
||||
/**
|
||||
* Turn on or off the log.
|
||||
*/
|
||||
static final boolean DEBUG = true;
|
||||
|
||||
/**
|
||||
* set the esptouch listener, when one device is connected to the Ap, it will be called back
|
||||
*
|
||||
* @param esptouchListener when one device is connected to the Ap, it will be called back
|
||||
*/
|
||||
void setEsptouchListener(IEsptouchListener esptouchListener);
|
||||
|
||||
/**
|
||||
* Interrupt the Esptouch Task when User tap back or close the Application.
|
||||
*/
|
||||
void interrupt();
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||
* be thrown Execute the Esptouch Task and return the result
|
||||
*
|
||||
* @return the IEsptouchResult
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
IEsptouchResult executeForResult() throws RuntimeException;
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread or RuntimeException will
|
||||
* be thrown Execute the Esptouch Task and return the result
|
||||
*
|
||||
* @param expectTaskResultCount the expect result count(if expectTaskResultCount <= 0,
|
||||
* expectTaskResultCount = Integer.MAX_VALUE)
|
||||
* @return the list of IEsptouchResult
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
List<IEsptouchResult> executeForResults(int expectTaskResultCount) throws RuntimeException;
|
||||
|
||||
boolean isCancelled();
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.espressif.iot.esptouch.udp;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.espressif.iot.esptouch.task.__IEsptouchTask;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* this class is used to help send UDP data according to length
|
||||
*
|
||||
* @author afunx
|
||||
*/
|
||||
public class UDPSocketClient {
|
||||
|
||||
private static final String TAG = "UDPSocketClient";
|
||||
private DatagramSocket mSocket;
|
||||
private volatile boolean mIsStop;
|
||||
private volatile boolean mIsClosed;
|
||||
|
||||
public UDPSocketClient() {
|
||||
try {
|
||||
this.mSocket = new DatagramSocket();
|
||||
this.mIsStop = false;
|
||||
this.mIsClosed = false;
|
||||
} catch (SocketException e) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.w(TAG, "SocketException");
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.i(TAG, "USPSocketClient is interrupt");
|
||||
}
|
||||
this.mIsStop = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the UDP socket
|
||||
*/
|
||||
public synchronized void close() {
|
||||
if (!this.mIsClosed) {
|
||||
this.mSocket.close();
|
||||
this.mIsClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send the data by UDP
|
||||
*
|
||||
* @param data the data to be sent
|
||||
* @param targetPort the port of target
|
||||
* @param interval the milliseconds to between each UDP sent
|
||||
*/
|
||||
public void sendData(byte[][] data, String targetHostName, int targetPort,
|
||||
long interval) {
|
||||
sendData(data, 0, data.length, targetHostName, targetPort, interval);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* send the data by UDP
|
||||
*
|
||||
* @param data the data to be sent
|
||||
* @param offset the offset which data to be sent
|
||||
* @param count the count of the data
|
||||
* @param targetPort the port of target
|
||||
* @param interval the milliseconds to between each UDP sent
|
||||
*/
|
||||
public void sendData(byte[][] data, int offset, int count,
|
||||
String targetHostName, int targetPort, long interval) {
|
||||
if ((data == null) || (data.length <= 0)) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.w(TAG, "sendData(): data == null or length <= 0");
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int i = offset; !mIsStop && i < offset + count; i++) {
|
||||
if (data[i].length == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
InetAddress targetInetAddress = InetAddress.getByName(targetHostName);
|
||||
DatagramPacket localDatagramPacket = new DatagramPacket(
|
||||
data[i], data[i].length, targetInetAddress, targetPort);
|
||||
this.mSocket.send(localDatagramPacket);
|
||||
} catch (UnknownHostException e) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.w(TAG, "sendData(): UnknownHostException");
|
||||
}
|
||||
e.printStackTrace();
|
||||
mIsStop = true;
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.w(TAG, "sendData(): IOException, but just ignore it");
|
||||
}
|
||||
// for the Ap will make some troubles when the phone send too many UDP packets,
|
||||
// but we don't expect the UDP packet received by others, so just ignore it
|
||||
}
|
||||
try {
|
||||
Thread.sleep(interval);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
if (__IEsptouchTask.DEBUG) {
|
||||
Log.w(TAG, "sendData is Interrupted");
|
||||
}
|
||||
mIsStop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mIsStop) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.espressif.iot.esptouch.udp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class UDPSocketServer {
|
||||
private static final String TAG = "UDPSocketServer";
|
||||
private DatagramSocket mServerSocket;
|
||||
private Context mContext;
|
||||
private WifiManager.MulticastLock mLock;
|
||||
private volatile boolean mIsClosed;
|
||||
|
||||
/**
|
||||
* Constructor of UDP Socket Server
|
||||
*
|
||||
* @param port the Socket Server port
|
||||
* @param socketTimeout the socket read timeout
|
||||
* @param context the context of the Application
|
||||
*/
|
||||
public UDPSocketServer(int port, int socketTimeout, Context context) {
|
||||
this.mContext = context;
|
||||
try {
|
||||
this.mServerSocket = new DatagramSocket(null);
|
||||
this.mServerSocket.setReuseAddress(true);
|
||||
this.mServerSocket.bind(new InetSocketAddress(port));
|
||||
this.mServerSocket.setSoTimeout(socketTimeout);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "IOException");
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.mIsClosed = false;
|
||||
WifiManager manager = (WifiManager) mContext.getApplicationContext()
|
||||
.getSystemService(Context.WIFI_SERVICE);
|
||||
mLock = manager.createMulticastLock("test wifi");
|
||||
Log.d(TAG, "mServerSocket is created, socket read timeout: "
|
||||
+ socketTimeout + ", port: " + port);
|
||||
}
|
||||
|
||||
private synchronized void acquireLock() {
|
||||
if (mLock != null && !mLock.isHeld()) {
|
||||
mLock.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void releaseLock() {
|
||||
if (mLock != null && mLock.isHeld()) {
|
||||
try {
|
||||
mLock.release();
|
||||
} catch (Throwable th) {
|
||||
// ignoring this exception, probably wakeLock was already released
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket timeout in milliseconds
|
||||
*
|
||||
* @param timeout the timeout in milliseconds or 0 for no timeout.
|
||||
* @return true whether the timeout is set suc
|
||||
*/
|
||||
public boolean setSoTimeout(int timeout) {
|
||||
try {
|
||||
this.mServerSocket.setSoTimeout(timeout);
|
||||
return true;
|
||||
} catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive one byte from the port and convert it into String
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte receiveOneByte() {
|
||||
Log.d(TAG, "receiveOneByte() entrance");
|
||||
try {
|
||||
acquireLock();
|
||||
DatagramPacket packet = new DatagramPacket(new byte[1], 1);
|
||||
mServerSocket.receive(packet);
|
||||
Log.d(TAG, "receive: " + (packet.getData()[0]));
|
||||
return packet.getData()[0];
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive specific length bytes from the port and convert it into String
|
||||
* 21,24,-2,52,-102,-93,-60
|
||||
* 15,18,fe,34,9a,a3,c4
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] receiveSpecLenBytes(int len) {
|
||||
Log.d(TAG, "receiveSpecLenBytes() entrance: len = " + len);
|
||||
try {
|
||||
acquireLock();
|
||||
DatagramPacket packet = new DatagramPacket(new byte[64], 64);
|
||||
mServerSocket.receive(packet);
|
||||
byte[] recDatas = Arrays.copyOf(packet.getData(), packet.getLength());
|
||||
Log.d(TAG, "received len : " + recDatas.length);
|
||||
for (int i = 0; i < recDatas.length; i++) {
|
||||
Log.w(TAG, "recDatas[" + i + "]:" + recDatas[i]);
|
||||
}
|
||||
Log.w(TAG, "receiveSpecLenBytes: " + new String(recDatas));
|
||||
if (recDatas.length != len) {
|
||||
Log.w(TAG,
|
||||
"received len is different from specific len, return null");
|
||||
return null;
|
||||
}
|
||||
return recDatas;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
Log.i(TAG, "USPSocketServer is interrupt");
|
||||
close();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
if (!this.mIsClosed) {
|
||||
Log.w(TAG, "mServerSocket is closed");
|
||||
mServerSocket.close();
|
||||
releaseLock();
|
||||
this.mIsClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
package com.espressif.iot.esptouch.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* In Java, it don't support unsigned int, so we use char to replace uint8.
|
||||
* The range of byte is [-128,127], and the range of char is [0,65535].
|
||||
* So the byte could used to store the uint8.
|
||||
* (We assume that the String could be mapped to assic)
|
||||
*
|
||||
* @author afunx
|
||||
*/
|
||||
public class ByteUtil {
|
||||
|
||||
public static final String ESPTOUCH_ENCODING_CHARSET = "UTF-8";
|
||||
|
||||
/**
|
||||
* Put String to byte[]
|
||||
*
|
||||
* @param destbytes the byte[] of dest
|
||||
* @param srcString the String of src
|
||||
* @param destOffset the offset of byte[]
|
||||
* @param srcOffset the offset of String
|
||||
* @param count the count of dest, and the count of src as well
|
||||
*/
|
||||
public static void putString2bytes(byte[] destbytes, String srcString,
|
||||
int destOffset, int srcOffset, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
destbytes[count + i] = srcString.getBytes()[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert uint8 into char( we treat char as uint8)
|
||||
*
|
||||
* @param uint8 the unit8 to be converted
|
||||
* @return the byte of the unint8
|
||||
*/
|
||||
public static byte convertUint8toByte(char uint8) {
|
||||
if (uint8 > Byte.MAX_VALUE - Byte.MIN_VALUE) {
|
||||
throw new RuntimeException("Out of Boundary");
|
||||
}
|
||||
return (byte) uint8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert char into uint8( we treat char as uint8 )
|
||||
*
|
||||
* @param b the byte to be converted
|
||||
* @return the char(uint8)
|
||||
*/
|
||||
public static char convertByte2Uint8(byte b) {
|
||||
// char will be promoted to int for char don't support & operator
|
||||
// & 0xff could make negatvie value to positive
|
||||
return (char) (b & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert byte[] into char[]( we treat char[] as uint8[])
|
||||
*
|
||||
* @param bytes the byte[] to be converted
|
||||
* @return the char[](uint8[])
|
||||
*/
|
||||
public static char[] convertBytes2Uint8s(byte[] bytes) {
|
||||
int len = bytes.length;
|
||||
char[] uint8s = new char[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint8s[i] = convertByte2Uint8(bytes[i]);
|
||||
}
|
||||
return uint8s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put byte[] into char[]( we treat char[] as uint8[])
|
||||
*
|
||||
* @param destUint8s the char[](uint8[]) array
|
||||
* @param srcBytes the byte[]
|
||||
* @param destOffset the offset of char[](uint8[])
|
||||
* @param srcOffset the offset of byte[]
|
||||
* @param count the count of dest, and the count of src as well
|
||||
*/
|
||||
public static void putbytes2Uint8s(char[] destUint8s, byte[] srcBytes,
|
||||
int destOffset, int srcOffset, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
destUint8s[destOffset + i] = convertByte2Uint8(srcBytes[srcOffset
|
||||
+ i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert byte to Hex String
|
||||
*
|
||||
* @param b the byte to be converted
|
||||
* @return the Hex String
|
||||
*/
|
||||
public static String convertByte2HexString(byte b) {
|
||||
char u8 = convertByte2Uint8(b);
|
||||
return Integer.toHexString(u8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert char(uint8) to Hex String
|
||||
*
|
||||
* @param u8 the char(uint8) to be converted
|
||||
* @return the Hex String
|
||||
*/
|
||||
public static String convertU8ToHexString(char u8) {
|
||||
return Integer.toHexString(u8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split uint8 to 2 bytes of high byte and low byte. e.g. 20 = 0x14 should
|
||||
* be split to [0x01,0x04] 0x01 is high byte and 0x04 is low byte
|
||||
*
|
||||
* @param uint8 the char(uint8)
|
||||
* @return the high and low bytes be split, byte[0] is high and byte[1] is
|
||||
* low
|
||||
*/
|
||||
public static byte[] splitUint8To2bytes(char uint8) {
|
||||
if (uint8 < 0 || uint8 > 0xff) {
|
||||
throw new RuntimeException("Out of Boundary");
|
||||
}
|
||||
String hexString = Integer.toHexString(uint8);
|
||||
byte low;
|
||||
byte high;
|
||||
if (hexString.length() > 1) {
|
||||
high = (byte) Integer.parseInt(hexString.substring(0, 1), 16);
|
||||
low = (byte) Integer.parseInt(hexString.substring(1, 2), 16);
|
||||
} else {
|
||||
high = 0;
|
||||
low = (byte) Integer.parseInt(hexString.substring(0, 1), 16);
|
||||
}
|
||||
byte[] result = new byte[]{high, low};
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine 2 bytes (high byte and low byte) to one whole byte
|
||||
*
|
||||
* @param high the high byte
|
||||
* @param low the low byte
|
||||
* @return the whole byte
|
||||
*/
|
||||
public static byte combine2bytesToOne(byte high, byte low) {
|
||||
if (high < 0 || high > 0xf || low < 0 || low > 0xf) {
|
||||
throw new RuntimeException("Out of Boundary");
|
||||
}
|
||||
return (byte) (high << 4 | low);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine 2 bytes (high byte and low byte) to
|
||||
*
|
||||
* @param high the high byte
|
||||
* @param low the low byte
|
||||
* @return the char(u8)
|
||||
*/
|
||||
public static char combine2bytesToU16(byte high, byte low) {
|
||||
char highU8 = convertByte2Uint8(high);
|
||||
char lowU8 = convertByte2Uint8(low);
|
||||
return (char) (highU8 << 8 | lowU8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the random byte to be sent
|
||||
*
|
||||
* @return the random byte
|
||||
*/
|
||||
private static byte randomByte() {
|
||||
return (byte) (127 - new Random().nextInt(256));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the random byte to be sent
|
||||
*
|
||||
* @param len the len presented by u8
|
||||
* @return the byte[] to be sent
|
||||
*/
|
||||
public static byte[] randomBytes(char len) {
|
||||
byte[] data = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[i] = randomByte();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte[] genSpecBytes(char len) {
|
||||
byte[] data = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[i] = '1';
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the random byte to be sent
|
||||
*
|
||||
* @param len the len presented by byte
|
||||
* @return the byte[] to be sent
|
||||
*/
|
||||
public static byte[] randomBytes(byte len) {
|
||||
char u8 = convertByte2Uint8(len);
|
||||
return randomBytes(u8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the specific byte to be sent
|
||||
*
|
||||
* @param len the len presented by byte
|
||||
* @return the byte[]
|
||||
*/
|
||||
public static byte[] genSpecBytes(byte len) {
|
||||
char u8 = convertByte2Uint8(len);
|
||||
return genSpecBytes(u8);
|
||||
}
|
||||
|
||||
public static String parseBssid(byte[] bssidBytes, int offset, int count) {
|
||||
byte[] bytes = new byte[count];
|
||||
System.arraycopy(bssidBytes, offset, bytes, 0, count);
|
||||
return parseBssid(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse "24,-2,52,-102,-93,-60" to "18,fe,34,9a,a3,c4"
|
||||
* parse the bssid from hex to String
|
||||
*
|
||||
* @param bssidBytes the hex bytes bssid, e.g. {24,-2,52,-102,-93,-60}
|
||||
* @return the String of bssid, e.g. 18fe349aa3c4
|
||||
*/
|
||||
public static String parseBssid(byte[] bssidBytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int k;
|
||||
String hexK;
|
||||
String str;
|
||||
for (byte bssidByte : bssidBytes) {
|
||||
k = 0xff & bssidByte;
|
||||
hexK = Integer.toHexString(k);
|
||||
str = ((k < 16) ? ("0" + hexK) : (hexK));
|
||||
System.out.println(str);
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string the string to be used
|
||||
* @return the byte[] of String according to {@link #ESPTOUCH_ENCODING_CHARSET}
|
||||
*/
|
||||
public static byte[] getBytesByString(String string) {
|
||||
try {
|
||||
return string.getBytes(ESPTOUCH_ENCODING_CHARSET);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalArgumentException("the charset is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test_splitUint8To2bytes() {
|
||||
// 20 = 0x14
|
||||
byte[] result = splitUint8To2bytes((char) 20);
|
||||
if (result[0] == 1 && result[1] == 4) {
|
||||
System.out.println("test_splitUint8To2bytes(): pass");
|
||||
} else {
|
||||
System.out.println("test_splitUint8To2bytes(): fail");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test_combine2bytesToOne() {
|
||||
byte high = 0x01;
|
||||
byte low = 0x04;
|
||||
if (combine2bytesToOne(high, low) == 20) {
|
||||
System.out.println("test_combine2bytesToOne(): pass");
|
||||
} else {
|
||||
System.out.println("test_combine2bytesToOne(): fail");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test_convertChar2Uint8() {
|
||||
byte b1 = 'a';
|
||||
// -128: 1000 0000 should be 128 in unsigned char
|
||||
// -1: 1111 1111 should be 255 in unsigned char
|
||||
byte b2 = (byte) -128;
|
||||
byte b3 = (byte) -1;
|
||||
if (convertByte2Uint8(b1) == 97 && convertByte2Uint8(b2) == 128
|
||||
&& convertByte2Uint8(b3) == 255) {
|
||||
System.out.println("test_convertChar2Uint8(): pass");
|
||||
} else {
|
||||
System.out.println("test_convertChar2Uint8(): fail");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test_convertUint8toByte() {
|
||||
char c1 = 'a';
|
||||
// 128: 1000 0000 should be -128 in byte
|
||||
// 255: 1111 1111 should be -1 in byte
|
||||
char c2 = 128;
|
||||
char c3 = 255;
|
||||
if (convertUint8toByte(c1) == 97 && convertUint8toByte(c2) == -128
|
||||
&& convertUint8toByte(c3) == -1) {
|
||||
System.out.println("test_convertUint8toByte(): pass");
|
||||
} else {
|
||||
System.out.println("test_convertUint8toByte(): fail");
|
||||
}
|
||||
}
|
||||
|
||||
private static void test_parseBssid() {
|
||||
byte b[] = {15, -2, 52, -102, -93, -60};
|
||||
if (parseBssid(b).equals("0ffe349aa3c4")) {
|
||||
System.out.println("test_parseBssid(): pass");
|
||||
} else {
|
||||
System.out.println("test_parseBssid(): fail");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
test_convertUint8toByte();
|
||||
test_convertChar2Uint8();
|
||||
test_splitUint8To2bytes();
|
||||
test_combine2bytesToOne();
|
||||
test_parseBssid();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.espressif.iot.esptouch.util;
|
||||
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
public class CRC8 implements Checksum {
|
||||
|
||||
private static final short[] crcTable = new short[256];
|
||||
private static final short CRC_POLYNOM = 0x8c;
|
||||
private static final short CRC_INITIAL = 0x00;
|
||||
|
||||
static {
|
||||
for (int dividend = 0; dividend < 256; dividend++) {
|
||||
int remainder = dividend;// << 8;
|
||||
for (int bit = 0; bit < 8; ++bit)
|
||||
if ((remainder & 0x01) != 0)
|
||||
remainder = (remainder >>> 1) ^ CRC_POLYNOM;
|
||||
else
|
||||
remainder >>>= 1;
|
||||
crcTable[dividend] = (short) remainder;
|
||||
}
|
||||
}
|
||||
|
||||
private final short init;
|
||||
private short value;
|
||||
|
||||
public CRC8() {
|
||||
this.value = this.init = CRC_INITIAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] buffer, int offset, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
int data = buffer[offset + i] ^ value;
|
||||
value = (short) (crcTable[data & 0xff] ^ (value << 8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current checksum with the specified array of bytes.
|
||||
* Equivalent to calling <code>update(buffer, 0, buffer.length)</code>.
|
||||
*
|
||||
* @param buffer the byte array to update the checksum with
|
||||
*/
|
||||
public void update(byte[] buffer) {
|
||||
update(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(int b) {
|
||||
update(new byte[]{(byte) b}, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValue() {
|
||||
return value & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
value = init;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.espressif.iot.esptouch.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class TouchNetUtil {
|
||||
|
||||
/**
|
||||
* get the local ip address by Android System
|
||||
*
|
||||
* @param context the context
|
||||
* @return the local ip addr allocated by Ap
|
||||
*/
|
||||
public static InetAddress getLocalInetAddress(Context context) {
|
||||
WifiManager wm = (WifiManager) context.getApplicationContext()
|
||||
.getSystemService(Context.WIFI_SERVICE);
|
||||
assert wm != null;
|
||||
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||
int localAddrInt = wifiInfo.getIpAddress();
|
||||
String localAddrStr = __formatString(localAddrInt);
|
||||
InetAddress localInetAddr = null;
|
||||
try {
|
||||
localInetAddr = InetAddress.getByName(localAddrStr);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return localInetAddr;
|
||||
}
|
||||
|
||||
private static String __formatString(int value) {
|
||||
StringBuilder strValue = new StringBuilder();
|
||||
byte[] ary = __intToByteArray(value);
|
||||
for (int i = ary.length - 1; i >= 0; i--) {
|
||||
strValue.append(ary[i] & 0xFF);
|
||||
if (i > 0) {
|
||||
strValue.append(".");
|
||||
}
|
||||
}
|
||||
return strValue.toString();
|
||||
}
|
||||
|
||||
private static byte[] __intToByteArray(int value) {
|
||||
byte[] b = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int offset = (b.length - 1 - i) * 8;
|
||||
b[i] = (byte) ((value >>> offset) & 0xFF);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse InetAddress
|
||||
*
|
||||
* @param inetAddrBytes
|
||||
* @return
|
||||
*/
|
||||
public static InetAddress parseInetAddr(byte[] inetAddrBytes, int offset,
|
||||
int count) {
|
||||
InetAddress inetAddress = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append((inetAddrBytes[offset + i] & 0xff));
|
||||
if (i != count - 1) {
|
||||
sb.append('.');
|
||||
}
|
||||
}
|
||||
try {
|
||||
inetAddress = InetAddress.getByName(sb.toString());
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return inetAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse bssid
|
||||
*
|
||||
* @param bssid the bssid like aa:bb:cc:dd:ee:ff
|
||||
* @return byte converted from bssid
|
||||
*/
|
||||
public static byte[] parseBssid2bytes(String bssid) {
|
||||
String[] bssidSplits = bssid.split(":");
|
||||
byte[] result = new byte[bssidSplits.length];
|
||||
for (int i = 0; i < bssidSplits.length; i++) {
|
||||
result[i] = (byte) Integer.parseInt(bssidSplits[i], 16);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] getOriginalSsidBytes(WifiInfo info) {
|
||||
try {
|
||||
Method method = info.getClass().getMethod("getWifiSsid");
|
||||
method.setAccessible(true);
|
||||
Object wifiSsid = method.invoke(info);
|
||||
if (wifiSsid == null) {
|
||||
return null;
|
||||
}
|
||||
method = wifiSsid.getClass().getMethod("getOctets");
|
||||
method.setAccessible(true);
|
||||
return (byte[]) method.invoke(wifiSsid);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user