NewSoftwareSerial.write problem

I am trying to code a simple baud rate converter that converts a 19,200 baud source to a 38,400 destination. The data being passed is binary so I understand that I should be using the .write() to transmit it. I use the hardware serial for the input in case there are any buffering issues. The code is bi-directional in case there needs to be reverse communication later.

#include <NewSoftSerial.h>
#define rxPin 2
#define txPin 4

NewSoftSerial mySerial =  NewSoftSerial(rxPin, txPin);

void setup()
{  
  mySerial.begin(38400);
  Serial.begin(19200);  
  delay(5000);  
}

void loop()
{   
  if (mySerial.available())
  {        
    Serial.write(mySerial.read());
  }
  
  if (Serial.available())  
  {
    mySerial.write(Serial.read());    
  }
}

The problem is that I get the following error from the last line of code:

/arduino-0018/libraries/NewSoftSerialOld/NewSoftSerial.h:71: error: 'virtual void NewSoftSerial::write(uint8_t)' is private

error: within this context

Serial.write(Serial.read()); works OK.
mySerial.write(Serial.read()); doesn’t.

Should I use mySerial.print() instead of mySerial.write() or will this ‘ASCII-ise’ my binary data stream? Should I use extra parameters?

While I’ve got your attention, what is the difference between the following:

mySerial.print((char)Serial.read());

mySerial.print(Serial.read());

mySerial.print(Serial.read(), BYTE);

Hi Lemming,

The "sanctioned" way to write binary data is to use this syntax:

mySerial.print(Serial.read(), BYTE);

The reason is that even though read() reads data one byte at a time, the return value from read() is of type int. The "BYTE" qualifier instructs print() to send it in binary form, but without it, the default is to print an int in as DEC, which means to "ASCII-ize" it.

In other words, you do this:

int c = 'A';
mySerial.print(c);

you may be surprised to see the string "65".

Clear?

Mikal

Thanks Mikal,

I understand your explanation and will use this method.

However, if .print() can handle everything, what is the purpose of .write()?

Also, what is the difference between

mySerial.print((char)Serial.read());

and

mySerial.print(Serial.read());

Also .... if .read() returns an int, isn't this signed and therefore the first bit is treated as a sign. If the two bytes (of the int) are being filled with binary data how does the language know to treat the first bit as part of the data and not a sign?

You really shouldn't be using

mySerial.print(Serial.read());

unless this is part of a if(Serial.available() > 0) block.

The read function returns one byte of data. It returns that byte in an int, though, so that it can set the sign bit, in case the read function was called when there was no data to read.

You should be calling Serial.read() only after calling Serial.available(), and storing the return value in a byte variable.

The print function is overloaded, too, so a call to print with one argument type may result in another call to print for another type. For instance, is Serial.print is called to print an int, the Serial.print function to print a long is called, which calls an private method, printNumber, which converts the number to a string, and calls write to output the string.

The Serial.print() function calls Serial.write() for character variables and character arrays.

Thanks PaulS,

That sheds some more light on the issue, however I am confused by your comment -

You really shouldn't be using
Code:
mySerial.print(Serial.read());

unless this is part of a if(Serial.available() > 0) block.

I have been using:

if (mySerial.available())
  {        
    Serial.print((char)mySerial.read());
  }
  
  if (Serial.available())  
  {        
    mySerial.print((char)Serial.read());
  }

Which I thought was the same thing.

Also I am still confused as when to use Serial.write and when to use Serial.print.

I thought that .write() was for binary data. I am using binary data yet I am advised to use .print().

When would you use Serial.write()?

if .read() returns an int, isn't this signed and therefore the first bit is treated as a sign. If the two bytes (of the int) are being filled with binary data how does the language know to treat the first bit as part of the data and not a sign?

The first (most-significant) byte is the sign - if it's zero, then the second (least-significant) byte is a valid character.
If it's 0xFF, then the value is negative. The only negative value returned by "Serial.read" is -1, or 0xFFFF.

In your example, the Serial.print of the value from Serial.read IS in a if(Serial.available() > 0) block, so you are OK.

Just to be clear, Serial.available() returns the number of bytes available to read, not just a flag that says whether there is data to read. Any non-zero value evaluates to true, so your if test and mine are the same. I prefer mine, though, because it is clearer (to me) that Serial.available returns an int rather than a boolean.

It’s also easier to modify mine to check for a specific minimum number of characters.

Also I am still confused as when to use Serial.write and when to use Serial.print.

I thought that .write() was for binary data.

It is.

I am using binary data yet I am advised to use .print().

If you are going to use Serial.print to write binary data, you need to use the BYTE flag, which causes the Serial.print function to call the Serial.write function for the first argument.

Or, you can skip the overhead of a function call, and use Serial.write directly.

[edit]I was basing all my comments on the behavior of the serial print functions on the hardware serial behavior, which relies on the Print class to actually perform the output. I just noticed that your subject line specifically refers to NewSoftSerial.

The NewSoftSerial class also uses the Print class to actually perform the output, except that it overloads the write method, which is what all the print methods ultimately use to make output occur.[/edit]

Thanks guys.

The fog has lifted.

The first (most-significant) byte is the sign - if it's zero, then the second (least-significant) byte is a valid character.
If it's 0xFF, then the value is negative. The only negative value returned by "Serial.read" is -1, or 0xFFFF.

Just to be perfectly accurate, it is only the highest order bit that is the sign, but otherwise this statement is correct.

As for write(), it always seemed to me that this function was part of the plumbing and not really intended for direct use. As was noted, it's the function that gets overloaded by Print derivatives, and is used by all the print and println variants to do their work. It's not even documented in the SoftwareSerial help. As such, I decided to make NewSoftSerial's write() method private, which is why it didn't work for you, Lemming. I'd be curious to hear arguments on the other side.

Mikal

I was wondering if it is materially more efficient to use the write() rather than using print() that then has to go off and call the write()?

Also, as a newbie, I couldn't figure out why Serial.write() worked and NewSoftwareSerial.write() did not. Although coming from different stables, I thought that NewSoftwareSerial would have similar methods to its hardware equivalent. Not a compelling reason for change but just a matter of consistency for the uninitiated.