赞
踩
#对接科大讯飞的魔飞装置有一段时间了,现在来总结一下遇到的一些问题以及踩过的一些坑:
1.参考科大讯飞给的串口开发文档
https://doc.iflyos.cn/aiui/sdk/smart_doc/serial_port_sdk.html#串口协议实现参考
里面有科大讯飞语音装置串口线具体连接方式,并且要注意的一点是此语音装置串口是TTL的并非是485和232,这点要注意一下,
当时就因为这个原因一度以为是自己串口读写代码有问题。
2.协议解析
根据讯飞串口开发的协议来看,在android端这边来实现的话是会提供一个UARTKitCtrDemo是上位机(Android平台)集成AIUI串口协议的sdk开发包的,奈何找了在官网找了很久都没有找到相关的开发包,只能自己解析串口协议,读取串口的数据以及向串口发送数据这一部分我就不做过多的讲解了,网上有很多只要设置了对的波特率,以及你接线的正确串口节点就可以,现在就android端实现提供部分协议解析:
1.根据协议文档,我们首先要区分的是握手消息,确认消息,以及控制消息。
握手消息和确认消息基本是固定的,文档有明确说明,在接收到握手消息的时候,要给装置回复确认消息,以下就是握手确认消息构建:
/** * 构造握手确认消息 * @param b 握手数据 * @param size 数据长度 */ public boolean bulidRevMessage(byte[] b,int size){ boolean isRev = false; byte[] rev = new byte[12]; if (size == 12){ if ((b[0] & 0xFF) == 165 && (b[1] & 0xff) == 1 && (b[2] & 0xff) == 1){ isRev = true; for (int i = 0;i < size-1;i++){ if (i == 2){ rev[i] = (byte) 0xff; }else { rev[i] = b[i]; } } short messageid = IntegerUtils.getShort(b, 5); messageId = messageid; byte checkSum = (byte) LockerSerialportUtil.check(rev, 12); rev[11] = checkSum; sendParams(rev); } } return isRev; }
用上面方面来判断是否是握手消息,如果是握手消息,就要发送握手确认消息,不然语音装置会一直给你发送握手消息。
2.下面就是重点,非握手消息的拼接部分代码:
/** * 拼接串口消息 * @param bytes * @param size */ public void analysisMessage(byte[] bytes,int size){ if (size > 2){ if ((bytes[0] & 0xFF) == 165 && (bytes[1] & 0xff) == 1 ){ if (size>7){ if ((bytes[2] & 0xff) == 255){ return; } message = new AIUIMessage(); message.setHead(bytes[0]); message.setmId(bytes[1]); message.setmType(bytes[2]); short messLen = IntegerUtils.getShort(bytes, 3); short messageid = IntegerUtils.getShort(bytes, 5); message.setmMessageLen(messLen); message.setmMessageId(messageid); messageId = messageid; bulidRevMessage(message); int p = messLen + 3 + 2 + 2 + 1; if (size == p){ byte[] body = Arrays.copyOfRange(bytes, 7, messLen+7); message.setmBody(body); }else { byte[] body = Arrays.copyOfRange(bytes, 7, size); message.setmBody(body); } }else { Log.d(TAG, "analysisMessage: 过滤消息"); } }else { if (message != null && message.getmMessageLen() > message.getmBody().length){ // Log.d(TAG, "analysisMessage: "+message.getmMessageLen()+"__"+ message.getmBody().length); message.setmBody(getBody(bytes,size)); } } }else if (message != null){ if (message.getmMessageLen() > message.getmBody().length){ message.setmBody(getBody(bytes,size)); } } } private byte[] getBody(byte[] bytes,int size){ byte[] bytes1 = message.getmBody(); byte[] bytes2; short messageLen = message.getmMessageLen(); int bodyLen = message.getmBody().length; if (size> (messageLen-bodyLen+1)){ bytes2 = Arrays.copyOfRange(bytes, 0, messageLen-bodyLen); }else { bytes2 = Arrays.copyOfRange(bytes, 0, size); } byte[] bytes3 = Utils.byteMerger(bytes1, bytes2); return bytes3; }
定义的消息接收对象代码:
public class AIUIMessage{ private byte head; private byte mId; private byte mType; private short mMessageLen; private short mMessageId; private byte[] mBody; private byte sn; public byte getHead() { return head; } public void setHead(byte head) { this.head = head; } public byte getmType() { return mType; } public void setmType(byte mType) { this.mType = mType; } public byte getmId() { return mId; } public void setmId(byte mId) { this.mId = mId; } public short getmMessageId() { return mMessageId; } public void setmMessageId(short mMessageId) { this.mMessageId = mMessageId; } public short getmMessageLen() { return mMessageLen; } public void setmMessageLen(short mMessageLen) { this.mMessageLen = mMessageLen; } public byte[] getmBody() { return mBody; } public void setmBody(byte[] mBody) { this.mBody = mBody; } public byte getSn() { return sn; } public void setSn(byte sn) { this.sn = sn; } }
这里面我自己定义了一个对象来存储串口读出来的数据,因为有的数据可能一次性读不完,所以要将消息拼接起来解析。
3.通过串口发送控制消息给语音装置这里我就简单的构建了一个例子出来:
/** * 构建控制消息 * @param messagId 消息id */ private void buildTTSMessage(short messagId, AIUIBase aiuiBase){ Gson gson = new Gson(); String s = gson.toJson(aiuiBase); try { messageId++; byte[] strByte = s.getBytes("UTF-8"); int len = 8 + strByte.length; byte[] sendTTs = new byte[len]; sendTTs[0] = (byte) 0xA5; sendTTs[1] = (byte) 0x01; sendTTs[2] = (byte) 0x05; byte[] bytes = IntegerUtils.shortToBytes((short) strByte.length); byte[] bytes1 = IntegerUtils.shortToBytes(messagId); sendTTs[3] = bytes[0]; sendTTs[4] = bytes[1]; sendTTs[5] = bytes1[0]; sendTTs[6] = bytes1[1]; for (int i=0;i<strByte.length;i++){ sendTTs[i+7] = strByte[i]; } byte checkSum = (byte) LockerSerialportUtil.check(sendTTs, len); sendTTs[len-1] = checkSum; sendParams(sendTTs); String s1 = LockerSerialportUtil.byteToStr(sendTTs, len); Log.d(TAG, "发送控制消息: "+s1); } catch (Exception e) { Log.d(TAG, "buildTTSMessage Exception: "+e); } }
发送控制消息的这里要特别注意一点,就是消息id不能够乱填,要根据上一条的消息id加1,来确定下一条消息id,乱填id会导致你发送的命令不生效,这里你可以根据语音装置给过来的id进行保存,然后发送消息的时候加1就好了,确认消息的id是不遵循这个规则的。
这些就是我这段时间弄魔飞语音装置的一些总结,可能有不好的地方,后续会做优化,修改。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。