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; 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 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 isSsidHiden whether the Ap's ssid is hidden */ public DatumCode(byte[] apSsid, byte[] apBssid, byte[] apPassword, InetAddress ipAddress, boolean isSsidHiden) { // 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; // hostname parse String ipAddrStrs[] = ipAddress.getHostAddress().split("\\."); int ipLen = ipAddrStrs.length; char ipAddrChars[] = new char[ipLen]; // only support ipv4 at the moment for (int i = 0; i < ipLen; ++i) { ipAddrChars[i] = (char) Integer.parseInt(ipAddrStrs[i]); } char _totalLen = (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen); char totalLen = isSsidHiden ? (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen + apSsidLen) : (char) (EXTRA_HEAD_LEN + ipLen + apPwdLen); // 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) { mDataCodes.add(new DataCode(ipAddrChars[i], i + EXTRA_HEAD_LEN)); totalXor ^= ipAddrChars[i]; } byte[] apPwdBytes = apPassword; char[] apPwdChars = new char[apPwdBytes.length]; for (int i = 0; i < apPwdBytes.length; i++) { apPwdChars[i] = ByteUtil.convertByte2Uint8(apPwdBytes[i]); } for (int i = 0; i < apPwdChars.length; i++) { mDataCodes.add(new DataCode(apPwdChars[i], i + EXTRA_HEAD_LEN + ipLen)); totalXor ^= apPwdChars[i]; } byte[] apSsidBytes = apSsid; char[] apSsidChars = new char[apSsidBytes.length]; // totalXor will xor apSsidChars no matter whether the ssid is hidden for (int i = 0; i < apSsidBytes.length; i++) { apSsidChars[i] = ByteUtil.convertByte2Uint8(apSsidBytes[i]); totalXor ^= apSsidChars[i]; } if (isSsidHiden) { for (int i = 0; i < apSsidChars.length; i++) { mDataCodes.add(new DataCode(apSsidChars[i], 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; } }