jSerialComm stops receiving data after a while - java

I'm trying to use this library for a JavaFX app that needs to listen 24/7 for messages sent on the serial port, so I'm trying to use the event based reading from jSerialComm with the RECEIVED event and a 0x03 (ETX) character delimeter. After running the app on windows 10, after a certain amount of time (sometimes minutes, sometimes hours) the app stops receiving data from the serial port. Am I setting up the classes correctly? This is my MessageListener class:
public final class MessageListener implements SerialPortMessageListener{
private FiseNavController controller;
#Override
public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
#Override
public byte[] getMessageDelimiter() { return new byte[] { (byte)0x03}; }
#Override
public boolean delimiterIndicatesEndOfMessage() { return true; }
#Override
public void serialEvent(SerialPortEvent event)
{
byte[] delimitedMessage = event.getReceivedData();
String message = new String(delimitedMessage);
System.out.println("Received the following delimited message: " + message);
}
}
This is how I set up the com port in my main class:
SerialPort[] ports = SerialPort.getCommPorts();
comPort = ports[ports.length - 1];
comPort.setComPortParameters(1200, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
//comPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0); --> commented out, not sure if this is needed and it doesn't make any difference
comPort.openPort();
MessageListener listener = new MessageListener();
comPort.addDataListener(listener);
Do I also need to clear the buffers every once in a while? Does this have to run on a separate thread?

Related

Resend messages after timeout

I have a list of objects that I put in Spring AMQP. Objects come from the controller. There is a service that processes these objects. And this service may crash with an OutOfMemoryException. Therefore, I run several instances of the application.
There is a problem: when the service crashes, I lose the received messages. I read about NACK. And could use it in case of Exception or RuntimeException. But my service crashes in Error. Therefore, I cannot send NACK. Is it possible to set a timeout in AMQP, after which I would be sent a message again if I had not confirmed the messages that had arrived earlier?
Here is the code I wrote:
public class Exchanges {
public static final String EXC_RENDER_NAME = "render.exchange.topic";
public static final TopicExchange EXC_RENDER = new TopicExchange(EXC_RENDER_NAME, true, false);
}
public class Queues {
public static final String RENDER_NAME = "render.queue.topic";
public static final Queue RENDER = new Queue(RENDER_NAME);
}
#RequiredArgsConstructor
#Service
public class RenderRabbitEventListener extends RabbitEventListener {
private final ApplicationEventPublisher eventPublisher;
#RabbitListener(bindings = #QueueBinding(value = #Queue(Queues.RENDER_NAME),
exchange = #Exchange(value = Exchanges.EXC_RENDER_NAME, type = "topic"),
key = "render.#")
)
public void onMessage(Message message, Channel channel) {
String routingKey = parseRoutingKey(message);
log.debug(String.format("Event %s", routingKey));
RenderQueueObject queueObject = parseRender(message, RenderQueueObject.class);
handleMessage(queueObject);
}
public void handleMessage(RenderQueueObject render) {
GenericSpringEvent<RenderQueueObject> springEvent = new GenericSpringEvent<>(render);
springEvent.setRender(true);
eventPublisher.publishEvent(springEvent);
}
}
And this is the method that sends messages:
    #Async ("threadPoolTaskExecutor")
    #EventListener (condition = "# event.queue")
    public void start (GenericSpringEvent <RenderQueueObject> event) {
        RenderQueueObject renderQueueObject = event.getWhat ();
        send (RENDER_NAME, renderQueueObject);
}
private void send(String routingKey, Object queue) {
try {
rabbitTemplate.convertAndSend(routingKey, objectMapper.writeValueAsString(queue));
} catch (JsonProcessingException e) {
log.warn("Can't send event!", e);
}
}
You need to close the connection to get the message re-queued.
It's best to terminate the application after an OOME (which, of course, will close the connection).

jSerialComm - SerialPortEvent.getReceivedData() returns null when Arduino Message is received

