0

I'm using SoftwareSerial to communicate with a Sigfox module. Documentation for the read function assigns its value to a char. However using it I get mangled characters and also have read in other question that I should assign it to int as it can return -1 for no data and [0;255] for received character.

This is my basic troubleshooting example:

#include <SoftwareSerial.h>
SoftwareSerial Sigfox(11,10);

void setup() {
  Serial.begin(9600); // HW serial
  Sigfox.begin(9600); // SW serial --> sigfox
}

void loop() {
  if(Sigfox.available()) {
    int c = Sigfox.read();
    Serial.write(c);
  }
  if(Serial.available()) Sigfox.write(Serial.read());
}

When c is char, I get -5 instead of OK. Also other output is mangled. When c is int, it receives the data OK.

My question is - why they use char in the example in documentation? Why is char signed in Arduino?

I want to read the entire line of text from serial port and store it into array. How to define that array? I have found an example on web that uses char buffer[32], but then again I get mangled data when I assign to it. If I use array of byte/int/unsigned char, I can't print it as Serial.write(SF_buffer); won't compile because of no matching function for call to 'write(unsigned char [32])'.

So what variable types should I use to receive and store the text from SoftwareSerial correctly?

Here is my function for reading the whole line:

unsigned char SF_buffer [32]; // max length of line to read from serial
bool SigfoxReadine() { // return true when whole line was received and is in buffer
  static int SF_cnt=0;
  while (Sigfox.available()) {
    int c = Sigfox.read();
    SF_buffer[SF_cnt++] = c;
    if ((c == '\n') || (SF_cnt == sizeof(SF_buffer)-1)) {
       SF_buffer[SF_cnt] = '\0';
       SF_cnt = 0;
       return(true);
    }
  }
  return(false);
}

UPDATE:

Trying readBytesUntil - the same result, but I have found that issue is only when I send data to module using println as in this example:

#include <SoftwareSerial.h>
SoftwareSerial Sigfox(11,10);

void setup() {
  Serial.begin(9600); // HW serial
  Sigfox.begin(9600); // SW serial --> sigfox
  Sigfox.println("AT$I=11");
}

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

void SF_read() {
  if (Sigfox.available()) {
    char buff[32];
    int l = Sigfox.readBytesUntil('\n', buff, sizeof(buff));
    if (l > 0 && buff[l - 1] == '\r') {
      l--; // to remove \r if it is there
    }
    buff[l] = 0; // terminate the string
    Serial.println(buff);
  }
}

The response to first command (in setup) is mangled. The response to the same AT command manually written into serial monitor (and sent to module via Sigfox.write in loop) is OK.

ӂ*⸮FBB1E27EE7

3430E2FBB1E27EE7

Also maybe I'm little lost in when to use print and when write... Example says to use write() to send back the char that was read(). Juraj's response uses println() to print the null-terminated buffer. What is the difference when I write/println this buffer?

  • refer to this when dealing with char data type ... asciitable.com – jsotola Oct 3 at 23:11
  • yes, using int data type is advisable ... if you use byte data type, then there is a conflict between data and an error flag ... a -1 is equivalent to hex 0xff, which is decimal 255 .... for int type, the decimal 255 is represented as 0x00ff and -1 is represented as 0xffff ... no conflict between those two .... please note that only a single byte is transmitted over serial ... the two byte int is created by the serial library so that your sketch has a way of receiving an error status from the library – jsotola Oct 3 at 23:22
  • Serial.write(SF_buffer, length); or for null terminated char array Serial.print(SF_buffer); – Juraj Oct 4 at 7:10
  • @Juraj if SF_buffer is char type, I get mangled output (SF_buffer[SF_cnt++]=c;). How to assign the int c into the char array correctly? – Marki555 Oct 4 at 7:26
  • use byte. does the devices send characters with ascii codes above 127? – Juraj Oct 4 at 7:28
1

Last test showed it mangles data only when using println() and doesn't depend on the char type. Then I remembered something about CRLF in the Sigfox datasheet:

Is recommended to use full duplex UART. In case of using half duplex, AT commands has to be ended only with one of ‘\r’ or ‘\n’ not both. Because if you send “AT\r\n” the Sigfox devkit starts sending “OK” instantly after it receive ‘\r’, but microcontroller is still sending byte ‘\n’.

SoftwareSerial is in fact half-duplex only (although I didn't find it in the reference documentation) and println() sends both '\r' and '\n', so while sending the later, Sigfox module is already trying to send back the answer, which gets mangled by SoftwareSerial.

Feel free to add your answer to explain why char is signed in Arduino and when to use print() and when write() with serial port.

2

I like the readBytes or readBytesUntil function. It doesn't end on a small gap between received bytes and fills the buffer. This functions are blocking with timeout, but if read some other device the input is usually fast and terminated reliably.

example for readBytesUntil:

if (Serial.available()) {
  char buff[32];
  int l = Serial.readBytesUntil('\n', buff, sizeof(buff));
  if (l > 0 && buff[l - 1] == '\r') {
    l--; // to remove \r if it is there
  }
  buff[l] = 0; // terminate the string
  Serial.println(buff);
}
  • does readBytes exist also for SoftwareSerial? Documentation mentions it only for Serial – Marki555 Oct 4 at 9:48
  • it is in the Stream base class – Juraj Oct 4 at 9:48
  • @Marki555, did it help? – Juraj Oct 4 at 19:14
  • testing... seems more strange now :) the issue from yesterday now seems to exist only when sending data to via Sigfox.println and not when using Sigfox.write... – Marki555 Oct 4 at 20:46
  • edited the question with new findings – Marki555 Oct 4 at 21:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.