Job transfer. It stopped for a while. Following on from our last article we learned how to customize a set of messages, today we continue parsing and assembling messages. We talked earlier about the Internet of Things communication and actually whatever medium we use as communication medium is essentially bytes. So ONCE again I have changed the content of this chapter so that we do not cover how to write the two blocking IO sockets: Socket and ServerSocket. That doesn’t mean much.

In the last section, a reader said he needed to know how to unpack the message.

chapter

  • Android communicating with iot Devices – A concept starter
  • Android communicating with iot devices – The essence of data transfer
  • Android and iot device communication – Network model layering
  • Android and Internet of Things device communication -UDP protocol principle
  • Communication between Android and iot devices -TCP protocol principle
  • Communication between Android and iot devices – based on TCP/IP custom messages
  • Android communicating with iot devices – What is byte order
  • Communication between Android and iot devices – byte packet assembly and parsing
  • Android communicates with iot devices – use UDP broadcast to do device lookup
  • Android and Internet of Things device communication – remote control Android client
  • Android communicates with iot devices -Android makes small servers
  • Android and Internet of Things device communication – debugging tips
  • Android communicates with iot devices – parallel serial and queue
  • Android communicating with iot devices – Data security
  • Android communicates with iot devices – heartbeat
  • Android and Internet of Things device communication – network IO model

directory

  • Assembled messages
  • Parsing a message
  • conclusion

Assembled messages

How on earth do we convert the following structure into bytes?

Protocol:

Converted bytes:

0x00 0x00 0x00 0x11 | 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 | 0x21 | 0x01 |0x57 0x9D

First we need to define an object as a structure. (See the previous section for those of you who don’t know why.)

public class AirCondBaseStructure {
    int len; / / the length
    byte sn[]; / / serial number
    byte code; / / function code
    byte data[]; // Pass through data
    byte crc[]; / / check
}

Copy the code

For this structure, we write another enumeration:

    public enum CodeEnum {
        POWER((byte) 0x21),/ / switch
        MODE((byte) 0x22),/ / mode
        TEMPERATURE((byte) 0x23);/ / temperature
        byte code;
        CodeEnum(bytei) { code = i; }}Copy the code

This enumerator corresponds exactly to the function in the comparison table.

So let me write the constructor.

  public AirCondBaseStructure(String sn, AirCondBaseStructure.CodeEnum code, byte[] data){
        this.sn = sn.getBytes(); / / serial number
        this.code = code.code;
        this.data = data;
        this.len=computeLen();// Get the length
        this.crc =computeCrc();/ / check
    }

Copy the code

Here the constructor takes only three arguments:

  • The serial number
  • function
  • Passthrough content

You can see that there are actually lengths and CRC checks. According to computeLen (); And computeCrc (); To automate the calculation.

ComputeLen method:

    /** * Count length *@return* /
    private int computeLen(a) {
        return sn.length + 1/* Function code length */ + data.length + 2/* Checksum */;
    }

Copy the code

The length here is fixed field plus variable length.

ComputeCrc method:

/** * computes CRC * @return
     */
    private byte[] computeCrc() {
        byte[] crc=new byte[2];
        byte[] datas=null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
            dataOutputStream.writeInt(len);
            dataOutputStream.write(sn);
            dataOutputStream.writeByte(code);
            dataOutputStream.write(data);
            dataOutputStream.flush();
             datas = byteArrayOutputStream.toByteArray();
            dataOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        CRC16M crc16 = new CRC16M();
        crc16.update(datas, datas.length);
        int ri = crc16.getValue();
        crc[0] = (byte) ((0xff00 & ri) >> 8);
        crc[1] = (byte) (0xff & ri);
        return crc;
    }
    
Copy the code

CRC check is used in CRC16 / Modbus standard. The full code is posted below.

Finally, the packets are grouped into bytes.

/** * serialize * @return
     */
    public byte[] toBytes(){
        byte[] datas=null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
            dataOutputStream.writeInt(len);
            dataOutputStream.write(sn);
            dataOutputStream.writeByte(code);
            dataOutputStream.write(data);
            dataOutputStream.write(crc);
            dataOutputStream.flush();
            datas = byteArrayOutputStream.toByteArray();
            dataOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return datas;
    }
Copy the code

Here we use ByteArrayOutputStream+DataOutputStream to write corresponding fields in order to ensure protocol consistency.

