0

I am doing some embedded programming using Python for the PC side and C for a controller side. Serial reading in python is easy in a sense that you can read a certain amount of bytes, but I am having ,,problems,, with reading in C. Is it possible to read, for example 5 bytes, without waiting for the 'EOL' character('\n' or 0x0a)? For now, I am adding '\n' at the end of every buffer transmitted from PC to controller but I would like to get rid of that since there is around 1 in 255 chance of failing the transmission (for every byte sent) if byte gets the value b'\x0a' and I always know the number of bytes I should expect from the value of the first byte. Thanks in advance everyone :-)

this is a part of the function

void recv(int port){          //function to receive buffer
//we are gonna receive a message and since this is an echo type of program we will signal
//signal thread to loop it back around
printf("Opened connection on port:%d \n",port);
while(1){
    if(stop){
        break;
    }
    //values are simulated with rand(), there is 10% movement to fall out of range
    voltage=rand_value(VOLTAGE_MIN-100000,VOLTAGE_MAX+100000);
    current=rand_value(CURRENT_MIN-100000,CURRENT_MAX+100000);
    temperature=rand_value(TEMP_MIN-30,TEMP_MAX+30);

    int nread;
    ioctl(port, FIONREAD, &nread);
    if (nread > 0) {
        memset(buf,0,sizeof(buf));
        int n=read(port,&buf,nread);  //blocking operation, it waits for "\n"
        /* for(int i=0; i<BUF_LEN; i++){
            //printf("Msg received: %s",buf);
            printf("buf index %d, data 0x%x \n", i, buf[i]);
        } */
        req=buf[0];                     //here we have command ID + data ID
                                        //                2bit        6bit
        printf("Bytes received: %d, req= 0x%x\n",n,req);    //prints the register and count of data received (always gets one above the actual data!)
        switch (((req&0b11000000)>>6)){     //SWITCHES COMMAND ID-S

this is opening the port in main

   int port=open("/dev/ttyPS1",O_RDWR);

in between these 2 goes termios setup

    recv(port);

so even tho i use number of available bytes it completely ignores that and waits for the 0x0a value

  • 2
    You might mean EOL (end of line, in some circles), not EOF... Have you looked into `fread()`?? – Fe2O3 Aug 10 '22 at 10:38
  • It would help to show the code instead of describing it. Also, as you are asking about C, it does not matter whether the other end of the serial line is programmed using Python. You should only add relevant tags. – Gerhardh Aug 10 '22 at 10:53
  • you can even use fgetc in a loop – stark Aug 10 '22 at 10:59
  • @Fe2O3 i have, but I don't think it would work since I don't have a file stream but a serial port – Aleksa Rajkovic Aug 10 '22 at 11:19
  • @stark don't think so, I have a serial port, not a file stream – Aleksa Rajkovic Aug 10 '22 at 11:25
  • Because you use `open`. If you used `fopen` you could use `fgetc`. – Gerhardh Aug 10 '22 at 11:42
  • There is nothing in the code that would wait for a `\n`. But the code you show is very incomplete. Not even a single function complete and many variable definitions missing. – Gerhardh Aug 10 '22 at 11:45
  • 1
    What makes you think that you **need** EOL or EOF? -- Please provide a [mre]. – the busybee Aug 10 '22 at 12:13
  • "*I always know the number of bytes I should expect from the value of the first byte*" -- Then that sounds like a binary message protocol, which means that you cannot use canonical reads (and wait on EOL). That is a scheme waiting to misbehave. BTW you are citing my post (the accepted answer) in your "answer" below. – sawdust Aug 10 '22 at 22:59
  • @sawdust Yes lol,some of the comments and answers there helped a lot, and yes it is binary message protocol basically :-), got it as a task for the summer internship. – Aleksa Rajkovic Aug 11 '22 at 08:00

2 Answers2

0

You can use the read system call (or fread for FILE*).

Usage with file descriptor:

int fd = STDIN_FILENO; // or your stream
int max_len = 10;
char buffer[max_len];
int actual_len = read(fd, buffer, max_len);
if (actual_len < 0) {
    exit(1); // error
}

Usage with FILE*:

FILE* file = stdin; // or your stream
int max_len = 10;
char buffer[max_len];
int actual_len = fread(file, buffer, max_len);
if (actual_len < 0) {
    exit(1); // error
}

The read systemcall reads up to n bytes into a buffer and returnes the number it could read. So if your stream has "hello" (without null terminator) as content, it will return 5.

And also I think you missunerstood EOF. EOF isn't actually a transmitted byte, it is a placeholder for stdio to signal that no more bytes were availible. Depending on the settings of the stream it can happen that you never get a EOF and the process just blocks until the stream is closed.

Tenobaal
  • 637
  • 1
  • 16
  • Thats how i used for now, BUT, the problem is that this way still requires using EOL character (EOF was a mistake), I will update the post with some code now. – Aleksa Rajkovic Aug 10 '22 at 11:27
0

So from thinking about things people said in the comments and reading a recommended question this post about buffer reading I made it work pretty much as I was trying for days

I used this time flags where BUF_LEN is defined constant of the max possible buffer received What I don't like about this solution is that it is load depended but it is what it is.

    tty.c_cc[VTIME] = 2;    // Wait for up to 0.2s (2 deciseconds), returning as soon as any data is received.
    tty.c_cc[VMIN] = BUF_LEN;

This is how communication in terminals looks like