Serial write of byte > 127

I am trying to write a byte of value 160 over a serial connection, to a Java application.

byte id = 128;
Serial.write( id);

Anything up to a value of 127 works fine, otherwise the byte is received as 65533, which I understand means invalid character.

The arduino spec says that a byte is "an 8-bit unsigned number, from 0 to 255" so not sure why this isn't working.

Here's the Java code and output,

int id = input.read();
LOG.info("id " + id);

"INFO: id 65533"

The Java spec says of this method "The character read, as an integer in the range 0 to 65535", so what am I doing wrong?

If you are sending the data as a byte, why are you storing it in an int in the Java app?

It's a while since I used JRuby but I think this is a Java problem. IIRC Java treats bytes as signed quantities.

Within your Java program I think you need to AND 0xFF with the received byte. But that may only be relevant for JRuby.

...R

PaulS: If you are sending the data as a byte, why are you storing it in an int in the Java app?

The read() method to BufferedReader reads a single character from the input stream and puts it in an integer. This should allow characters up to a value of 65535 which should be more than sufficient for my needs.

Robin2:
It’s a while since I used JRuby but I think this is a Java problem. IIRC Java treats bytes as signed quantities.

Within your Java program I think you need to AND 0xFF with the received byte. But that may only be relevant for JRuby.

Wouldn’t that be ANDing 65533 and 256, i.e. 1111111111111101 and 11111111? Which wouldn’t change the value?

PerceptualRobots: Wouldn't that be ANDing 65533 and 256, i.e. 1111111111111101 and 11111111? Which wouldn't change the value?

It's a long time since I wrote the JRuby program and the suggestion I made is what I think solved the problem. Have you tried it?

If I have not got it quite correct you at least have an idea to try Googling.

...R

  1. @Robin2 - Forget JRuby.

  2. @PaulS Java's read methods normally follow the same rules as Serials read method and stdio's getc and streams read, in that they return the byte/char OR -1 (no data/EOF)

  3. @OP this is a classic case of why you should post all your code.

So what java class is input an instance of ?

Mark

holmes4: 1. @Robin2 - Forget JRuby.

That is probably the problem - I already have :)

So what java class is input an instance of ?

This is what I detest about Java :)

...R

The read() method to BufferedReader reads a single character

Aha. So, you REALLY need to look at the range of values that can be stored in a char in Java. On the Arduino a char holds -128 to 127, NOT 0 to 256. You are OBVIOUSLY using the wrong process for reading bytes.

PaulS: Aha. So, you REALLY need to look at the range of values that can be stored in a char in Java. On the Arduino a char holds -128 to 127, NOT 0 to 256. You are OBVIOUSLY using the wrong process for reading bytes.

As I put in my first post, "The character read, as an integer in the range 0 to 65535".

From arduino I am sending a byte not a char,

    byte b = 160;
    Serial.write(b);

of which the arduino spec says, "A byte stores an 8-bit unsigned number, from 0 to 255".

So why is the Java read the wrong process?

holmes4:
So what java class is input an instance of ?

Here’s how “input” is created.

input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));

Maybe I should be using something else?

The data is being sent as a byte and is being received as a byte because physically, nothing else is possible. It is only after that that it is converted to an int.

Try receiving it as a byte in Java and when you have that working properly you can convert the "good" byte to an int.

...R

I've managed to resolve it by using,

        input = new BufferedInputStream(serialPort.getInputStream());

The "int read()" method "Returns: the next byte of data, or -1 if the end of the stream is reached."

So I guess the other read method was only allowing text characters.

Thanks for the help.

So I guess the other read method was only allowing text characters.

The other method was returning a pointer to a char array. This one returns a pointer to a byte array. Since chars are only -128 to 127, you could not expect to get a value of 160.

I can not reproduce the problem you are seeing.

Arduino code

void setup() {
  Serial.begin(115200);
}
byte val = 120;
unsigned long lastOut;
void loop() {
  unsigned long topLoop = millis();
  if (topLoop - lastOut > 100) {
    Serial.write(val++);
    lastOut = topLoop;
  }
}

Processing code (this is Java, isn’t it?)

import processing.serial.*;

Serial mySerial;
boolean newVal = false;
String echoString;

void setup() {
  mySerial = new Serial(this, "COM33", 115200);  // <- adjust
}
void draw() {
  if (newVal) {
    println(echoString);
    newVal = false;
  }
}
void serialEvent(Serial p) {
  echoString = "read ";
  while (p.available() > 0) {
    int val = p.read();
    echoString +=  val + ", ";
  }
  newVal = true;
}

output

read 120, 
read 121, 
read 122, 
read 123, 
read 124, 
read 125, 
read 126, 
read 127, 
read 128, 
read 129, 
read 130, 
read 131, 
read 132, 
read 133, 
read 134, 
read 135, 
read 136, 
read 137, 
read 138, 
read 139, 
read 140, 
read 141, 
read 142, 
read 143, 
read 144, 
read 145, 
read 146, 
read 147, 
read 148, 
read 149,

Processing code (this is Java, isn't it?)

Yes, but you are not using the same class(es) as OP. Just like C#, Java has several classes for reading data from streams, depending on whether the stream is binary data or ASCII data, whether the data is of determinate length, or not (reading from a file is; reading from a serial port is not), etc.

Some classes return pointers to bytes. Some classes return pointers to chars. Using the right class to read the right kind of data is important.