-1

I am trying to read some data from a text file and writing it to the ttyUSB* socket id. I am using Hi3520d Dvr. I have it's RS485 port connected to a "RS485 to RS232 converter". This converter is connected to the PC through a USB port.

The text file is getting read properly to the buffer, but while writing last few lines of the text is not transmitting. This is happening with file with size more than 4.5kb exactly and without usleep() function.

I am using minicom on linux terminal to display both read and written text. Thanks in advance for looking into this.

#include <stdio.h>  
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define Bdrate B9600

int Intserial(char *dev, int Baudrate)
{
    //printf("Insterial func\n");  
    int sid;
    int iDebug = -1;
    struct termios serial_struct;
    sid = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
    if (sid > 0)
    {
        memset(&serial_struct, 0, sizeof(serial_struct)); /* clear the new struct */
        serial_struct.c_cflag = Baudrate | CS8 | CLOCAL | CREAD;
        serial_struct.c_iflag = IGNPAR;
        serial_struct.c_oflag = 0;
        serial_struct.c_lflag = 0;
        serial_struct.c_cc[VMIN] = 0; /* block untill n bytes are received */
        serial_struct.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
        iDebug = tcsetattr(sid, TCSANOW, &serial_struct);
        if (iDebug < 0)
        {
            printf("Err 0\n"); //Unable to set serial port parameters
            return (0);
        }
    }
    else
    {
        printf("Err 1\n");  //Serial port not open
        return (0);
    }
//printf("sid is %d \n",sid);
    return (sid);
}