Finally, let’s look at the results:

  public static void main(String[] args) {
        String sn="1234567890123";
        AirCondBaseStructure powerOpen =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.POWER, new byte[] {0x01});
        System.out.println("Air conditioner On message:"+hex2Str(powerOpen.toBytes()));

        AirCondBaseStructure powerCloce =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.POWER, new byte[] {(byte)0x00});
        System.out.println("Air conditioner Shutdown message:"+hex2Str(powerCloce.toBytes()));

        AirCondBaseStructure modeAuto =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.MODE, new byte[] {(byte)0x03});
        System.out.println("Air Conditioner Automatic Message:"+hex2Str(modeAuto.toBytes()));

        AirCondBaseStructure modeDeh =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.MODE, new byte[] {(byte)0x05});
        System.out.println("Air conditioner dehumidification packet:"+hex2Str(modeDeh.toBytes()));


        AirCondBaseStructure temperature =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.TEMPERATURE,  new byte[] {(byte)0x00, (byte) 0x19});
        System.out.println("Air conditioner 25 degree message:"+hex2Str(temperature.toBytes()));
    }

Copy the code

For the upper layer, the way of assembly is relatively simple, just need to set the corresponding enumeration function in, bring the data, the rest of the serialization and verification are realized internally.

Here we simulate five groups of packets, and the output results are as follows.

Console output:

Air Conditioner On message: 0x00 0x00 0x00 0x11 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x21 0x01 0x57 0x9D Air Conditioner Off Message: 0x00 0x00 0x11 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x21 0x00 0x96 0x5D 0x00 0x00 0x11 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x22 0x03 0xD6 0xAC Air Conditioner Dehumidification Packet: 0x00 0x00 0x11 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x22 0x05 0x56 0xAE 0x00 0x00 0x00 0x12 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30 0x31 0x32 0x33 0x23 0x00 0x19 0x4D 0x94Copy the code

Let’s take a closer look at their changes.

At this point we have assembled the message and converted it into a byte array.

Maybe we’re thinking, well, how do we send it? We saw in the first video that it doesn’t really matter what’s being transmitted. They all end up in byte or binary form. So we’ve all converted, and the rest is pretty straightforward. Is to feed the data in, feed to TCP/IP, UDP, Bluetooth, infrared, radio, acoustic, electromagnetic…. It depends on the situation.

Complete code:

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/** * Created by Bolex on 2018/6/17. */
public class AirCondBaseStructure {
    int len; / / the length
    byte sn[]; / / serial number
    byte code; / / function code
    byte data[]; // Pass through data
    byte crc[]; / / check


    public AirCondBaseStructure(String sn, AirCondBaseStructure.CodeEnum code, byte[] data){
        this.sn = sn.getBytes(); / / serial number
        this.code = code.code;
        this.data = data;
        this.len=computeLen();// Get the length
        this.crc =computeCrc();/ / check
    }


