package com.jfinal.weixin.iot.protocol; import java.nio.ByteBuffer; import java.nio.charset.Charset; import com.jfinal.log.Log; import com.jfinal.weixin.sdk.utils.Charsets; /** * 蓝牙灯泡自定义协议结构解析 */ public class BlueLight { private static final Log log = Log.getLog(BlueLight.class); /** *
* 包 由包头+包体组成,包头如:
* struct BlueDemoHead
* {
* unsigned char m_magicCode[2];
* unsigned short m_version;
* unsigned short m_totalLength;
* unsigned short m_cmdId;
* unsigned short m_seq;
* unsigned short m_errorCode;
* };
* 包体为字符串 utf-8编码
*
*/
public static class Head {
public char magic;// 固定为 0xFECF
public short version;
public short length;// 包头+包体总长度
public short cmdId;// 命令字
public short seq;// 序列号 resp时为参数 push时为0
public short errorCode;// 错误代码 0表示成功
@Override
public String toString() {
return "Head [magic=" + magic + ", version=" + version
+ ", length=" + length + ", cmdId=" + cmdId + ", seq="
+ seq + ", errorCode=" + errorCode + "]";
}
}
public Head head;
public String body;
/**
* 构造类型
*
* @param cmdId
* 命令
* @param respText
* 包体内容
* @param seq
* 序列号 响应包同传入参数值;push包为0
* @return {BlueLight}
*/
public static BlueLight build(CmdId cmdId, String respText, short seq) {
BlueLight light = new BlueLight();
light.body = respText;
light.head = new Head();
byte[] b = respText == null ? new byte[0] : respText.getBytes(CHARSET);
light.head.magic = MAGIC;
light.head.version = 1;
light.head.length = (short) (HEAD_LENGTH + b.length);
light.head.cmdId = cmdId.value();
light.head.seq = seq;
light.head.errorCode = 0;
return light;
}
/**
* 转为二进制
* @return {byte[]}
*/
public byte[] toBytes() {
byte[] b = body == null ? new byte[0] : body.getBytes(CHARSET);
ByteBuffer buf = ByteBuffer.allocate(head.length);
buf.putChar(head.magic);
buf.putShort(head.version);
buf.putShort(head.length);
buf.putShort(head.cmdId);
buf.putShort(head.seq);
buf.putShort(head.errorCode);
buf.put(b);
buf.flip();
return buf.array();
}
/**
* 二进制转对象
* @param reqBytes 二进制
* @return {BlueLight}
*/
public static BlueLight parse(byte[] reqBytes) {
ByteBuffer buf = ByteBuffer.wrap(reqBytes);
char magic = buf.getChar();
// magic校验
if (magic != MAGIC) {
log.error("magic not valid " + magic);
}
Head h = new Head();
h.magic = MAGIC;
h.version = buf.getShort();
h.length = buf.getShort();
h.cmdId = buf.getShort();
h.seq = buf.getShort();
h.errorCode = buf.getShort();
int bodyLen = h.length - HEAD_LENGTH;
byte[] bodyBytes = new byte[bodyLen];
buf.get(bodyBytes);
String b = new String(bodyBytes, CHARSET);
BlueLight light = new BlueLight();
light.head = h;
light.body = b;
return light;
}
// magic code
private static final char MAGIC = 0xFECF;
// 包头长度
private static final short HEAD_LENGTH = 12;
private static Charset CHARSET = Charsets.UTF_8;
/**
* 命令
*/
public static enum CmdId {
/**
* 请求
*/
SEND_TEXT_REQ(0x01),
/**
* 响应
*/
SEND_TEXT_RESP(0x1001),
/**
* 点灯
*/
OPEN_LIGHT_PUSH(0x2001),
/**
* 灭灯
*/
CLOSE_LIGHT_PUSH(0x2002);
private short value;
private CmdId(int v) {
this.value = (short) v;
}
public short value() {
return value;
}
}
@Override
public String toString() {
return "BlueLight [body=" + body + ", head=" + head + "]";
}
static char[] bytesToChars(byte[] bytes) {
char[] cs = new char[bytes.length];
for (int i = 0; i < bytes.length; i++) {
cs[i] = (char) bytes[i];
}
return cs;
}
static byte[] charsToBytes(char[] chars) {
byte[] bs = new byte[chars.length];
for (int i = 0; i < chars.length; i++) {
bs[i] = (byte) chars[i];
}
return bs;
}
protected static String bytesToHex(byte[] b) {
char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
StringBuilder buf = new StringBuilder();
for (int j = 0; j < b.length; j++) {
buf.append(hexDigit[(b[j] >> 4) & 0x0f]);
buf.append(hexDigit[b[j] & 0x0f]);
}
return buf.toString();
}
}