int main()
{
    int sid1 = -1, size = 0, i = 0, x, w;
    size_t ln;
    FILE *fd;
    char buf[2233];
    fd = fopen("h.txt", "r");

    if (fd)
    {
        sid1 = Intserial("/dev/ttyAMA1", Bdrate); //RS485 port of Hi3520d
        if (sid1 > -1)
        {
            system("himm 0x200F004C 0"); // commands transmitting and recieving
            system("himm 0x201A0400 1");
            system("himm 0x201a0004 1");

            while (!feof(fd))
            {

                memset(buf, 0, sizeof(buf));
                fread(buf, sizeof(buf), 1, fd);
                printf("%s", buf);
                write(sid1, buf, sizeof(buf));
                usleep(5);
            }
            getchar();
        }
        else
            printf("com port cant open\r\n ");

        fclose(fd);
        close(sid1);
    }
    else
        printf("File cant open\r\n");

    printf("task completed............\r\n");
}
LPs
  • 16,045
  • 8
  • 30
  • 61
  • `fread` does not terminate your buffer with null-terminator. `printf("%s",buf); ` invokes undefined behavior. – LPs Dec 20 '16 at 13:37
  • [why-is-while-feof-file-always-wrong](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – LPs Dec 20 '16 at 13:44
  • (1) The *termios* configuration is low quality. See [Setting Terminal Modes Properly](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC237) and [Serial Programming Guide for POSIX Operating Systems](http://www.cmrr.umn.edu/~strupp/serial.html) (2) Serial terminal is opened for non-blocking mode. Then **write()** syscalls are issued without checking the return values to confirm that data was accepted. IOW you're possibly silently ignoring errors. – sawdust Dec 21 '16 at 08:29

2 Answers2

1

You have to observe return value of fread for number of bytes read by fread function. the actual read size may not equal to bytes requested, also you have to pass number of bytes read by fread (as valid bytes in buffer) to write function as number of bytes to write.

The code should be something like this

memset(buf,0,sizeof(buf));
size_t bytesRead = fread(buf,sizeof(buf),1,fd);
if(bytesRead > 0)              
    write(sid1,buf, bytesRead);

Also as LPs said, fread doesn't end buffer with termination character, so passing buffer filled by fread to printf("%s") will be undefined behavior

e.jahandar
  • 1,715
  • 12
  • 30
  • It's hypocritical to preach that the return value should be checked for a **fread()**, and then provide code that doesn't check the return value of a (problematic non-blocking) **write()**. – sawdust Dec 21 '16 at 08:54
  • Tried your suggestion. But now it's transmitting just 2 bytes and going to "Transfer done" statement. Looks like only 1byte is reading. My file size is 4466bytes. –  Dec 21 '16 at 09:15
0

There are numerous issues with your code, but the salient cause of "the text is not transmitting" is probably the failure to check the return value of

write(sid1, buf, sizeof(buf));

Because the serial terminal was opened in non-blocking mode, each write() will return immediately, before the data has been actually transmitted.
Since the serial terminal is configured for a rather slow 9600 baud, the data could be queued up in the line discipline buffer and other intermediate buffers.

The line discipline buffer is typically 4096 bytes long.
Assuming that the fread() operations are always successful (which you seem to have verified), then the second iteration of the write() of 2233 bytes could potentially saturate the line discipline buffer, and return with a short write return value (which would be ignored).

The third iteration of the write(), if it's quick enough, could then be outright rejected with a return value of -1 and an errno of EAGAIN to indicate that the write would block.
This error condition would be silently ignored, and this 2233 bytes of data will never be transmitted.

This seems to correlate perfectly with your observation of "last few lines of the text is not transmitting ... with file with size more than 4.5kb exactly and without usleep() function."


ADDENDUM

Revised code for blocking mode, proper terminal setup, and checking of return values is shown below.
A corrected version of @e.jahandar's suggestion and comments from @LPs are also incorporated.

...

    sid = open(dev, O_RDWR | O_NOCTTY);
    if (sid < 0) {
        printf("Err 1\n");  //Serial port not open
        return (-1);
    }
    if (tcgetattr(sid, &serial_struct) < 0) {
        printf("Err 2\n");
        return (-2);
    }
    cfsetospeed(&serial_struct, (speed_t)Baudrate);
    cfsetispeed(&serial_struct, (speed_t)Baudrate);

    cfmakeraw(&serial_struct);

    serial_struct.c_cc[VMIN] = 1;
    serial_struct.c_cc[VTIME] = 10;

    serial_struct.c_cflag &= ~CSTOPB;
    serial_struct.c_cflag &= ~CRTSCTS;    /* no HW flow control? */
    serial_struct.c_cflag |= CLOCAL | CREAD;

    if (tcsetattr(sid, TCSANOW, &serial_struct) < 0) {
        printf("Err 3\n"); //Unable to set serial port parameters
        return (-3);
    }

...

#define BUFSIZE  2233

    char buf[BUFSIZE + 1];

...

    size_t frv;
    ssize_t wrv;

...
    do {
        frv = fread(buf, 1, BUFSIZE, fd);
        buf[frv] = 0;  /* terminate string for printf */
        if (frv > 0) {             
            wrv = write(sid1, buf, frv);
            if (wrv < frv) {
                /* handle error or short write */
            }
        } else
            break;
    } while (1);

...
sawdust
  • 16,103
  • 3
  • 40
  • 50
  • sawdust thank you for your suggestion. I am looking into it. For a file size of 4488bytes, i used a buffer of 66 bytes ie buf[66] and usleep(1). This is giving me the perfect output. –  Dec 21 '16 at 13:05
  • while using buf[66] for 4488 byte file. The while loop is running 68 time. Out of which 67 times the fread returns 1 and write is returning 66. But in the last one, ie 68th time it's fread is returning 0 and write is returning 66. –  Dec 22 '16 at 12:21
  • Also when using a "buf" of higher value, the same thing is happening for fread and write is transmitting some small value. For example if its is buf[102]. The last while loop is giving fread as 0 and write as 47. –  Dec 22 '16 at 12:24
  • sawdust i looked into your suggestion, but i was unable to understand how to make it in blocking mode. Since i am beginner, could you please guide me through it. –  Dec 22 '16 at 12:27
  • (1) *"while using ..."*, *" when using ..."* -- Programming languages are used because natural languages are ambiguous. Without actual code to review, a summary of symptoms is worthless. Edit you question to append this info. (2) Typically a simple `sid = open(dev, O_RDWR | O_NOCTTY);` should work for blocking mode. – sawdust Dec 22 '16 at 20:58