From 569a5c66c672a4b25c33c915b11bae9faba2c139 Mon Sep 17 00:00:00 2001 From: Will Hedgecock Date: Fri, 17 Dec 2021 15:37:56 -0600 Subject: [PATCH] Enable full range of event listener options for Windows --- src/main/c/Windows/SerialPort_Windows.c | 10 ++ .../com/fazecast/jSerialComm/SerialPort.java | 123 ++++++++---------- .../jSerialComm/SerialPortDataListener.java | 26 +++- .../fazecast/jSerialComm/SerialPortEvent.java | 60 ++++++++- .../resources/Windows/aarch64/jSerialComm.dll | Bin 83456 -> 83456 bytes .../resources/Windows/armv7/jSerialComm.dll | Bin 71168 -> 71168 bytes .../resources/Windows/x86/jSerialComm.dll | Bin 83968 -> 83968 bytes .../resources/Windows/x86_64/jSerialComm.dll | Bin 88064 -> 88064 bytes 8 files changed, 141 insertions(+), 78 deletions(-) diff --git a/src/main/c/Windows/SerialPort_Windows.c b/src/main/c/Windows/SerialPort_Windows.c index 2f9c32a..c213149 100644 --- a/src/main/c/Windows/SerialPort_Windows.c +++ b/src/main/c/Windows/SerialPort_Windows.c @@ -495,6 +495,16 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou eventFlags |= EV_RXCHAR; if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) eventFlags |= EV_TXEMPTY; + if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT) + eventFlags |= EV_BREAK; + if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS) + eventFlags |= EV_CTS; + if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR) + eventFlags |= EV_DSR; + if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR) + eventFlags |= EV_RING; + if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT) + eventFlags |= EV_RLSD; // Set updated port timeouts COMMTIMEOUTS timeouts; diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 38401aa..97a8d9e 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -2,7 +2,7 @@ * SerialPort.java * * Created on: Feb 25, 2012 - * Last Updated on: Dec 15, 2021 + * Last Updated on: Dec 17, 2021 * Author: Will Hedgecock * * Copyright (C) 2012-2021 Fazecast, Inc. @@ -934,19 +934,13 @@ public final class SerialPort if (userDataListener != null) return false; userDataListener = listener; + eventFlags = listener.getListeningEvents(); + if ((eventFlags & LISTENING_EVENT_DATA_RECEIVED) > 0) + eventFlags |= LISTENING_EVENT_DATA_AVAILABLE; serialEventListener = ((userDataListener instanceof SerialPortPacketListener) ? new SerialPortEventListener(((SerialPortPacketListener)userDataListener).getPacketSize()) : ((userDataListener instanceof SerialPortMessageListener) ? new SerialPortEventListener(((SerialPortMessageListener)userDataListener).getMessageDelimiter(), ((SerialPortMessageListener)userDataListener).delimiterIndicatesEndOfMessage()) : new SerialPortEventListener())); - - eventFlags = 0; - if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_AVAILABLE) > 0) - eventFlags |= LISTENING_EVENT_DATA_AVAILABLE; - if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_RECEIVED) > 0) - eventFlags |= LISTENING_EVENT_DATA_RECEIVED; - if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_WRITTEN) > 0) - eventFlags |= LISTENING_EVENT_DATA_WRITTEN; - if (portHandle > 0) { configTimeouts(portHandle, timeoutMode, readTimeout, writeTimeout, eventFlags); @@ -1667,75 +1661,62 @@ public final class SerialPort public final void waitForSerialEvent() throws Exception { - switch (waitForEvent(portHandle)) + int event = waitForEvent(portHandle) & eventFlags; + if (((event & LISTENING_EVENT_DATA_AVAILABLE) > 0) && ((eventFlags & LISTENING_EVENT_DATA_RECEIVED) > 0)) { - case LISTENING_EVENT_DATA_AVAILABLE: + // Read data from serial port + int numBytesAvailable, bytesRemaining, newBytesIndex; + event &= ~(LISTENING_EVENT_DATA_AVAILABLE | LISTENING_EVENT_DATA_RECEIVED); + while (eventListenerRunning && ((numBytesAvailable = bytesAvailable(portHandle)) > 0)) { - if ((eventFlags & LISTENING_EVENT_DATA_RECEIVED) > 0) + newBytesIndex = 0; + byte[] newBytes = new byte[numBytesAvailable]; + bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0, timeoutMode, readTimeout); + if (delimiters.length > 0) { - // Read data from serial port - int numBytesAvailable, bytesRemaining, newBytesIndex; - while (eventListenerRunning && ((numBytesAvailable = bytesAvailable(portHandle)) > 0)) + int startIndex = 0; + for (int offset = 0; offset < bytesRemaining; ++offset) + if (newBytes[offset] == delimiters[delimiterIndex]) + { + if ((++delimiterIndex) == delimiters.length) + { + messageBytes.write(newBytes, startIndex, 1 + offset - startIndex); + byte[] byteArray = (messageEndIsDelimited ? messageBytes.toByteArray() : Arrays.copyOf(messageBytes.toByteArray(), messageBytes.size() - delimiters.length)); + if ((byteArray.length > 0) && (messageEndIsDelimited || (delimiters[0] == byteArray[0]))) + userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, byteArray)); + startIndex = offset + 1; + messageBytes.reset(); + delimiterIndex = 0; + if (!messageEndIsDelimited) + messageBytes.write(delimiters, 0, delimiters.length); + } + } + else if (delimiterIndex != 0) + delimiterIndex = (newBytes[offset] == delimiters[0]) ? 1 : 0; + messageBytes.write(newBytes, startIndex, bytesRemaining - startIndex); + } + else if (dataPacket.length == 0) + userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, newBytes.clone())); + else + { + while (bytesRemaining >= (dataPacket.length - dataPacketIndex)) { - newBytesIndex = 0; - byte[] newBytes = new byte[numBytesAvailable]; - bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0, timeoutMode, readTimeout); - if (delimiters.length > 0) - { - int startIndex = 0; - for (int offset = 0; offset < bytesRemaining; ++offset) - if (newBytes[offset] == delimiters[delimiterIndex]) - { - if ((++delimiterIndex) == delimiters.length) - { - messageBytes.write(newBytes, startIndex, 1 + offset - startIndex); - byte[] byteArray = (messageEndIsDelimited ? messageBytes.toByteArray() : Arrays.copyOf(messageBytes.toByteArray(), messageBytes.size() - delimiters.length)); - if ((byteArray.length > 0) && (messageEndIsDelimited || (delimiters[0] == byteArray[0]))) - userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, byteArray)); - startIndex = offset + 1; - messageBytes.reset(); - delimiterIndex = 0; - if (!messageEndIsDelimited) - messageBytes.write(delimiters, 0, delimiters.length); - } - } - else if (delimiterIndex != 0) - delimiterIndex = (newBytes[offset] == delimiters[0]) ? 1 : 0; - messageBytes.write(newBytes, startIndex, bytesRemaining - startIndex); - } - else if (dataPacket.length == 0) - userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, newBytes.clone())); - else - { - while (bytesRemaining >= (dataPacket.length - dataPacketIndex)) - { - System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, dataPacket.length - dataPacketIndex); - bytesRemaining -= (dataPacket.length - dataPacketIndex); - newBytesIndex += (dataPacket.length - dataPacketIndex); - dataPacketIndex = 0; - userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, dataPacket.clone())); - } - if (bytesRemaining > 0) - { - System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, bytesRemaining); - dataPacketIndex += bytesRemaining; - } - } + System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, dataPacket.length - dataPacketIndex); + bytesRemaining -= (dataPacket.length - dataPacketIndex); + newBytesIndex += (dataPacket.length - dataPacketIndex); + dataPacketIndex = 0; + userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, dataPacket.clone())); + } + if (bytesRemaining > 0) + { + System.arraycopy(newBytes, newBytesIndex, dataPacket, dataPacketIndex, bytesRemaining); + dataPacketIndex += bytesRemaining; } } - else if ((eventFlags & LISTENING_EVENT_DATA_AVAILABLE) > 0) - userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_AVAILABLE)); - break; } - case LISTENING_EVENT_DATA_WRITTEN: - { - if ((eventFlags & LISTENING_EVENT_DATA_WRITTEN) > 0) - userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_WRITTEN)); - break; - } - default: - break; } + if (event != LISTENING_EVENT_TIMED_OUT) + userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, event)); } } diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java b/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java index c9d1fb3..8c75766 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java @@ -2,10 +2,10 @@ * SerialPortDataListener.java * * Created on: Feb 25, 2015 - * Last Updated on: Jan 03, 2018 + * Last Updated on: Dec 17, 2021 * Author: Will Hedgecock * - * Copyright (C) 2012-2020 Fazecast, Inc. + * Copyright (C) 2012-2021 Fazecast, Inc. * * This file is part of jSerialComm. * @@ -44,6 +44,15 @@ public interface SerialPortDataListener extends EventListener *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
*      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
*      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
+ *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
+ *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
+ *      {@link SerialPort#LISTENING_EVENT_CTS}
+ *      {@link SerialPort#LISTENING_EVENT_DSR}
+ *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
+ *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
*

* Two or more events may be OR'd together to listen for multiple events; however, if {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE} is OR'd with {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}, the {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED} flag will take precedence. *

@@ -54,15 +63,24 @@ public interface SerialPortDataListener extends EventListener * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN + * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT + * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT + * @see SerialPort#LISTENING_EVENT_CTS + * @see SerialPort#LISTENING_EVENT_DSR + * @see SerialPort#LISTENING_EVENT_RING_INDICATOR + * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR + * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_PARITY_ERROR */ public abstract int getListeningEvents(); /** - * Called whenever one of the serial port events specified by the {@link #getListeningEvents()} method occurs. + * Called whenever one or more of the serial port events specified by the {@link #getListeningEvents()} method occurs. *

* Note that your implementation of this function should always perform as little data processing as possible, as the speed at which this callback will fire is at the mercy of the underlying operating system. If you need to collect a large amount of data, application-level buffering should be implemented and data processing should occur on a separate thread. * - * @param event A {@link SerialPortEvent} object containing information and/or data about the serial event that occurred. + * @param event A {@link SerialPortEvent} object containing information and/or data about the serial events that occurred. * @see SerialPortEvent */ public abstract void serialEvent(SerialPortEvent event); diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java b/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java index 34b0953..9142a51 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java @@ -2,7 +2,7 @@ * SerialPortEvent.java * * Created on: Feb 25, 2015 - * Last Updated on: Nov 18, 2021 + * Last Updated on: Dec 17, 2021 * Author: Will Hedgecock * * Copyright (C) 2012-2021 Fazecast, Inc. @@ -50,6 +50,15 @@ public class SerialPortEvent extends EventObject *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
*      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
*      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
+ *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
+ *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
+ *      {@link SerialPort#LISTENING_EVENT_CTS}
+ *      {@link SerialPort#LISTENING_EVENT_DSR}
+ *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
+ *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
*

* Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} * event will never be called on a non-Windows system. @@ -59,6 +68,15 @@ public class SerialPortEvent extends EventObject * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN + * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT + * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT + * @see SerialPort#LISTENING_EVENT_CTS + * @see SerialPort#LISTENING_EVENT_DSR + * @see SerialPort#LISTENING_EVENT_RING_INDICATOR + * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR + * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_PARITY_ERROR */ public SerialPortEvent(SerialPort comPort, int serialEventType) { @@ -75,6 +93,15 @@ public class SerialPortEvent extends EventObject *      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
*      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
*      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
+ *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
+ *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
+ *      {@link SerialPort#LISTENING_EVENT_CTS}
+ *      {@link SerialPort#LISTENING_EVENT_DSR}
+ *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
+ *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
*

* Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} * event will never be called on a non-Windows system. @@ -85,6 +112,15 @@ public class SerialPortEvent extends EventObject * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN + * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT + * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT + * @see SerialPort#LISTENING_EVENT_CTS + * @see SerialPort#LISTENING_EVENT_DSR + * @see SerialPort#LISTENING_EVENT_RING_INDICATOR + * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR + * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_PARITY_ERROR */ public SerialPortEvent(SerialPort comPort, int serialEventType, byte[] data) { @@ -101,13 +137,22 @@ public class SerialPortEvent extends EventObject public final SerialPort getSerialPort() { return (SerialPort)source; } /** - * Returns the type of serial port event that caused this object to be created. + * Returns the type of serial port events that caused this object to be created. *

- * Return values will be one and only one of the following: + * Return value will be a bitmask containing one or more of the following items OR'd together: *

*      {@link SerialPort#LISTENING_EVENT_DATA_AVAILABLE}
*      {@link SerialPort#LISTENING_EVENT_DATA_RECEIVED}
*      {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN}
+ *      {@link SerialPort#LISTENING_EVENT_BREAK_INTERRUPT}
+ *      {@link SerialPort#LISTENING_EVENT_CARRIER_DETECT}
+ *      {@link SerialPort#LISTENING_EVENT_CTS}
+ *      {@link SerialPort#LISTENING_EVENT_DSR}
+ *      {@link SerialPort#LISTENING_EVENT_RING_INDICATOR}
+ *      {@link SerialPort#LISTENING_EVENT_FRAMING_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR}
+ *      {@link SerialPort#LISTENING_EVENT_PARITY_ERROR}
*

* Note that event-based write callbacks are only supported on Windows operating systems. As such, the {@link SerialPort#LISTENING_EVENT_DATA_WRITTEN} * event will never be called on a non-Windows system. @@ -116,6 +161,15 @@ public class SerialPortEvent extends EventObject * @see SerialPort#LISTENING_EVENT_DATA_AVAILABLE * @see SerialPort#LISTENING_EVENT_DATA_RECEIVED * @see SerialPort#LISTENING_EVENT_DATA_WRITTEN + * @see SerialPort#LISTENING_EVENT_BREAK_INTERRUPT + * @see SerialPort#LISTENING_EVENT_CARRIER_DETECT + * @see SerialPort#LISTENING_EVENT_CTS + * @see SerialPort#LISTENING_EVENT_DSR + * @see SerialPort#LISTENING_EVENT_RING_INDICATOR + * @see SerialPort#LISTENING_EVENT_FRAMING_ERROR + * @see SerialPort#LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR + * @see SerialPort#LISTENING_EVENT_PARITY_ERROR */ public final int getEventType() { return eventType; } diff --git a/src/main/resources/Windows/aarch64/jSerialComm.dll b/src/main/resources/Windows/aarch64/jSerialComm.dll index 642a93c788a5017444ac53fe47840db366101a01..8ea07775305676d2b066523105fea308cc056a73 100644 GIT binary patch delta 2295 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 delta 2206 zcmZ8hdr*`|67Qam)zuPQ#btS~f*^|zjG(9>e3TDBg2IYuL=Z%U6p4xP)H5Zx1Qk&@ zz+U6)I1o)Bs|IyQyiI(->0LtIc_kOi9HqvklsaNenVcrNF_`NQb9GhsM^Df6^!&Q} z*E3_Q*4e6cbvETE*ZDIQIz)r4!Yv9;Bh*d6DP+-^F`QC$=kVVWhj<`P{BZ&?wgF+ zveY*gjh7~X9X(XH>n_&ct-yLAY}O01%kQRwUGlx40D*0?(;SMJCHuz43S3V?p|#j7 zPlXaq)bG)js#dwK&!d77m%?dBV9dtC@8{eUi!r#ExC~U$3&Tlpk9PyeH8BIr>7_~D z7)qIqZ_Y`<&&W9^+IS|I z*#%}dj@b=`L3Y~+6P92TElsGv?bMU71q&!MF%I`pO`^n!l%$f+lb~O_vV_kSzUayi zLGr$OLqQ=s=a~hQ)Vsihz0$oP8jVu}!QP*&I`ujj)t?N`2Lr#DN@Y??s1T3+<+_DF zh%04j8n@A#j=nq>1@-axJz3IMi5`C{OY^7W={7t|VT)Qkcl(2Vut(mid#CJKl!!Q! z{4$C#fXXv+_%7bgD8z3lDYFEx(W%S>=%D%5O58nYd0oz0QiwQ;8nW)-Eh=4l2~X0T z>@++itFq@J&Zn!(j`0=Tu)IP%H_?yF_ux$`en0#@z`VHyL~I>x1{ErWJbQt zSthpm(25ylbYk1+{pPYE~0&q;Z8Um`YuRZ{TE_ zwI)#n8L4ckKiSv#jxrd*9?v(gK&Wo;uvtgYg*8#e@5j7oP}5%MK6V+pwd?M4$A+s;vjsN%6(Gx{csr(0dg&eE_M|CgU*RU{xqUBU9v!k>#z>i4t{^taf_LH& z56gy%RRVQ#VCMnEM!CPT(F6C>^y&lr%CA-z`XvkpyTW<6VpZpKp7)Ma-Om(oETq($ zSR7B~HL-qy|MiJho!**{65#lWeIjIcO*HB*4+FcKx~q*8Tx<2~;*|}d-KF?BdKHu7 z&%7>RqS~pdHqO${t0wWk-P6DBHnKM9p}v!;aPg@l^lfc4|7hdt;+Tcpx4((EW9qW1Cs6a`%&^R%1G+##{_0*Y}33pvU`er@YhjD2U(D4s_Iqb!ORiybP z@;S|StO?wU2JwO%a{#WH4E$%!^{CgdC$rt9_&X*J>HvpD7Ss<#zxxc?dl%}p>hqPv z8)Lm8Msw?>@_lKziLUOeG=9cDt=v@?e}nq1o1fw^)$OELDF83hPD;ZQ)Xn2T9;4`G zyD#qI*#uc_e+~I%xcA5T00ZpiM-w;}>dT*P|H7r{9Z!eKh40QDB3iAq>-T@*>zdv$ z5p(6%hAp}g5%X=<;%VSa;Tq`Li4Y1t);uL2A!c{kkR^Hy9(`2kBel(Z&Prc8&kdM( zBOf4UEZD3XL9KIXSF@Rtj(;ii${%X;hMbF>Q z6T7o1uO&~kE~kqv%|68|ZPqdD%OOtdm%e~cSwWjyXN%8s_I$u7Y6(ILOOx#F3s|uoF;r-dTScg%CEA{WgUNQV)`0h8n8F~i z3BwgF$lutm74lEkTA+KZwSvB5ttIobX6NMencQ#I2G&|)fvmOSBQ!fF9;4aM!wgV) mqE$Z&ng%P^w8ny_waPWE<(-M)BEAD)Erepzxicy**8K;tst)!5 diff --git a/src/main/resources/Windows/armv7/jSerialComm.dll b/src/main/resources/Windows/armv7/jSerialComm.dll index fbf583ba559ff470ae55278f370ffc0bd606a8c2..0cedcabe3f3add56074062676fc550e5fa7ba376 100644 GIT binary patch delta 2526 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 diff --git a/src/main/resources/Windows/x86/jSerialComm.dll b/src/main/resources/Windows/x86/jSerialComm.dll index cd3220f7fce8dc8a7925afed7faf09b5d0065254..0abf7ec6837a6e232f210da5c9aa826a8837e700 100644 GIT binary patch delta 2500 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 r9Ig*v6^|Mi4s{f0mOa5l|&N_Xp5$35aqfr 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 W1PZ@k>?y5P#B*9$v3C-rIsOMHHmFhn delta 4262 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