|
@@ -37,6 +37,8 @@ import com.wdkl.ncs.s433.receiver.utils.NetUtil;
|
|
import com.wdkl.ncs.s433.receiver.utils.SpeechUtil;
|
|
import com.wdkl.ncs.s433.receiver.utils.SpeechUtil;
|
|
import com.wdkl.ncs.s433.receiver.utils.VoiceManagerUtil;
|
|
import com.wdkl.ncs.s433.receiver.utils.VoiceManagerUtil;
|
|
|
|
|
|
|
|
+import org.apache.commons.lang3.ArrayUtils;
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
import org.greenrobot.eventbus.EventBus;
|
|
import org.greenrobot.eventbus.EventBus;
|
|
import org.greenrobot.eventbus.Subscribe;
|
|
import org.greenrobot.eventbus.Subscribe;
|
|
import org.greenrobot.eventbus.ThreadMode;
|
|
import org.greenrobot.eventbus.ThreadMode;
|
|
@@ -44,12 +46,20 @@ import org.greenrobot.eventbus.ThreadMode;
|
|
import java.io.DataOutputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStream;
|
|
|
|
+import java.nio.ByteBuffer;
|
|
import java.text.SimpleDateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
import java.util.Calendar;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.Iterator;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.Random;
|
|
import java.util.TimeZone;
|
|
import java.util.TimeZone;
|
|
|
|
+import java.util.Timer;
|
|
|
|
+import java.util.TimerTask;
|
|
|
|
+import java.util.zip.CRC32;
|
|
|
|
|
|
import static android.serialport.SerialPort.DEFAULT_SU_PATH;
|
|
import static android.serialport.SerialPort.DEFAULT_SU_PATH;
|
|
|
|
|
|
@@ -66,6 +76,11 @@ public class MainActivity extends SerialPortActivity {
|
|
private SmdtManager smdtManager;
|
|
private SmdtManager smdtManager;
|
|
private boolean debugShow = false;
|
|
private boolean debugShow = false;
|
|
|
|
|
|
|
|
+ //缓存本机收到的消息和时间
|
|
|
|
+ Map<String,Long> receivedCache = new HashMap<>();
|
|
|
|
+ //调度延迟任务
|
|
|
|
+ Timer timer = new Timer();
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
super.onCreate(savedInstanceState);
|
|
@@ -314,12 +329,148 @@ public class MainActivity extends SerialPortActivity {
|
|
});
|
|
});
|
|
//}
|
|
//}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //中继实现,每个机器收到一条消息后发出两次,第一次2秒内随机延迟,第二次3-4秒内随机延迟发送。可能会收到很多次。
|
|
|
|
+ //为防止多个设备同一时间发送导致信号互相干扰(实测两台设备同时发送时,第三个接收者会收不到消息),每个设备在收到消息后
|
|
|
|
+ //随机延迟一段时间发送,未减少碰撞分2次随机发送
|
|
|
|
+ long ctime = new Date().getTime();
|
|
|
|
+ //清理掉1分钟之前收到的消息
|
|
|
|
+ Iterator<Map.Entry<String, Long>> iterator = receivedCache.entrySet().iterator();
|
|
|
|
+ while (iterator.hasNext()){
|
|
|
|
+ if(iterator.next().getValue()-ctime>60000){
|
|
|
|
+ iterator.remove();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ final String org = data;
|
|
|
|
+ int i = random.nextInt(200)+1;
|
|
|
|
+ int j=random.nextInt(200)+200;
|
|
|
|
+ if(!receivedCache.containsKey(data)||receivedCache.containsKey(data)&&receivedCache.get(data)-ctime>60000) {
|
|
|
|
+ receivedCache.put(data,ctime);
|
|
|
|
+ Integer[] taskTime = new Integer[]{i,j};
|
|
|
|
+ for (Integer t : taskTime) {
|
|
|
|
+ timer.schedule(new TimerTask() {
|
|
|
|
+ @Override
|
|
|
|
+ public void run() {
|
|
|
|
+ try {
|
|
|
|
+ Log.i(TAG, "run: " + org);
|
|
|
|
+ if (StringUtils.isNotEmpty(org)) {
|
|
|
|
+ sendMsg(org, mOutputStream, 120);
|
|
|
|
+ }
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }, t * 10);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ //中继完成
|
|
|
|
+
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
Log.e("Application", "onDataReceivedString Exception...");
|
|
Log.e("Application", "onDataReceivedString Exception...");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 消息分包发送,包格式如下:每个包可传输的数据内容是发送缓冲区的大小减去21个字节。21个字节为包控制数据
|
|
|
|
+ * 保证接收端接收后可校验包的正确性。假设发送缓冲区是60个字节,那么每个包最多可发送39个字节的消息数据,
|
|
|
|
+ * 因为包已经校验准确性,接收端只需合并包内容数据即可。消息id使用整个消息内容的crc校验值
|
|
|
|
+ * 帧头 有效数据长度 包序 总包数 消息id 包内容 crc包校验
|
|
|
|
+ * 2B 1B 1B 1B 8B MAX-18 8B
|
|
|
|
+ *
|
|
|
|
+ * @param msg
|
|
|
|
+ * @param outputStream 输出
|
|
|
|
+ * @param packageLength 芯片发射分包长度(60,修改后为120)
|
|
|
|
+ */
|
|
|
|
+ private void sendMsg(String msg, OutputStream outputStream, int packageLength) throws IOException {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ char[] alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_".toCharArray();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ byte[] msgBytes = msg.getBytes();
|
|
|
|
+ //msgBytesLength 要发送的消息总长度,
|
|
|
|
+ int msgBytesLength = msgBytes.length;
|
|
|
|
+ //packageContentLength 每个包可发送的长度
|
|
|
|
+ int packageContentLength = packageLength - 21;
|
|
|
|
+ //要发送包的个数
|
|
|
|
+ int packages = msgBytesLength / packageContentLength + (msgBytesLength % packageContentLength != 0 ? 1 : 0);
|
|
|
|
+// String msgId = NanoIdUtils.randomNanoId(new Random(), alphabet, 5);
|
|
|
|
+ CRC32 crc32Msg = new CRC32();
|
|
|
|
+ crc32Msg.update(msgBytes);
|
|
|
|
+ long msgId = crc32Msg.getValue();
|
|
|
|
+// byte[] packageContent = new byte[packageContentLength];
|
|
|
|
+ byte[] start = String2Byte("AA55");
|
|
|
|
+ for (int i = 0; i < packages; i++) {
|
|
|
|
+ ByteBuffer buffer = ByteBuffer.allocate(packageLength - 8); //校验数据之前的数据
|
|
|
|
+ buffer.put(start);
|
|
|
|
+ //消息内容实际数据长度
|
|
|
|
+ byte contentLength = (byte) Math.min(packageContentLength, msgBytesLength - i * packageContentLength);
|
|
|
|
+ buffer.put(contentLength);
|
|
|
|
+ //包序
|
|
|
|
+ buffer.put((byte) (i + 1));
|
|
|
|
+ //总包数
|
|
|
|
+ buffer.put((byte) packages);
|
|
|
|
+ //消息id字节
|
|
|
|
+ byte[] msgIdBytes = ByteBuffer.allocate(8).putLong(msgId).array(); //msgId.getBytes();
|
|
|
|
+ buffer.put(msgIdBytes);
|
|
|
|
+ //包内容
|
|
|
|
+ byte[] subarray = ArrayUtils.subarray(msgBytes, i * packageContentLength, i * packageContentLength + contentLength);
|
|
|
|
+ ByteBuffer wrap = ByteBuffer.allocate(packageContentLength).put(subarray);
|
|
|
|
+ if (subarray.length < packageContentLength) {
|
|
|
|
+ wrap.put(new byte[packageContentLength - subarray.length]);
|
|
|
|
+ }
|
|
|
|
+ buffer.put(wrap.array());
|
|
|
|
+ CRC32 crc32 = new CRC32();
|
|
|
|
+ //计算校验
|
|
|
|
+ crc32.update(buffer.array());
|
|
|
|
+ Log.i(TAG, "sendMsg: "+ArrayUtils.toString(buffer.array()));
|
|
|
|
+ long value = crc32.getValue();
|
|
|
|
+ Log.i(TAG, "Crc: " + value);
|
|
|
|
+ byte[] crc = ByteBuffer.allocate(8).putLong(value).array();
|
|
|
|
+ ByteBuffer bufferSend = ByteBuffer.allocate(packageLength);
|
|
|
|
+ //把crc校验加入到包尾
|
|
|
|
+ bufferSend.put(buffer.array());
|
|
|
|
+ bufferSend.put(crc);
|
|
|
|
+ //发送包
|
|
|
|
+ Log.i(TAG, "sendMsg: 发送:"+ArrayUtils.toString(bufferSend.array()));
|
|
|
|
+ outputStream.write(bufferSend.array());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ throw e;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 16进制字符串转换成byte数组
|
|
|
|
+ */
|
|
|
|
+ public byte[] String2Byte(String s) {
|
|
|
|
+ s = s.replace(" ", "");
|
|
|
|
+ s = s.replace("#", "");
|
|
|
|
+ byte[] baKeyword = new byte[s.length() / 2];
|
|
|
|
+ for (int i = 0; i < baKeyword.length; i++) {
|
|
|
|
+ try {
|
|
|
|
+ baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return baKeyword;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
private void parseTcpData(TcpModel tcpModel) {
|
|
private void parseTcpData(TcpModel tcpModel) {
|
|
Log.e("Application", "action: " + tcpModel.getAction() + ", data: " + tcpModel.getData());
|
|
Log.e("Application", "action: " + tcpModel.getAction() + ", data: " + tcpModel.getData());
|
|
try {
|
|
try {
|