I'm making a program in Java which processes weather data recived from an Arduino Uno. It stores the data in a database and sends it to different apis.
I'm uses the jSerialComm library to get the data, which is sent via Serial Port from the Arduino. I'm using the SerialPortEvent, which is fired as soon as the Arduino sends any data (I'm not using InputStream, because of some other things in the programm won't work anymore).
Javacode:
(enable() is called in the main method of the program)
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
public class Arduino implements SerialPortDataListener {
#Override
public void enable() {
SerialPort comPort = SerialPort.getCommPort("COM5");
System.out.println(comPort.getDescriptivePortName());
comPort.openPort();
comPort.setBaudRate(9600);
comPort.addDataListener(this);
}
#Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
#Override
public void serialEvent(SerialPortEvent event) {
byte[] newData = event.getReceivedData();
System.out.println(newData);
}
}
Arduino programm:
(Just a simple testprogram for now)
void setup() {
Serial.begin(9600);
}
int i = 0;
void loop() {
Serial.println(i);
i++;
delay(1000);
}
But no matter what I'm doing, the SerialPortEvent.getReceivedData() methode always returns null, instead of the byte[]-Object (Its printed out once a second, as the Arduino sends its data):
Console Output:
User-Specified Port
null
null
null
null
...
Where is my mistake?
After messing around with your code a bit I've gotten it to work. First, you need to set the event to only trigger when data has been read by updating the getListeningEvents method to the following:
#Override
public int getListeningEvents() {
return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
}
Then, you need to interpret the array of bytes that is returned as a string by changing the serialEvent method to this:
#Override
public void serialEvent(SerialPortEvent event) {
byte[] newData = event.getReceivedData();
System.out.print(new String(newData));
}
This will print the numbers with newlines, because the Arduino is already sending newline characters after every number.
Try to get SerialPortEvent type inside serialEvent method then read the data as stream in case event triggers that data is ready, by first declaring input stream that should be accessible to the method :
InputStream inputStream = comPort.getInputStream();
Then serialEvent should be like this:
#Override
public void serialEvent(SerialPortEvent event) {
switch(event.getEventType())
{
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
System.out.println("empty");
break;
case SerialPortEvent.DATA_AVAILABLE:
try
{
byte[] readBuffer = new byte[inputStream.available()];
while(inputStream.available() > 0)
{
int numBytes = inputStream.read(readBuffer);
}
totalReadBuffer = readBuffer;
System.out.print(new String(readBuffer));
}
catch(IOException e)
{
}
catch(Exception ex)
{
ex.printStackTrace();
}
break;
}
}
}
You can check Link for full code, please note that class used for serial communication is SerialPortEventListener you can try it instead

Jetty WebSocket Client Doesn't work for Binary Listener

I have a Java app that uses the Jetty WebSocket Client, version 9.x. It works fine for text messages sent from the server, but the binary listener is never invoked. I have a Javascript client implementation which I'm basically duplicating. I'm doing the same exact thing in Javascript that I do in Java, calling the same server. The Javascript works, and the Java doesn't. So I'm thinking that something is not configured properly in Jetty for binary listeners.
For example, the server is sending blob data. I know that in the Javascript client, I can set the binarytype to either arraybuffer or blob. I figured there may be a similar setting required in Jetty, but I've looked all through the API and searched many examples online. There are precious few examples of binary listeners online, and no mention anywhere of setting the binarytype, or any other special setting required to make binary llisteners work.
Here's a consolidated representation of my code. The code is spread throughout various classes, so this is not a stand-alone app, but I think it shows what I'm doing. The server is implemented with libwebsockets.
Client implementation
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
client = new WebSocketClient();
client.start();
client.setMaxBinaryMessageBufferSize((int) 500e6);//just to be sure
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setSubProtocols("pipe-data");
client = new SimpleSocket();
client.connect(socket, uri, request);
Socket implementation
#WebSocket
public class SimpleSocket {
#SuppressWarnings("unused")
private Session session;
private SocketHandlerBase handler;
private boolean connected = false;
public SimpleSocket(SocketHandlerBase listener) {
this.handler = listener;
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
this.handler.onClose(statusCode, reason);
this.connected = false;
}
#OnWebSocketConnect
public void onConnect(Session session) {
this.handler.onConnect(session);
this.connected = true;
}
//invoked when text messages are sent
#OnWebSocketMessage
public void onMessage(String msg) {
this.handler.onMessage(msg);
}
//does not get invoked when binary data is sent
#OnWebSocketMessage
public void onMessage(byte buf[], int offset, int length) {
this.handler.onMessage(buf, offset, length);
}
public boolean isConnected() {
return this.connected;
}
public SocketHandlerBase getHandler() {
return this.handler;
}
}
There was a hard to find problem with the server I was calling. A very specific configuration of invocation arguments was causing the binary listener to not be called. Nothing about the Jetty client or WebSockets in general involved here.

Pusher: Decrease timeout for connection state