    public enum CodeEnum {
        POWER((byte) 0x21),/ / switch
        MODE((byte) 0x22),/ / mode
        TEMPERATURE((byte) 0x23);/ / temperature
        byte code;
        CodeEnum(bytei) { code = i; }}/** * Count length *@return* /
    private int computeLen(a) {
        return sn.length + 1/* Function code length */ + data.length + 2/* Checksum */;
    }

    /** * Computes CRC *@return* /
    private byte[] computeCrc() {
        byte[] crc=new byte[2];
        byte[] datas=null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
            dataOutputStream.writeInt(len);
            dataOutputStream.write(sn);
            dataOutputStream.writeByte(code);
            dataOutputStream.write(data);
            dataOutputStream.flush();
             datas = byteArrayOutputStream.toByteArray();
            dataOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        CRC16M crc16 = new CRC16M();
        crc16.update(datas, datas.length);
        int ri = crc16.getValue();
        crc[0] = (byte) ((0xff00 & ri) >> 8);
        crc[1] = (byte) (0xff & ri);
        return crc;
    }

    /** * serialize *@return* /
    public byte[] toBytes(){
        byte[] datas=null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
            dataOutputStream.writeInt(len);
            dataOutputStream.write(sn);
            dataOutputStream.writeByte(code);
            dataOutputStream.write(data);
            dataOutputStream.write(crc);
            dataOutputStream.flush();
            datas = byteArrayOutputStream.toByteArray();
            dataOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        returndatas; }}Copy the code

public class CRC16M {

	byte uchCRCHi = (byte) 0xFF;
	byte uchCRCLo = (byte) 0xFF;
	private static byte[] auchCRCHi = { 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
			(byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
			(byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
			(byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
			(byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
			(byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
			(byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
			(byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
			(byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
			(byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
			(byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
			(byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
			(byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
			(byte) 0xC1, (byte) 0x81, (byte) 0x40 };

	private static byte[] auchCRCLo = { (byte) 0x00, (byte) 0xC0, (byte) 0xC1,
			(byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2,
			(byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05,
			(byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C,
			(byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE,
			(byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B,
			(byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8, (byte) 0xD8,
			(byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB,
			(byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF,
			(byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
			(byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7,
			(byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12,
			(byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0,
			(byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1,
			(byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36,
			(byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35,
			(byte) 0x34, (byte) 0xF4, (byte) 0x3C, (byte) 0xFC, (byte) 0xFD,
			(byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE,
			(byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39,
			(byte) 0xF9, (byte) 0xF8, (byte) 0x38, (byte) 0x28, (byte) 0xE8,
			(byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A,
			(byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF,
			(byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4,
			(byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7,
			(byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3,
			(byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
			(byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63,
			(byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6,
			(byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64,
			(byte) 0xA4, (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D,
			(byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA,
			(byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9,
			(byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9,
			(byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA,
			(byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D,
			(byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74,
			(byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6,
			(byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73,
			(byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50,
			(byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53,
			(byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57,
			(byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
			(byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F,
			(byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A,
			(byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58,
			(byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89,
			(byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E,
			(byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D,
			(byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84, (byte) 0x85,
			(byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86,
			(byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41,
			(byte) 0x81, (byte) 0x80, (byte) 0x40 };

	public int value;

	public CRC16M() {
		value = 0;

	}

	public void update(byte[] puchMsg, int usDataLen) {
		int uIndex;
		for (int i = 0; i < usDataLen; i++) {
			uIndex = (uchCRCHi ^ puchMsg[i]) & 0xff;

			uchCRCHi = (byte) (uchCRCLo ^ auchCRCHi[uIndex]);
			uchCRCLo = auchCRCLo[uIndex];
		}
		value = ((((int) uchCRCHi) << 8 | (((int) uchCRCLo) & 0xff))) & 0xffff;

		return;
	}

	public void reset() {
		value = 0;
		uchCRCHi = (byte) 0xff;
		uchCRCLo = (byte) 0xff;
	}

	public int getValue() {
		return value;
	}

	private static byte uniteBytes(byte src0, byte src1) {
		byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
				.byteValue();
		_b0 = (byte) (_b0 << 4);
		byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
				.byteValue();
		byte ret = (byte) (_b0 ^ _b1);
		return ret;
	}

	private static byte[] HexString2Buf(String src) {
		int len = src.length();
		byte[] ret = new byte[len / 2+2];
		byte[] tmp = src.getBytes();
		for (int i = 0; i < len; i += 2) {
			ret[i / 2] = uniteBytes(tmp[i], tmp[i + 1]);
		}
		return ret;
	}

	public static byte[] getSendBuf(String toSend){
		byte[] bb = HexString2Buf(toSend);
		CRC16M crc16 = new CRC16M();
		crc16.update(bb, bb.length-2);
		int ri = crc16.getValue();
		bb[bb.length-1]=(byte) (0xff & ri);
		bb[bb.length-2]=(byte) ((0xff00 & ri) >> 8);
		return bb;
	}
	public static boolean checkBuf(byte[] bb){
		CRC16M crc16 = new CRC16M();
		crc16.update(bb, bb.length-2);
		int ri = crc16.getValue();
		if(bb[bb.length-1]==(byte)(ri&0xff) 
				&& bb[bb.length-2]==(byte) ((0xff00 & ri) >> 8))
			return true;
		return false; }}Copy the code
import java.io.*;
import java.nio.ByteBuffer;

/**
 * Created by Bolex on 2018/6/17.
 */
public class AirCondMain {

    public static void main(String[] args) {
        String sn="1234567890123";
        AirCondBaseStructure powerOpen =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.POWER, new byte[]{0x01});
        System.out.println("Air conditioner On message:"+hex2Str(powerOpen.toBytes()));

