Three-dimensional array arrives in wrong order at serial port - java
For an university assignment I'm writing a java application that will run some game logic for an interactive LED table. The table itself is being controlled by either 2 Arduino Duemilanove or 1 Arduino Mega 2560.
To give the Arduino(s) information about which LEDs should be lit in which color I send the data over the serial port from a Raspberry Pi 3b+ to the Arduinos. As the table consists of 14 LED strips with 14 LEDs per LED strip and each LED has 3 color values (RGB) I store the data about the table in an int[14][14][3] array.
Before sending the array to the Arduino I create a JSON object of it (using the Jackson library) and then send the array as a String using jSerialComm. Depending on which Arduino setup I use I also either transfer the whole array to JSON or split it into two int[7][14][3] arrays before creating the JSON object.
As the data arrived in the wrong order at the serial port when I used 2 Arduinos and jSerialComm I now got a new Arduino Mega 2560 (as other SO questions suggested the wrong data order might occur due to an outdated PL2303 module) and tried it again with the same result. After some further research I now tried using JSSC instead of jSerialComm but still the same result shows up.
The java class that I use to send the data to the arduino looks like this (the outcommented code being the code where I used jSerialComm / 2 Arduinos):
package de.pimatrix.backend;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fazecast.jSerialComm.SerialPort;
import jssc.SerialPortException;
public class SerialThread implements Runnable {
public static SerialPort arduino1, arduino2;
private int[][][] matrix = new int[14][14][3];
private int[][][] matrixLeft = new int[7][14][3];
private int[][][] matrixRight = new int[7][14][3];
private Socket localHost;
private Matrix matrixData;
private ObjectInputStream in;
#Override
public void run() {
SerialJSONWriter writer = new SerialJSONWriter();
ServerSocket ss = null;
localHost = null;
matrixData = new Matrix(matrix);
try {
ss = new ServerSocket(62000); // erstellen eines lokalen Sockets auf Port 62000, um die zu übertragende
// Matrix vom ClientThread
} catch (IOException e) {
}
while (true) {
try {
localHost = ss.accept();
} catch (Exception e) {
e.printStackTrace();
}
initializeInputStream();
waitForMatrix();
splitMatrix();
try {
writer.tryWrite(matrixRight, matrixLeft);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void splitMatrix() {
for (int i = 0; i < 14; i++) {
for (int j = 0; j < 14; j++) {
if (i <= 6) {
matrixRight[i][j][0] = matrix[i][j][0];
matrixRight[i][j][1] = matrix[i][j][1];
matrixRight[i][j][2] = matrix[i][j][2];
} else {
matrixLeft[i - 7][j][0] = matrix[i][j][0];
matrixLeft[i - 7][j][1] = matrix[i][j][1];
matrixLeft[i - 7][j][2] = matrix[i][j][2];
}
}
}
}
private void initializeInputStream() {
try {
InputStream input = localHost.getInputStream();
in = new ObjectInputStream(input);
} catch (IOException e) {
e.printStackTrace();
}
}
public void waitForMatrix() {
System.out.println("Waiting for Matrix");
try {
matrixData = (Matrix) in.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
this.matrix = matrixData.matrix;
}
class SerialJSONWriter implements AutoCloseable {
// Zuweisen der seriellen Ports
// private final SerialPort /*arduino1, arduino2,*/ arduinoMega;
private jssc.SerialPort arduinoMega;
public SerialJSONWriter() {
// arduino1 = SerialPort.getCommPort("COM5");
// arduino2 = SerialPort.getCommPort("COM6");
// arduinoMega = SerialPort.getCommPort("COM7");
arduinoMega = new jssc.SerialPort("COM7");
try {
arduinoMega.openPort();
arduinoMega.setParams(115200, 8, 1, jssc.SerialPort.PARITY_EVEN);
} catch (SerialPortException e) {
e.printStackTrace();
}
// arduinoMega.setBaudRate(115200);
// arduinoMega.setNumDataBits(8);
// arduinoMega.setNumStopBits(1);
// arduinoMega.setParity(0);
// setzen der Timeouts für die Kommunikation mit den Arduinos
// arduino1.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
// arduino2.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
// arduinoMega.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
// arduino1.setBaudRate(115200);
// arduino2.setBaudRate(115200);
// arduinoMega.setBaudRate(115200);
// arduino1.openPort();
// arduino2.openPort();
// arduinoMega.openPort();
// arduino1.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
// 0);
// arduino2.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
// 0);
// arduinoMega.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
// 0);
}
public void write() {
}
private void tryWrite(Object dataRight, Object dataLeft) throws IOException {
String dataAsJSONRight = new ObjectMapper().writeValueAsString(dataRight) + "\n";
String dataAsJSONLeft = new ObjectMapper().writeValueAsString(dataLeft) + "\n";
try {
arduinoMega.writeString(dataAsJSONRight);
} catch (SerialPortException e) {
e.printStackTrace();
}
// for (int i = 0; i < dataAsJSONRight.length(); i++) {
//// arduino1.getOutputStream().write(dataAsJSONRight.getBytes()[i]);
// System.out.println(dataAsJSONRight);
// arduinoMega.getOutputStream().write(dataAsJSONRight.getBytes()[i]);
// }
// for (int i = 0; i < dataAsJSONLeft.length(); i++) {
//// arduino2.getOutputStream().write(dataAsJSONLeft.getBytes()[i]);
// arduinoMega.getOutputStream().write(dataAsJSONLeft.getBytes()[i]);
// }
}
#Override
public void close() throws Exception {
// arduino1.closePort();
// arduino2.closePort();
arduinoMega.closePort();
}
}
}
On the Arduino(s) the processing looks like this:
#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>
#define PINROW0 2
#define PINROW1 3
#define PINROW2 4
#define PINROW3 5
#define PINROW4 6
#define PINROW5 7
#define PINROW6 8
#define NUMPIXELS 14 //Amount of pixels per row
Adafruit_NeoPixel row[] = { //Intitialize the array, that contains the addressable LED strips in the Adafruit format
Adafruit_NeoPixel(NUMPIXELS, PINROW0, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW1, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW2, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW3, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW4, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW5, NEO_GRB + NEO_KHZ800),
Adafruit_NeoPixel(NUMPIXELS, PINROW6, NEO_GRB + NEO_KHZ800)
};
#define DELAY 1000 //set refresh cycle to 10 milliseconds
#define NUMSTRIPS 7/*(sizeof(row)/sizeof(row[0]))*/ //Amount of connected LED strips
int values[7][14][3];
int c = 0;
String matrixAsString = "";
void setup() {
/*Setup serial port on which the Pi connects to the Arduino*/
Serial.begin(115200); //set baudrate to 115200 Bit per second
Serial.setTimeout(1000);
Serial.println(100);
/*initialize NeoPixel Library*/
for (int i = 0; i < NUMSTRIPS; i++) {
row[i].begin();
row[i].show();
}
}
void process(String matrixAsString) {
StaticJsonDocument<4372> doc;
Serial.println(matrixAsString);
deserializeJson(doc, matrixAsString);
for (int i = 0; i < 7; i++) {
for (int j = 0; i < 14; j++) {
values[i][j][0] = values[i][j][1] = values[i][j][2] = (int) (doc[i][j][0]);
}
}
}
//infinite loop refreshing the matrix
void loop() {
while (Serial.available()) {
char c = Serial.read();
Serial.println(matrixAsString);
matrixAsString += c;
if (c == '\n') {
process(matrixAsString);
matrixAsString = "";
}
}
}
When sending the data for a half matrix (so an int[7][14][3]):
[[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]]
through the serial monitor in the Arduino IDE I get this output from the Arduino (as of the Serial.println() in void loop):
As one can see the first RGB values are transmitted correctly, however after even less than one complete LED strip the data arrives in the wrong order and (as you can see at the end of the picture) at some point completely stops showing up, which probably indicates no data is being read any more.
I've been trying a hell of things like changing the Arduino in case the PL2303 is outdated or defective as well as trying different libraries for serial communication however I cannot figure out what I'm doing wrong. I've spent over 30 hours trying different approaches to no avail so things are becoming really frustrating for me.
UPDATE
As suggested by B.Letz I got the setup of the data, stop and parity bits right (now being 8 data, 1 stop and no parity bits). By reading the arduino feedback I still got the same results but after some tweeking I recognized that the problem probably was that my Serial.print apparently led to a massive lag on the Arduino so it couldn't handle all the data correctly and in time. After removing the first Serial.print call before doing the processing I now see the first matrix that is being transmitted being printed correctly by the Arduino. However for some reason for all further transmitted data the Arduino prints null. I'll try extending the timeouts in case the null pointer occurs due to a timeout on the Arduino-side.
UPDATE 2
Opposed to my assumption reconfiguring the timeouts didn't solve the problem. I also figured out that after the first JSON Object is sent the Arduino prints null to the console and only sends me the first JSON object after receiving the second JSON object. However this is the only time I get any feedback from the Arduino except null. What I also noticed is that when I send the JSON String over the serial monitor the Arduino instantly prints the correct String BUT it also prints an empty new line and doesn't respond to any new data in any kind.
The first step for a working solution was removing the unnecessary Serial.print() call everytime a new char was read. After removing this line I could confirm the data arrived properly.
The shifted feedback as mentioned in my second update to the post:
I also figured out that after the first JSON Object is sent the Arduino prints null to the console and only sends me the first JSON object after receiving the second JSON object. However this is the only time I get any feedback from the Arduino except null
occured due to the fact that I didn't wait long enough on the java application side for data to arrive before calling the read() function. After solving this I always received the correct string.
Trying out different configurations with either DynamicJsonDocument and StaticJsonDocument I now ended up using DynamicJsonDocument however also a StaticJsonDocument might have worked here.
A rather unpleasant issue was that in the inner for-loop in void process I accidently compared the counter variable to that of the outer for-loop, although I was able to retrieve the correct data at that point outside of the for-loop.
The problem asked in this questions is thereby solved, however a even bigger problem now occured as I'm not able to retrieve any data from the received JSON object as soon as I start implementing the code for controlling the LEDs and call row[i].setPixelColor(j, row[i].Color(values[i][j][0], values[i][j][1], values[i][j][2])); at any point in my code. So to sum things up this specific call is the actual reason that the code doesn't work properly.
I'll be opening a new question for that new problem as it doesn't belong to this question thematically, however I will add a reference to it here, once it's written.
UPDATE
The new question regarding addressing more than 7 LED strips using Adafruit's NeoPixel library can be found here.
Related
Sending data from arduino to java
Hello im working on a project for myself. i have serveral RFID cards. I want to send a RFID code(cardID) to my arduino and then scan a random rfid card. if the sent RFID code and the one scaned are matching i want to send back a string/number or just one byte back to my java programm. so far sending to my arduino and checking the RFID card is working fine however im stuck at sending something back to my java programm. i was thinking about using serielConnection but tbh its very difficult to understand. can someone help me out ? thanks in advance my java code package test; import java.io.IOException; import com.fazecast.jSerialComm.SerialPort; public class Startup { public static void main(String[] args) throws IOException, InterruptedException { SerialPort sp = SerialPort.getCommPort("COM4"); // device name TODO: must be changed sp.setComPortParameters(115200, 8, 33, 34); // 9600,8,1,0default connection settings for Arduino sp.setComPortTimeouts(SerialPort.TIMEOUT_WRITE_BLOCKING, 0, 0); // block until bytes can be written if (sp.openPort()) { System.out.println("Port is open :)"); } else { System.out.println("Failed to open port :("); return; } /*for (Integer i = 0; i < 5; ++i) { sp.getOutputStream().write(i.byteValue()); sp.getOutputStream().flush(); System.out.println("Sent number: " + i); Thread.sleep(4000); //default 1000 } */ //rfid tag 0x82,130 //rfid card 118 Integer i = 0;//0x82,130 sp.getOutputStream().write(i.byteValue()); sp.getOutputStream().flush(); System.out.println("Sent number: " + i); Thread.sleep(8000); if (sp.closePort()) { System.out.println("Port is closed :)"); } else { System.out.println("Failed to close port :("); return; } //from arduino } } arduino code: #include <SPI.h> #include <MFRC522.h> #define RST_PIN 26 #define SS_PIN 5 #define MISO_PIN 19 #define MOSI_PIN 23 #define SCK_PIN 18 byte incomingByte = Serial.read(); MFRC522 mfrc522(SS_PIN, RST_PIN); MFRC522::MIFARE_Key key; void setup() { Serial.begin(115200); // Initialize serial communications with the PC pinMode(16,OUTPUT); pinMode(21,OUTPUT); while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN); mfrc522.PCD_Init(); // Init MFRC522 delay(40); // Optional delay. Some board do need more time after init to be ready, see Readme mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details //dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); } void loop() { if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } if ( ! mfrc522.PICC_ReadCardSerial()) { return; } if(Serial.available() > 0){ byte incomingByte = Serial.read(); if (mfrc522.uid.uidByte[0] == incomingByte )/*&&*/ //それぞれ読んだカードの値と比較したい16進数の値を比較 ) { digitalWrite(16,HIGH); delay(5000); digitalWrite(16,LOW); delay(50); } else{ digitalWrite(21,HIGH); delay(2000); digitalWrite(21,LOW); } } } as i understand so far, for the arduino i just have to add this to send data from the arduino SerielWrite(a number); what is giving me a headache is how to receive it in java. i already know that i need rxtx or jseriel libary for my java code. i also already tryed some examples to recieve a number but it didnt work at all. does someone maybe has a very easy code to receive a number in java ?
To recieve data in java from the arduino, you need a SerialDataListener to listen for data on the Serial Port. This can be done by creating a class which implements the SerialDataListener interface. This examples just prints to the console whatever data is read from the Serial Port but you can make it do whatever you'd like. import com.fazecast.jSerialComm.*; public class ComPortListener implements SerialPortDataListener { private static String bufferReadToString = ""; // empty, but not null private static int cutoffASCII = 10; // ASCII code of the character used for cut-off between received messages #Override public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; //returns data on the Serial Port } #Override public void serialEvent(SerialPortEvent event) { byte[] buffer = new byte[event.getSerialPort().bytesAvailable()]; event.getSerialPort().readBytes(buffer, buffer.length); String s = new String(buffer); bufferReadToString = bufferReadToString.concat(s); //converts the bytes read from the Serial port to a string if ((bufferReadToString.indexOf(cutoffASCII) + 1) > 0) { System.out.println(bufferReadToString); //prints out the recived data } } } To use this, add the following code to your Startup class if (sp.openPort()) { System.out.println("Port is open :)"); ComPortListener listenerObject = new ComPortListener(); //creates new listener object serialPort.addDataListener(listenerObject); }
Midi input on raspberry pi
I have implemented a simple program, that takes input from a Midi keyboard and then outputs the corresponding sound using the javax synthesizer interface. This works really well on my Pc running Windows, however, I want to run it on a Raspberry Pi running Raspbian. It actually does work, too, but as soon as i play more/faster notes, the sound starts to jitter and crackle really bad, and i have to stop playing notes for about 2 seconds in order for the jittering to die down. I am using a external USB sound adapter already, which did not really help alot. Here is the class that handles the midi input: public class MidiHandler { public MidiHandler() { MidiDevice device; MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); for (int i = 0; i < infos.length; i++) { try { device = MidiSystem.getMidiDevice(infos[i]); // does the device have any transmitters? // if it does, add it to the device list System.out.println(infos[i]); // get all transmitters List<Transmitter> transmitters = device.getTransmitters(); // and for each transmitter for (int j = 0; j < transmitters.size(); j++) { // create a new receiver transmitters.get(j).setReceiver( // using my own MidiInputReceiver new MidiInputReceiver(device.getDeviceInfo() .toString())); } Transmitter trans = device.getTransmitter(); trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo() .toString())); // open each device device.open(); // if code gets this far without throwing an exception // print a success message } catch (MidiUnavailableException e) { } } } // tried to write my own class. I thought the send method handles an // MidiEvents sent to it public class MidiInputReceiver implements Receiver { Synthesizer synth; MidiChannel[] mc; Instrument[] instr; int instrument; int channel; public MidiInputReceiver(String name) { try { patcher p = new patcher(); this.instrument = p.getInstrument(); this.channel = p.getChannel(); this.synth = MidiSystem.getSynthesizer(); this.synth.open(); this.mc = synth.getChannels(); instr = synth.getDefaultSoundbank().getInstruments(); this.synth.loadInstrument(instr[1]); mc[this.channel].programChange(0, this.instrument); System.out.println(this.channel + ", " + this.instrument); } catch (MidiUnavailableException e) { e.printStackTrace(); System.exit(1); } } public void send(MidiMessage msg, long timeStamp) { /* * Use to display midi message * for(int i = 0; i < msg.getMessage().length; i++) { System.out.print("[" + msg.getMessage()[i] + "] "); } System.out.println(); */ if (msg.getMessage()[0] == -112) { mc[this.channel].noteOn(msg.getMessage()[1], msg.getMessage()[2]+1000); } if (msg.getMessage()[0] == -128) { mc[this.channel].noteOff(msg.getMessage()[1], msg.getMessage()[2]+1000); } } public void close() { } } } Is this due to hardware limitations of the Pi, or can I do anything about it?
If you have any loops for updating the midi retrieval/sound output, maybe try thread-sleeping in there to give the OS time to do stuff? Other than that, not sure. The USB on the original Raspberry Pi wasn't very good for some reason (lots of bugs, slow performance -- but these did get fixed somewhat in newer Linux/firmware). You may also need to modify the sample rate to match the ideal setting for the current sound output, if it's accessible (sample rate mismatch means more conversion). Java may try to use the ideal as the default, but may be misreported by the OS?
How to read (all available) data from serial connection when using JSSC?
I'm trying to work with JSSC. I built my app according to this link: https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples My event handler looks like: 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); } } } } } The problem is that I'm always not getting the incoming data in one piece. (I the message has a length of 100 bytes, Im getting 48 and 52 bytes in 2 separates calls) - The other side send me messages in different lengths. - In the ICD Im working with, there is a field which tell us the length of the message. (from byte #10 to byte #13) - I cant read 14 bytes: (serialPort.readBytes(14);, parse the message length and read the rest of the message: (serialPort.readBytes(messageLength-14); But if I will do it, I will not have the message in once piece (I will have 2 separates byte[] and I need it in one piece (byte[]) without the work of copy function. Is it possible ? When working with Ethernet (SocketChannel) we can read data using ByteBuffer. But with JSSC we cant. Is there a good alternative to JSSC ? Thanks
You can't rely on any library to give you all the content you need at once because : the library dont know how many data you need the library will give you data as it comes and also depending on buffers, hardware, etc You must develop your own business logic to handle your packets reception. It will of course depend on how your packets are defined : are they always the same length, are they separated with same ending character, etc. Here is an example that should work with your system (note you should take this as a start, not a full solution, it doesn't include timeout for example) : 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] == '\0') { m_bReceptionActive = true; m_nReceptionPosition = 1; } } } catch(Exception e) { e.printStackTrace(); } break; default: break; } } }
After writing data to serial port it need to be flushed. Check the timing and pay attention to the fact that read should occur only after other end has written. read size is just an indication to read system call and is not guaranteed. The data may have arrived and is buffered in serial port hardware buffer but may not have been transferred to operating system buffer hence not to application. Consider using scm library, it flushes data after each write http://www.embeddedunveiled.com/
Try this: Write your data to the serial port (using serialPort.writeBytes()) and if you are expecting a response, use this: 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(); } Do what you want with the returned byte array; in my case I just display it for testing. I found it works just fine if you read one byte at a time, using a 100ms timeout, and when it does time out, you've read all data in the buffer. Source: trying to talk to an Epson serial printer using jssc and ESC/POS.
Java writing bytes to serial port USB
I have a code below that I am sending to a serial USB port... it was working, now its not! the akber() function dies if the wrong string is sent... if I send akber("1.0.0.0.1.5") - it works perfectly, if I send akber("23.0.128.0.0.5") - it does not work... See code below public static byte[] akber(final String input) { StringTokenizer tokens = new StringTokenizer(input, "."); int numberOfArrays = tokens.countTokens(); byte[][] byteArrays; byteArrays = new byte[numberOfArrays][4]; int i = 0; int space = 0; while (tokens.hasMoreTokens()) { int x = Integer.valueOf(tokens.nextToken()); if (x<256) { space++; } else { space+=2; } byteArrays[i] = BigInteger.valueOf(x).toByteArray(); i++; } final byte[] output = new byte[space]; copySmallArraysToBigArray(byteArrays, output); return output; } public static void copySmallArraysToBigArray(final byte[][] smallArrays, final byte[] bigArray) { int currentOffset = 0; for (final byte[] currentArray : smallArrays) { System.arraycopy(currentArray, 0, bigArray, currentOffset, currentArray.length); currentOffset += currentArray.length; } } called from function: serialPort.writeBytes(akber(data)); I would need it to work with any combination of numbers in the "data" string, so it converts them to the right type of bytes and writes to port... its not my code, and I don't quite understand it, but still need to fix it :-)
Change this line: if (x<256) { space++; } else { space+=2; } to if (x<128) { space++; } else { space+=2; } I ran your code, originally it throws an IndexOutOfBoundsException for akber("1.0.128.0.0.5"); so check your code that it is not consuming exceptions somewhere, e.g. try { exceptionThrowingMethod(); } catch(Exception e) { } If the exceptionThrowingMethod throws an exception the code will continue as if the exception was not thrown (but the exceptionThrowingMethod didn't execute succesfully!)
Actually although the above allowed the code to continue working, it did not solve the problem as byte values from the function above 128 were the negative equivalent or something, and sent the wrong values, so the USB hardware was receiving the incorrect characters and not working... by looking at other posts about "Java 128 bytes" on stackoverflow, worked out its something to with byte code above 128 being the same as its negative equivalent, so solved it with trial and error, very annoying - but changed that line to: if (x<128) { space++; } else { space+=2; int x2 = (x-128)*2; x=x-(x*2); if (x<-128) { x=x+x2; } } which seemed to work. So happy days, till I find another issue with it! Might be a simple solution for people looking to convert values above 127 to bytes, than more standard Java solution I saw and didnt really understand, as am more used to scripting. Thanks.
Is there any way to send an array of Point with DataOutputStream over a Socket?
I want to send an array of point (Point points[] = new point[20]) with DataOutputStream over a socket and be able to correctly read it with DataInputStream on the other side. I CANNOT send each element separately, it must be sent as a whole array and be able to be interpreted as a whole array.
See e.g. the section "Transporting Custom Objects" in Advanced Socket Programming: Put your data into a Serializable class, say MyData. (You don't really have to do this in your case, because arrays implement Serializable, but there is a chance that later you will want to send other data along with your point array...) On the sender side, create a MyData object and fill it with data. Cast socket.getOutputStream() to an ObjectOutputStream, and call its writeObject method to send the MyData object. On the receiver side, cast socket.getInputStream() to an ObjectInputStream, and call its readObject method to receive the object (you will have to cast it to MyData). Anyway, I would also consider using RMI. For example, you could create a PointServer, register it in the RMI registry, and access it through simple function calls in your client application. RMI is much easier to work with than sockets. For example, you don't have to design a protocol, you only need to define methods for your distributed objects.
Why not use an ObjectInputStream/ObjectOutputStream instead? Here's a piece of code for something I wrote long ago, it will allow you to send any kind of object through the wire so long as it's serializable, obviously: ObjectInputStream input = new ObjectInputStream(communicationSocket.getInputStream()); if (input != null) { try { Object o = input.readObject(); if (o != null && o instanceof DataObject) { DataObject response = (DataObject) o; { //Do something cool with DataObject } } }//etc... DataObject is just a "wrapper"/custom class that you can define as having as one of it's properties a Point[]; in other words, you could define DataObject as: import java.io.Serializable; public class DataObject implements Serializable { private Point[] points; //etc - define getter setter for points } And you can write it as: output = new ObjectOutputStream(communicationSocket .getOutputStream()); output.writeObject(yourDataObject); Now, you can read this as so: while (listening) { try { Object currentObject = input.readObject(); if (currentObject != null && currentObject instanceof DataObject) { Point[] points = ((DataObject) currentObject).getPoints(); //Do something with points } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { listening = false; } }
Well, there are some points that you should be aware of, for example, the size of an int 32 or 64 bits, the byte order of the sending and the receiving machines, etc. Also, there should be a protocol to communicate both sockets, I mean, there should be a header in every packets send so that you know how much data you are going to received, I won't deal with that, I assume that you want to send and receive an array of 20 points. In this example it's assumed that both machines are 32 bits, i.e. an int is 4 bytes in size and that both machines use LITTLE_ENDIAN byte order. // To send an array of points use these two methods: public byte[] pointsToBytes(Point[] p, int numPts) { // 2 is for x and y and 4 is the size of an int in bytes ByteBuffer buff = ByteBuffer.allocateDirect(numPts * 2 * 4); buff.order(ByteOrder.LITTLE_ENDIAN); for (int i = 0; i < numPts; i++) { buff.putInt(p[i].x); buff.putInt(p[i].y); } return buff.array(); } public boolean sendData(Point[] pts, int size) { try { byte[] buffer = pointsToBytes(pts, size); mainSocket.getOutputStream().write(buffer, 0, buffer.length); return true; } catch (Exception e) { e.printStackTrace(); } return false; } // To receive an array of point use these two methods: public Point[] bytesToPoints(byte[] byteBuff, int numBytes) { ByteBuffer buff = ByteBuffer.wrap(byteBuff); buff.order(ByteOrder.LITTLE_ENDIAN); // 2 is for x and y and 4 is the size of an int in bytes int ptsInBuffer = numBytes / 2 / 4; Point[] pts = new Point[ptsInBuffer]; for (int i = 0; i < ptsInBuffer; i++) { pts[i].x=buff.getInt(); pts[i].y=buff.getInt(); } return pts; } public Point[] getData(int pointsToRead) { try { byte[] buffer = new byte[pointsToRead * 4 * 2]; int bytesRead = mainSocket.getInputStream().read(buffer, 0, pointsToRead*4*2); return bytesToPoints(buffer, bytesRead); } catch (Exception e) { e.printStackTrace(); } return null; }