I'm currently experimenting with websockets using the Pusher library for Java.
Pusher automatically changes its connection state from CONNECTED to DISCONNECTED if the internet connection is lost. However, this only seems to happen after 150 seconds of being disconnected. This is very unfortunate as in those 150s, a lot of messages can get lost, and a de facto old message can still be seen as the most up-to-date.
How can I know if the last received message is the most up-to-date? Or is there any way to decrease the timeout for the connection state?
Here is the pusher code I'm using:
import com.pusher.client.Pusher;
import com.pusher.client.channel.Channel;
import com.pusher.client.channel.ChannelEventListener;
import com.pusher.client.channel.SubscriptionEventListener;
import com.pusher.client.connection.ConnectionEventListener;
import com.pusher.client.connection.ConnectionState;
import com.pusher.client.connection.ConnectionStateChange;
public class Testing {
public static void main(String[] args) throws Exception {
// Create a new Pusher instance
Pusher pusher = new Pusher("PusherKey");
pusher.connect(new ConnectionEventListener() {
#Override
public void onConnectionStateChange(ConnectionStateChange change) {
System.out.println("State changed to " + change.getCurrentState() +
" from " + change.getPreviousState());
}
#Override
public void onError(String message, String code, Exception e) {
System.out.println("There was a problem connecting!");
}
}, ConnectionState.ALL);
// Subscribe to a channel
Channel channel = pusher.subscribe("channel", new ChannelEventListener() {
#Override
public void onSubscriptionSucceeded(String channelName) {
System.out.println("Subscribed!");
}
#Override
public void onEvent(String channelName, String eventName, String data) {
System.out.println("desilo se");
}
});
// Bind to listen for events called "my-event" sent to "my-channel"
channel.bind("my-event", new SubscriptionEventListener() {
#Override
public void onEvent(String channel, String event, String data) {
System.out.println("Received event with data: " + data);
}
});
while(true){
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
}
Just found the answer: Initiate Pusher-object with PusherOptions-object.
Here is the PusherOptions-class: http://pusher.github.io/pusher-java-client/src-html/com/pusher/client/PusherOptions.html
Here is a simple example how I decreased my connection-timeout from 150s to 15s:
// Define timeout parameters
PusherOptions opt = new PusherOptions();
opt.setActivityTimeout((long)10000L);
opt.setPongTimeout((long)5000L);
// Create a new Pusher instance
Pusher pusher = new Pusher(PUSHER_KEY, opt);
ActivityTimeout defines how often a ping is sent out to check the connectivity, PongTimeout defines the waiting time until a response from the ping-signal is expected.
The minimum ActivityTimeout is 1000ms, however such a low value is strongly discouraged by Pusher, probably to decrease the server-traffic.

Java Client Server Programming: How to pass message from server to All Client threads?

I am creating a program with a server A and multiple clients B, C, D.
B C & D will all message the client with a number X, and I would like to know how it is possible for the server to message ALL clients simultaneously with the latest value for X?
As it stands, it will update only the client who has last passed number X.
Here is the code I have for run()
public void run(){
String number;
do
{
//Accept message from client on
//the socket's input stream...
received = in.readLine();
//Echo message back to client on
//the socket's output stream...
out.println("Number recieved: " + number);
}
}
Google up JMS Publish and Subscribe.
Basically:
The server publishes to a topic and the clients subscribe to a topic.
The best way to notify clients about something is to use JMX. If you're not supposed to use this technology, then you should keep clients list somewhere in your code (say in static field) and then iterate over this list and send received number
I'm not sure what you're trying to do...but you could try broadcasting a message using socket programming. Check this out
You can add all the sockets to a collection. Send the same message to every socket in the collection. Remove sockets from the collection when they are closed.
e.g.
final List<Socket> sockets = new CopyOnWriteArrayList<Socket>();
// when you have a new socket
sockets.add(socket);
// when you have a dead socket.
sockets.remove(socket);
// to send the same message to multiple sockets.
public static void sendToAll(byte[] bytes) {
for(Socket s: sockets)
try {
s.getOutputStream().write(bytes);
} catch (IOException ioe) {
// handle exception, close the socket.
sockets.remove(s);
}
}
I agree the real solution is JMS, but if you want to "roll your own" a simple solution I would suggest is making your own simplified version using the same idea of JMS. Create a class that will receive events from your client. Create an interface that your clients can implement and then add themselves as a listener to this new class. Some simple code:
class MyEventPublisher {
Collection<EventListener> listeners;
int number;
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void setNumber(int newNumber) {
int oldNumber = this.number;
this.number = newNumber;
for (EventListener listener : listeners) {
listener.numberChanged(newNumber, oldNumber);
}
}
}
interface EventListener {
void numberChanged(int newNumber, int oldNumber);
}
class MyClientSocket implements EventListener {
MyEventPublisher publisher;
public MyClientSocket(MyEventPublisher publisher) {
this.publisher = publisher;
publisher.addListener(this);
}
public recieveNumberFromSocket() {
int numberFromSocket = readNumber();
publisher.setNumber(numberFromSocket);
}
public void numberChanged(int newNumber, int oldNumber) {
//someone else changed the number
//do something interesting with it
}
}
You are looking for a multicast protocol, based on your descriptions.
So, I'll guess you'll be better of looking this:
Multicast (JDK 6)
Multicast (JDK 7)
Previous versions starting from JDK version 1.4.2 include multicast but you'll be better off if you use JDK version 6 or greater ;)

Categories

Resources