简体   繁体   中英

why is C++ Serial read function pausing program and piling data?

I have an arduino transmitting the following string "<123456789ABC>". A seperate C++ program is able to open the serial port connected to the arduino and read this data however it seems to read the string dozens of times and outputs them at once together then freezes the program in between reads.

The function for reading incoming serial port data:

std::string SerialPort::readSerialPort(int wait_time) {

    DWORD bytes_read;
    char inc_msg[1];
    std::string complete_inc_msg;
    bool began = false;

    // Timer
    unsigned long start_time = time(nullptr);

    ClearCommError(this->handler, &this->errors, &this->status);

    // after wait_time elapsed
    while ((time(nullptr) - start_time) < wait_time) {

        if (this->status.cbInQue > 0){

            if (ReadFile(this->handler, inc_msg, 1, &bytes_read, NULL)) {

                // < and > delimiters

                if (inc_msg[0] == '<' || began) {
                    began = true;

                    if (inc_msg[0] == '>') {
                        return complete_inc_msg;
                    }

                    if (inc_msg[0] != '<')
                        complete_inc_msg.append(inc_msg, 1);
                }
            }
            else
                return "Warning: Failed to receive data.\n";
        }
    }
    return complete_inc_msg;
}

The function is called in the main program so:

std::string readResult = gyroport->readSerialPort(1);
cout << readResult << "\n";

gyroport is just an object of the serial port class that contains all the serial com functions ( init , read , write etc.)

Console output:

123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC

123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC

123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC
123456789ABC

At every break between the 'chunks' the entire program freezes for the duration of wait_time, afterward a chunk of messages is spat out instantaneously before freezing again.

Why is this happening and how can I modify the read function to act on each incoming string as it arrives without pausing the entire program?

You probably want to set the read timeout for the serial port. Here's a really simplified terminal program that shows the basics of how it's done.

#include <stdio.h>
#include <conio.h>
#include <string.h>

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

void system_error(char *name) {
// Retrieve, format, and print out a message from the last error.  The 
// `name' that's passed should be in the form of a present tense noun 
// (phrase) such as "opening file".
//
    char *ptr = NULL;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        0,
        GetLastError(),
        0,
        (char *)&ptr,
        1024,
        NULL);

    fprintf(stderr, "\nError %s: %s\n", name, ptr);
    LocalFree(ptr);
}

int main(int argc, char **argv) {

    int ch;
    char buffer[64];
    HANDLE file;
    COMMTIMEOUTS timeouts;
    DWORD read, written;
    DCB port;
    HANDLE keyboard = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode;
    char port_name[128] = "\\\\.\\COM3";
    char init[] = "";

    if ( argc > 2 )
        sprintf(port_name, "\\\\.\\COM%s", argv[1]);

    // open the comm port.
    file = CreateFile(port_name,
        GENERIC_READ | GENERIC_WRITE,
        0, 
        NULL, 
        OPEN_EXISTING,
        0,
        NULL);

    if ( INVALID_HANDLE_VALUE == file) {
        system_error("opening file");
        return 1;
    }

    // get the current DCB, and adjust a few bits to our liking.
    memset(&port, 0, sizeof(port));
    port.DCBlength = sizeof(port);
    if (!GetCommState(file, &port))
        system_error("getting comm state");
    if (!BuildCommDCB("baud=19200 parity=n data=8 stop=1", &port))
        system_error("building comm DCB");
    if (!SetCommState(file, &port))
        system_error("adjusting port settings");

    // set short timeouts on the comm port.
    timeouts.ReadIntervalTimeout = 1;
    timeouts.ReadTotalTimeoutMultiplier = 1;
    timeouts.ReadTotalTimeoutConstant = 1;
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1;
    if (!SetCommTimeouts(file, &timeouts))
        system_error("setting port time-outs.");

    // set keyboard to raw reading.
    if (!GetConsoleMode(keyboard, &mode))
        system_error("getting keyboard mode");
    mode &= ~ ENABLE_PROCESSED_INPUT;
    if (!SetConsoleMode(keyboard, mode))
        system_error("setting keyboard mode");

    if (!EscapeCommFunction(file, CLRDTR))
        system_error("clearing DTR");
    Sleep(200);
    if (!EscapeCommFunction(file, SETDTR))
        system_error("setting DTR");

    if (!WriteFile(file, init, sizeof(init), &written, NULL))
        system_error("writing data to port");

    if (written != sizeof(init))
        system_error("not all data written to port");

    // basic terminal loop:
    do {
        // check for data on port and display it on screen.
        ReadFile(file, buffer, sizeof(buffer), &read, NULL);
        if (read)
            WriteFile(screen, buffer, read, &written, NULL);
    
        // check for keypress, and write any out the port.
        if ( kbhit() ) {
            ch = getch();
            WriteFile(file, &ch, 1, &written, NULL);
        }
    // until user hits ctrl-backspace.
    } while ( ch != 127);

    // close up and go home.
    CloseHandle(keyboard);
    CloseHandle(file);
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM