Java串行数据事件处理

标签 java events event-handling serial-port

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

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

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);
}

最佳答案

Problem is i need a url call to be sent once when the id is received and once when not visible(powered down).

第二部分由定时器完成,如果没有数据到达串口,则计划任务将发送 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:

Terminates this timer, discarding any currently scheduled tasks. Does not interfere with a currently executing task (if it exists). Once a timer has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it.

Note that calling this method from within the run method of a timer task that was invoked by this timer absolutely guarantees that the ongoing task execution is the last task execution that will ever be performed by this timer.

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

<小时/>

编辑

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

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

您也许可以使用 Timer.scheduleAtFixedRate() 更改当前的方法方法以固定的时间速率检查串行端口是否停止读取 ID。由于您只需发送一次收到的 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接口(interface),旨在使用 Timer 使用类将在计划时间到来时创建一个单独的线程来执行此任务,因此不要在新线程中使用 TimerTask
  • 别惹事 Threads 除非你确切地知道你在做什么。制作一个非常容易 犯了错误,把事情搞砸了。

关于Java串行数据事件处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21682485/

相关文章:

java - 未调用标有@AssertTrue 的方法

java - 在 Eclipse 中,如何在显示窗口中显示调试器代码执行的异常消息?

c# - 如何避免将事件提升为封闭形式?

events - 未使用 adAsyncExecute 参数触发 ExecuteComplete ADODB 连接事件

.net - 何时重写 OnEventMethod 与处理实际事件

java - 使用 ASM 或 Javassist 提高字段获取和设置性能

java.lang.NoClassDefFoundError : org/openqa/selenium/remote/HttpVerb 错误

javascript - javascript中的鼠标悬停事件不会输出

C# - 将事件作为参数传递给子类时发生内存泄漏

c# - C# 方法如何仅在触发事件后才返回?