26
2017
09

安卓app如何处理串口的响应信息

大多数串口的响应是不需要处理的,命令发了也就发了。但严格来说,每一次命令发出去后,上层应用最好是做相应的处理。如果成功啦,就继续干别的;如果失败了,可以重试或者给用户相应的提示。

最近公司的项目里就遇到了这个情况。app对串口的响应非常依赖。其中最难的地方是,若干条串口命令是有顺序的,需要短时间内执行完,但是后面的命令依赖于前面命令的执行。若前面命令执行失败了,需要重试。那么就要求上层应用对发送的串口命令和其对应的响应一一对应起来。

好,问题来了。我们都知道串口通信是异步的。并且,为了保持通信畅通,每隔一定时间(100ms)还需要发送联络帧。假设我们现在有两种命令各2条共4条,它们的发送顺序是A1、B1、A2、B2。

Created with Raphaël 2.1.0 串口 串口 单片机 单片机 A1 处理A1 A1的响应 B1 处理B1 B1的响应 A2 处理A2 A2的响应 B2 处理B2 B2的响应

简化后的流程就是这样了。

一开始觉得有点摸不着头脑,毕竟回调函数都是void,又不能赋值,收到A1的响应后,我该如何告诉上层应用可以发送B1命令了呢。后来我想了一个办法。
1.声明并初始化一个全局变量List<> commandList;
2.准备好所有的命令(A1A2B1B2)并按顺序加到commandList里

commandList.add(A1);
commandList.add(B1);
commandList.add(A2);
commandList.add(B2);

3.编写两个方法

    /** * 执行命令列表中的第一个命令 */
    private void executeCommand() {
        if (commandList.size() == 0) {
            return;
        } else {
            //拿出第一条
            String command = commandList.get(0);
            //如有需要做些预处理
            //发送串口命令
            motorManager.sendCommand(command);
        }
    }

    /** * 移除命令列表中的第一个命令 */
    private void removeCommand() {
        if (commandList.size() == 0) {
            return;
        } else {
            //把第一条命令从列表中移除
            commandList.remove(0);
            //若执行的是当前用户的最后一条命令,则向服务端发送数据
            if (commandList.size() == 0) {
                //命令执行完看还需不需要做什么事情
                //比如可以将完成情况写到服务端
            }
        }
    }

4.将removeCommand和executeCommand方法放在串口回调函数中

    MotorCallback motorCallback = new MotorCallback() {

        @Override
        public void uartMsg(UartACK ack) {
            if (ack.errorCode != null && !ack.errorCode.equals("")) {
                //// 系统异常
                if (MotorManager.ERROR_SYSTEM.equals(ack.errorCode) ||
                        MotorManager.ERROR_MOTOR_TIMEOUT.equals(ack.errorCode)) {
                    //如果复位次数小于2,则复位,1秒后重发指令
                    if (resetNum < 2) {
                        //发送复位命令
                        motorManager.reset();
                        //new一个绑定在主线程Looper上的Handler
                        //休眠1秒钟后重发指令
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    Thread.sleep(1000);
                                    executeCommand();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                        resetNum++;
                    } else {
                        //// TODO: 2017/9/21 复位2次了还有问题,该如何解决?
                    }
                } else {
                    //// TODO: 2017/9/21 其他异常该如何告知给用户? //ack.errorTip
                    final String errorTip = ack.errorTip;
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            //放在UI线程弹Toast
                            Toast.makeText(MealActivity.this, errorTip, Toast.LENGTH_LONG).show();
                            Log.d(TAG, "Toast.makeText=" + errorTip);
                        }
                    });
                }
            } else {
                //当A类指令和B类指令执行成功后
                //必须定义好这个条件才能保证命令有序执行
                if (ack.number != null || ack.deliverWeight != null) {
                    //移除已经执行完的命令
                    removeCommand();
                    //继续执行下一个命令
                    executeCommand();
                }
            }
        }
    };

实践证明这样的方式挺好用的。

上一篇:四大组件的运行状态 下一篇:Git:warning: ignoring broken ref refs/remotes/origin/HEAD