I did not see any code that initialises the serial port. So it will still use the current settings as shown by the stty command line tool. You have to use tcsetattr to select the same basic settings as on the PIC (probably 8N1; baud rate seems to mach already), disable all kinds of flow control (software and hardware), and all additional features like echoing.
On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal. On error, -1 is returned, and errno is set appropriately. In this case it is left unspecified whether the file position (if any) changes.
read() will return zero when there are no data available. So you have either to clear your c variable before, or - better - check the return value:
int received = read(hComPort, &c, 1);
if (received == 1 && c >= 0x20 && c <= 0x7E)
data[cnt++] = c;
else if (received < 0)
// handle error here
Another option is setting blocking mode (attributes c_cc[VMIN] to non zero and c_cc[VTIME] to the timeout value). Then you will not get zero return values but still have to check for negative return values indicating timeout or other errors.
Question on how to error handle.
I am falling into the received < 0 but if I just ignore it and keep looking for chars, I get a complete, correct message. Is it safe to do that or should I clear the error? And How?
Thanks in advance
That is EGAIN (you can look it up in errno.h and get the corresponding error message with strerror(3) - Linux manual page[^] ) and in most cases (as here) not an error. You are just calling read again too fast (the next character has not been received so far).
To avoid this you can set a timeout value. Then the read() will block until data are available or a timeout occured.
You have to set it explicitly, there is no garbage collector or reference counts in C. The two pointers have no connection, so when you free x, pointer p still points to the original block of memory. You must be very careful to manage dynamic memory properly in C, and even in C++.
You have not a pointer to pointer. As Richard correctly pointed out, you have two independent pointers to the same block of memory; you have to explicitely set p = NULL;.
With a pointer to pointer the scenario would change:
char* x = (char*)calloc(sizeof(char),150);
char** p = &x;
x = NULL;
printf("%p\n", *p); // here *p is NULL