使用 JSSC 时如何从串行连接读取(所有可用的)数据?
How to read (all available) data from serial connection when using JSSC?
我正在尝试与 JSSC 合作。
我根据这个 link:
构建了我的应用程序
https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples
我的事件处理程序如下所示:
static class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR()){//If data is available
try {
byte buffer[] = serialPort.readBytes();
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
}
}
问题是我总是无法将传入的数据整合在一起。 (我的消息长度为 100 字节,我在 2 个单独的调用中得到 48 和 52 字节)
- 对方给我发不同长度的信息。
- 在我使用的 ICD 中,有一个字段告诉我们消息的长度。 (从字节 #10 到字节 #13)
- 我无法读取 14 个字节:
(serialPort.readBytes(14);,
解析消息长度并阅读消息的其余部分:
(serialPort.readBytes(messageLength-14);
但是如果我愿意这样做,我将不会在一次中获得消息(我将有 2 个单独的 byte[] 并且我需要在一个 (byte[]) 中没有复制功能的工作。
- 可能吗?
使用以太网 (SocketChannel) 时,我们可以使用 ByteBuffer 读取数据。但是对于 JSSC,我们不能。
- 有没有更好的 JSSC 替代方案?
谢谢
你不能依赖任何图书馆一次给你所有你需要的内容,因为:
- 图书馆不知道你需要多少数据
- 库会根据缓冲区、硬件等情况为您提供数据
您必须开发自己的业务逻辑来处理您的数据包接收。这当然取决于您的数据包是如何定义的:它们是否总是相同的长度,它们是否以相同的结束字符分隔等。
这是一个应该适用于您的系统的示例(请注意,您应该将此作为开始,而不是完整的解决方案,例如它不包括超时):
static class SerialPortReader implements SerialPortEventListener
{
private int m_nReceptionPosition = 0;
private boolean m_bReceptionActive = false;
private byte[] m_aReceptionBuffer = new byte[2048];
@Override
public void serialEvent(SerialPortEvent p_oEvent)
{
byte[] aReceiveBuffer = new byte[2048];
int nLength = 0;
int nByte = 0;
switch(p_oEvent.getEventType())
{
case SerialPortEvent.RXCHAR:
try
{
aReceiveBuffer = serialPort.readBytes();
for(nByte = 0;nByte < aReceiveBuffer.length;nByte++)
{
//System.out.print(String.format("%02X ",aReceiveBuffer[nByte]));
m_aReceptionBuffer[m_nReceptionPosition] = aReceiveBuffer[nByte];
// Buffer overflow protection
if(m_nReceptionPosition >= 2047)
{
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
else if(m_bReceptionActive)
{
m_nReceptionPosition++;
// Receive at least the start of the packet including the length
if(m_nReceptionPosition >= 14)
{
nLength = (short)((short)m_aReceptionBuffer[10] & 0x000000FF);
nLength |= ((short)m_aReceptionBuffer[11] << 8) & 0x0000FF00;
nLength |= ((short)m_aReceptionBuffer[12] << 16) & 0x00FF0000;
nLength |= ((short)m_aReceptionBuffer[13] << 24) & 0xFF000000;
//nLength += ..; // Depending if the length in the packet include ALL bytes from the packet or only the content part
if(m_nReceptionPosition >= nLength)
{
// You received at least all the content
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
}
}
// Start receiving only if this is a Start Of Header
else if(m_aReceptionBuffer[0] == '[=10=]')
{
m_bReceptionActive = true;
m_nReceptionPosition = 1;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
break;
default:
break;
}
}
}
串口写入数据后需要刷新。检查时序,注意读应该在另一端写完之后才发生。读取大小只是读取系统调用的指示,并不能保证。数据可能已经到达并缓冲在串行端口硬件缓冲区中,但可能尚未传输到操作系统缓冲区,因此未传输到应用程序。考虑使用 scm 库,它会在每次写入后刷新数据 http://www.embeddedunveiled.com/
试试这个:
将数据写入串行端口(使用 serialPort.writeBytes()),如果您希望得到响应,请使用:
byte[] getData() throws SerialPortException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b;
try {
while ((b = serialPort.readBytes(1, 100)) != null) {
baos.write(b);
// System.out.println ("Wrote: " + b.length + " bytes");
}
// System.out.println("Returning: " + Arrays.toString(baos.toByteArray()));
} catch (SerialPortTimeoutException ex) {
; //don't want to catch it, it just means there is no more data to read
}
return baos.toByteArray();
}
用返回的字节数组做你想做的;在我的例子中,我只是展示它用于测试。
我发现如果您使用 100 毫秒超时一次读取一个字节,它工作得很好,并且当它确实超时时,您已经读取了缓冲区中的所有数据。
来源:尝试使用 jssc 和 ESC/POS 与 Epson 串行打印机通信。
我正在尝试与 JSSC 合作。 我根据这个 link:
构建了我的应用程序https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples
我的事件处理程序如下所示:
static class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR()){//If data is available
try {
byte buffer[] = serialPort.readBytes();
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
}
}
问题是我总是无法将传入的数据整合在一起。 (我的消息长度为 100 字节,我在 2 个单独的调用中得到 48 和 52 字节)
- 对方给我发不同长度的信息。
- 在我使用的 ICD 中,有一个字段告诉我们消息的长度。 (从字节 #10 到字节 #13)
- 我无法读取 14 个字节:
(serialPort.readBytes(14);,
解析消息长度并阅读消息的其余部分:
(serialPort.readBytes(messageLength-14);
但是如果我愿意这样做,我将不会在一次中获得消息(我将有 2 个单独的 byte[] 并且我需要在一个 (byte[]) 中没有复制功能的工作。
- 可能吗?
使用以太网 (SocketChannel) 时,我们可以使用 ByteBuffer 读取数据。但是对于 JSSC,我们不能。
- 有没有更好的 JSSC 替代方案?
谢谢
你不能依赖任何图书馆一次给你所有你需要的内容,因为:
- 图书馆不知道你需要多少数据
- 库会根据缓冲区、硬件等情况为您提供数据
您必须开发自己的业务逻辑来处理您的数据包接收。这当然取决于您的数据包是如何定义的:它们是否总是相同的长度,它们是否以相同的结束字符分隔等。
这是一个应该适用于您的系统的示例(请注意,您应该将此作为开始,而不是完整的解决方案,例如它不包括超时):
static class SerialPortReader implements SerialPortEventListener
{
private int m_nReceptionPosition = 0;
private boolean m_bReceptionActive = false;
private byte[] m_aReceptionBuffer = new byte[2048];
@Override
public void serialEvent(SerialPortEvent p_oEvent)
{
byte[] aReceiveBuffer = new byte[2048];
int nLength = 0;
int nByte = 0;
switch(p_oEvent.getEventType())
{
case SerialPortEvent.RXCHAR:
try
{
aReceiveBuffer = serialPort.readBytes();
for(nByte = 0;nByte < aReceiveBuffer.length;nByte++)
{
//System.out.print(String.format("%02X ",aReceiveBuffer[nByte]));
m_aReceptionBuffer[m_nReceptionPosition] = aReceiveBuffer[nByte];
// Buffer overflow protection
if(m_nReceptionPosition >= 2047)
{
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
else if(m_bReceptionActive)
{
m_nReceptionPosition++;
// Receive at least the start of the packet including the length
if(m_nReceptionPosition >= 14)
{
nLength = (short)((short)m_aReceptionBuffer[10] & 0x000000FF);
nLength |= ((short)m_aReceptionBuffer[11] << 8) & 0x0000FF00;
nLength |= ((short)m_aReceptionBuffer[12] << 16) & 0x00FF0000;
nLength |= ((short)m_aReceptionBuffer[13] << 24) & 0xFF000000;
//nLength += ..; // Depending if the length in the packet include ALL bytes from the packet or only the content part
if(m_nReceptionPosition >= nLength)
{
// You received at least all the content
// Reset for next packet
m_bReceptionActive = false;
m_nReceptionPosition = 0;
}
}
}
// Start receiving only if this is a Start Of Header
else if(m_aReceptionBuffer[0] == '[=10=]')
{
m_bReceptionActive = true;
m_nReceptionPosition = 1;
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
break;
default:
break;
}
}
}
串口写入数据后需要刷新。检查时序,注意读应该在另一端写完之后才发生。读取大小只是读取系统调用的指示,并不能保证。数据可能已经到达并缓冲在串行端口硬件缓冲区中,但可能尚未传输到操作系统缓冲区,因此未传输到应用程序。考虑使用 scm 库,它会在每次写入后刷新数据 http://www.embeddedunveiled.com/
试试这个:
将数据写入串行端口(使用 serialPort.writeBytes()),如果您希望得到响应,请使用:
byte[] getData() throws SerialPortException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b;
try {
while ((b = serialPort.readBytes(1, 100)) != null) {
baos.write(b);
// System.out.println ("Wrote: " + b.length + " bytes");
}
// System.out.println("Returning: " + Arrays.toString(baos.toByteArray()));
} catch (SerialPortTimeoutException ex) {
; //don't want to catch it, it just means there is no more data to read
}
return baos.toByteArray();
}
用返回的字节数组做你想做的;在我的例子中,我只是展示它用于测试。
我发现如果您使用 100 毫秒超时一次读取一个字节,它工作得很好,并且当它确实超时时,您已经读取了缓冲区中的所有数据。
来源:尝试使用 jssc 和 ESC/POS 与 Epson 串行打印机通信。