0

The code below processes incoming RS232 serial data 1 character at a time and works fine.

However the incoming serial feed in my use case does not contain any CR or LF characters which make further delimiting/processing to a piped program difficult. The end delimiter is always a ! exclamation character instead of a CR or LF. e.g. 123456!abcdef!qwerty!

Is there a way to modify the code below to substitute the ! character to a CR (carriage return)? For example, is the incoming string is 123456abcdef! then the program should replace the ! with a CR so it outputs 123456abcdef<carriage return>

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringSerial.h>

int main ()

  for (;;)
  {
    putchar (serialGetchar (fd)) ;
    fflush (stdout) ;
  }
}
Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
stackman
  • 3
  • 1

3 Answers3

2

You can do it in the same single char basis as:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringSerial.h>

int main ()

  for (;;)
  {
    char c = serialGetchar (fd);
    putchar (c == '!' ? '\r' : c) ;
    fflush (stdout) ;
  }
}

Normally it is used new line with carriage return, in that case would be:

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringSerial.h>

int main ()

  for (;;)
  {
    char c = serialGetchar (fd);
    if (c == '!')
    {
        putchar ('\r') ;
        putchar ('\n') ;
    }
    else
    {
        putchar (c) ;
    }
    fflush (stdout) ;
  }
}
Lisandro
  • 89
  • 1
  • 4
  • `c == '!' ? '\r' : c` introduces implicit promotion to `int`, which isn't desired. Use an `if` statement to avoid this (and make the code easier to read at the same time). – Lundin Sep 26 '17 at 14:36
  • 3 on-line sources indicate `serialGetchar()` returns `int`. `putchar()` tales an `int`. Recommend `int c = serialGetchar (fd);`. – chux - Reinstate Monica Sep 26 '17 at 20:08
  • thanks so much to everyone for your answers. the problem is solved. – stackman Sep 27 '17 at 02:19
  • `putchar()` nominally takes an `int` but only the low-end byte is used: the `int` is cast to an `unsigned char`. I would assume `serialGetchar()` does the opposite: returns an `unsigned char` cast to an `int`. Similarly, the statement `c == '!' ? '\r' : c` implicitly promotes everything to `int` because character literals are `int`s in c, but this isn't actually a problem because the promotion consistently discards everything but the low-end byte. It's not as if 1 in 256 times the cast turns `0xff` into `0x00` due to integer overflow. The cast behaves absolutely predictably. – sig_seg_v Oct 04 '17 at 01:36
  • @Lundin any valid argument passed to `putchar()` is promoted to `int`. I completely fail to see why this "isn't desired". – sig_seg_v Oct 04 '17 at 01:41
1
char c = serialGetchar (fd)) ;
c = (c == '!') ? '\r' : c ;
putchar (c) ;

Or, put another way,

char c = serialGetchar (fd)) ;
if (c == '!') c = '\r' ;
putchar (c) ;
sig_seg_v
  • 570
  • 4
  • 15
  • The second version is better since it is easier to read and doesn't contain any implicit promotion weirdness. Thanks to implicit promotion, version 1) tries to store an `int` inside a `char` which isn't really helpful. – Lundin Sep 26 '17 at 14:33
  • Simple ternaries aren't difficult to read... https://stackoverflow.com/a/160295/4024569 https://stackoverflow.com/questions/694814/ternary-operator-bad-or-good-practice – sig_seg_v Sep 26 '17 at 17:29
1

You can replace the whole code with

for(;;)
{
  char c = serialGetchar (fd);
  if(c == '!')
  {
    putchar('\n');
  }
  else
  {
    putchar(c);
    fflush (stdout);
  }
}

It isn't necessary to flush stdout after writing a '\n' to it - doing this will trigger a flush automatically. So as a minor optimization, this code doesn't flush stdout twice upon finding a '!'.

Lundin
  • 195,001
  • 40
  • 254
  • 396