        AirCondBaseStructure powerCloce =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.POWER, new byte[]{(byte)0x00});
        System.out.println("Air conditioner Shutdown message:"+hex2Str(powerCloce.toBytes()));

        AirCondBaseStructure modeAuto =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.MODE, new byte[]{(byte)0x03});
        System.out.println("Air Conditioner Automatic Message:"+hex2Str(modeAuto.toBytes()));

        AirCondBaseStructure modeDeh =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.MODE, new byte[]{(byte)0x05});
        System.out.println("Air conditioner dehumidification packet:"+hex2Str(modeDeh.toBytes()));


        AirCondBaseStructure temperature =new AirCondBaseStructure(sn, AirCondBaseStructure.CodeEnum.TEMPERATURE,  new byte[]{(byte)0x00, (byte) 0x19});
        System.out.println("Air conditioner 25 degree message:"+hex2Str(temperature.toBytes()));
    }

     static String hex2Str(byte[] raw){
        String HEXES = "0123456789ABCDEF";
        if ( raw == null ) {
            return null;
        }
        final StringBuilder hex = new StringBuilder( 2 * raw.length );
        for ( final byte b : raw ) {
            hex.append("0x");
            hex.append(HEXES.charAt((b & 0xF0) >> 4))
                    .append(HEXES.charAt((b & 0x0F)));
            hex.append("");
        }
        returnhex.toString(); }}Copy the code

Parsing a message

The process of parsing a message is to convert the byte array back into an object, also known as deserialization.

Here because it is the article demo (lazy), unlike the previous assembly of the packet to do the packaging.

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;

/** * Created by Bolex on 2018/6/17. */
public class AirCondAnalyzeMain {

    public static void main(String[] args) throws IOException {
        byte[] powerOpenBytes = hexStringToBytes("00000011313233343536373839303132332101579D");
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(powerOpenBytes);
        DataInputStream dis = new DataInputStream(byteArrayInputStream);
        int len = dis.readInt(); / / at length
        byte[] sn = new byte[13]; / / serial number
        byte[] code = new byte[1]; / / function code
        byte[] crc = new byte[2]; / / check
        byte[] data = new byte[len - sn.length - code.length - crc.length];
        dis.read(sn);
        dis.read(code);
        dis.read(data);
        dis.read(crc);
        System.out.println("Message length:" + len);
        System.out.println(Sn: "" + new String(sn));
        System.out.println("Function code:" + hex2Str(code));
        System.out.println("Data:" + hex2Str(data));
        System.out.println("Check:" + hex2Str(crc));
         dis.close();
    }

    private static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    /**
     * Convert char to byte
     *
     * @param c char
     * @return byte
     */
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    private static String hex2Str(byte[] raw) {
        String HEXES = "0123456789ABCDEF";
        if (raw == null) {
            return null;
        }
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append("0x");
            hex.append(HEXES.charAt((b & 0xF0) > >4))
                    .append(HEXES.charAt((b & 0x0F)));
            hex.append("");
        }
        returnhex.toString(); }}Copy the code

We see the main method. It is mainly to parse a group of power on packets. There’s nothing there, just a DataInputStream to read. But the length is variable, so we need to read the length first, and then read the other fields backwards based on the length.

And then the console will output

Packet Length: 17 SN: 1234567890123 Function code: 0x21 Data: 0x01 Parity: 0x57 0x9DCopy the code

The actual business situation is more complex than this, so it’s best to do some abstraction and encapsulation. Don’t do the flow programming I wrote about in my article. Because if you don’t encapsulate the back maintenance will look painful. There’s also a lot of duplicate code. You should not parse each set of packets by hand repeatedly.


conclusion

Assembling and parsing byte packets is a very basic capability. There are already DataInput sockets in Java that are easy to parse. In the process of debugging and development, we try our best to do the log, see the meaning, and it is best to convert the HEX format into a string to view. Generally out of the first two touch protocol prone to cause a bug.

You might wonder why you don’t just use JSON to do pass-through. This has been discussed a long time ago, and it is important to try to avoid too much transparent content. Using byte bits for fields increases propagation efficiency and stability. After this article, you can also try to read headers in MP3, JPG, APK, etc., in bytes. It’s also a good way to practice.