Java串行数据事件处理

时间:2014-02-10 16:23:11

标签: java events event-handling serial-port

下面的代码详细说明了串行事件发生时读取的ID,设备上电时每隔几秒生成一个id(串行事件),并且关闭时没有接收到串行数据。问题是我需要的接收到id时发送一次url调用,不可见时发送一次urd调用(断电)。

我相信我很接近,但似乎无法做到正确。如果有人可以帮助解决这个问题以及如何设置标志和调度程序以实现上述情况并且可能解释我哪里出错,我将非常感激。

int numberOfEmptyIds = 0;
int maxNumberOfAttempts = 5;
boolean urlSent = false;
long timeoutInMillis = 10000; // let's say 10000 millis, equivalent to 10 seconds
Timer timer = null;

public void connect(String portName) throws Exception {
    ...
    scheduleTimer();
}

public void serialEvent(SerialPortEvent evt) {
    if(evt.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        try {
            while(in.read(buffer) > -1) {
                String asHexStr = DatatypeConverter.printHexBinary(buffer);
                if(asHexStr.contains("FB1")) {
                    scheduleTimer();
                    numberOfEmptyIds = 0;

                } else {
                    numberOfEmtyIds++;
                    if(numberOfEmptyIds == maxNumberOfAttempts && !urlSent) {
                        // send the url here
                    }
                }             
            }
        } catch (IOException ex) {
           // Log the exception here
        }
    }
}

private void scheduleTimer() {
    timer = new Timer("Timeout");
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            if(!urlSent) {
                // send the url here
            }
        }
    };
    timer.schedule(task, timeoutInMillis);
}

1 个答案:

答案 0 :(得分:1)

  

问题是我需要在收到ID时发送一次网址调用   并且一旦不可见(断电)。

第二部分由计时器完成,如果没有数据到达串口,则计划任务将发送URL(如果尚未发送)。在我对previous question的回答中,我忘记在重新安排任务时取消计时器:

private void scheduleTimer() {
    if(timer != null) {
        timer.cancel();
    }
    timer = new Timer("Timeout");
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            if(!urlSent) {
                // send the url here
            }
        }
    };
    timer.schedule(task, timeoutInMillis);
}

这样就会有一个计划任务。来自Timer.cancel() javadoc:

  

终止此计时器,丢弃当前计划的任何任务。是否   不干扰当前正在执行的任务(如果存在)。一旦   计时器已终止,其执行线程正常终止,   并且不再安排任何任务。

     

请注意,在计时器的run方法中调用此方法   这个计时器调用的任务绝对保证了   正在进行的任务执行是最后一次执行任务   由此计时器执行。

关于第一部分,您可以使用布尔标志来管理它,就像urlSent一样。如果您只需要发送一次URL,那么您可以为ID到达的URL发送一个标志,并且由于没有收到数据(或空ID)而发送另一个URL标记。


修改

根据您发布的here流程图,如下所示:

Enter description here http://dl6.fileswap.com/storage_previews/02112014/54cd147697479d29c43c530b93d5fa83/52fe9168/aW1hZ2UvanBlZw%3D%3D/4cf59787af56f18847df6235cdc20816.jpg

如果串口停止读取ID,您可以使用Timer.scheduleAtFixedRate()方法更改当前方法,以固定的时间a检查。由于您只需要发送一次ID接收通知,因此当有效发送此URL时,您可以将urlSent标记设置为true。此外,我认为你可以摆脱检查收到的数据是否不包含预期的ID。像这样:

boolean urlSent = false;

long lastIdArrivalTime = 0;
long timeTolerance = 60000;

long timeoutInMillis = 300000; // 5 minutes
Timer timer = null;

public void connect(String portName) throws Exception {
    ...
    scheduleTimer();
}

public void serialEvent(SerialPortEvent evt) {
    if(evt.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        try {
            while(in.read(buffer) > -1) {
                String asHexStr = DatatypeConverter.printHexBinary(buffer);
                if(asHexStr.contains("FB100000010F0801")) {
                    lastIdArrivalTime = System.currentTimeMillis();
                    if(!urlSent) {
                        // send the URL notifying the ID
                        urlSent = true; // next time url will not be sent
                    }
                }
            }
        } catch (IOException ex) {
           // Log the exception here
        }
    }
}

private void scheduleTimer() {
    timer = new Timer("Timeout");
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            long currentTime = System.currentTimeMillis();
            if((currentTime - lastIdArrivalTime) >= timeTolerance) {
                // sent the URL notifying the device is off
                urlSent = false; // this way the next ID arrival will be notified
            }
        }
    };
    timer.scheduleAtFixedRate(task, timeoutInMillis, timeoutInMillis);
}

一些注意事项:

  • 此计时器只安排一次,因为它将每5分钟执行一次任务。如果您需要关闭连接,请不要忘记调用timer.cancel()方法。
  • 变量lastIdArrivalTime保存ID到达时的最后时间(以毫秒为单位)。
  • 变量timeTolerance是假定连接断开的最大时间容差。正如您所说,设备会在固定的秒数内发送ID,因此,如果自上次ID到达后花了1分钟,那么您可以假设连接已关闭(或设备已关闭)。

有关您的代码的一些提示here

  • TimerTask实现Runnable接口,旨在使用Timer类,它将在预定时间到来时创建一个单独的线程来执行此任务,所以不要使用{ {1}}在一个新主题中。
  • 不要乱用 Threads 除非你确切知道你在做什么。这非常容易 错误并搞砸了事情。