0

I keep trying to write to a gantry motor via COM Serial Port in C++ and the device doesn't perform the command and returns random symbols.

This should move the gantry arm on a machine when it's working correctly and return the position of the arm through the read function and return the position of the arm. When I place a ComEventWait or whatever it doesn't stop waiting.

main.cpp

#include <iostream>
#include "../../../../Documents/Development/proteinmaker6channel/ProteinMaker/device_connection.h"
int main()
{
    DeviceConnection dc = DeviceConnection();

    dc.performWrite("XEXSULF");
    dc.performWrite("YEXSULF");
    dc.performWrite("ZEXSULF");

    dc.performWrite("XEXHHLF");
    dc.performWrite("YEXHHLF");
    dc.performWrite("ZEXHHLF");
}

device_connection.cpp

#include "device_connection.h"
#include<windows.h>
#include<stdio.h>
#include <list>
#include <string>
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include <assert.h>
#include <stdio.h>
using namespace std;


DeviceConnection::DeviceConnection()
{
}

void DeviceConnection::open(std::string portName)
{
    wchar_t pszPortName[10] = { 0 }; //com port id
    wchar_t PortNo[20] = { 'C', 'O', 'M', '3', '\0' }; //contain friendly name
    //Enter the com port id
    //Open the serial com port
    hComm = CreateFile(PortNo, //friendly name
        GENERIC_READ | GENERIC_WRITE,      // Read/Write Access
        0,                                 // No Sharing, ports cant be shared
        NULL,                              // No Security
        OPEN_EXISTING,                     // Open existing port only
        NULL,              // Non Overlapped I/O
        NULL);                             // Null for Comm Devices
    if (hComm == INVALID_HANDLE_VALUE)
    {
        printf_s("\nPort can't be opened");
        system("pause");
        return;
    }
    printf_s("\nPort opened");
}

void DeviceConnection::performWrite(std::string command) {
    open("COM3");
    setParameters();
    setTimeouts();
    write(command);
    setCommMask();
    //wait();
    read();
    CloseHandle(hComm);//Closing the Serial Port
    system("pause");
}

bool DeviceConnection::write(std::string command){
    //strcpy_s(SerialBuffer, command.c_str());
    printf_s("\nwriting:  %s \n", command.c_str());
    //Writing data to Serial Port
    bool Status = WriteFile(hComm,// Handle to the Serialport
        command.c_str(),            // Data to be written to the port
        64,   // No of bytes to write into the port
        &BytesWritten,  // No of bytes written to the port
        NULL);
    if (Status == FALSE)
    {
        CloseHandle(hComm);//Closing the Serial Port
        printf_s("\nFailed to Write at %d " + BytesWritten + '\n');
        return false;
    }
    printf_s("\nbytes written to the serail port: %d \n", BytesWritten);

    
    return 1;
}

void DeviceConnection::read() {
    //Read data and store in a buffer
    char ReadData;        //temperory Character
    char Output[64] = "";
    unsigned char loop = 0;
    do
    {
            Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL);
            printf(&ReadData);
            printf("\nreading(%d): %s", loop, &ReadData);
            Output[loop] = ReadData;
           ++loop;
    } while (NoBytesRead > 0);
    --loop; //Get Actual length of received data
    printf("\nbytes received = %s\n", Output);
    //print receive data on console
    //int index = 0;
    //for (index = 0; index < loop; ++index)
    //{
    //    //printf_s("%s", ReadData);
    //}
}

void DeviceConnection::wait() {
    //Setting WaitComm() Event
    DWORD dwEventMask;     // Event mask to trigger
    OVERLAPPED o;
    o.hEvent = CreateEvent(
        NULL,   // default security attributes 
        TRUE,   // manual-reset event 
        FALSE,  // not signaled 
        NULL    // no name
    );


    // Initialize the rest of the OVERLAPPED structure to zero.
    o.Internal = 0;
    o.InternalHigh = 0;
    o.Offset = 0;
    o.OffsetHigh = 0;
    //assert(&o.hEvent);
    printf_s("\nWaiting %d", BytesWritten);
    Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received
    printf_s("\nDone\n\n", Status);
    if (Status == FALSE)
    {
        printf_s("\nError! in Setting WaitCommEvent()\n\n");
        system("pause");
        return;
    }
}

void DeviceConnection::setCommMask() {
    //print numbers of byte written to the serial port
    //printf_s("\nSetting Comm Mask = %d", EV_RXCHAR);
    //Setting Receive Mask
    Status = SetCommMask(hComm, EV_RXCHAR);
    if (Status == FALSE)
    {
        printf_s("\nError to in Setting CommMask\n\n");
        CloseHandle(hComm);//Closing the Serial Port
        system("pause");
        return;
    }

}

void DeviceConnection::setParameters()
{
    //Setting the Parameters for the SerialPort
    params.DCBlength = sizeof(params);
    Status = GetCommState(hComm, &params); //retreives  the current settings
    if (Status == FALSE)
    {
        printf_s("\nError getting the Com state");
        CloseHandle(hComm);//Closing the Serial Port
        system("pause");
        return;
    }
    //  Print some of the DCB structure values
    _tprintf(TEXT("\nOriginal BaudRate: %d, ByteSize: %d, Parity: %d, StopBits: %d"),
        params.BaudRate,
        params.ByteSize,
        params.Parity,
        params.StopBits);
    params.BaudRate = CBR_38400;      //BaudRate = 9600
    params.ByteSize = 8;             //ByteSize = 8
    params.StopBits = ONESTOPBIT;    //StopBits = 1
    params.Parity = NOPARITY;      //Parity = None
    Status = SetCommState(hComm, &params);
    if (Status == FALSE)
    {
        printf_s("\nError to Setting DCB Structure\n\n");
        CloseHandle(hComm);//Closing the Serial Port
        system("pause");
        return;
    }
    _tprintf(TEXT("\nUpdated BaudRate: %d, ByteSize: %d, Parity: %d, StopBits: %d"),
        params.BaudRate,
        params.ByteSize,
        params.Parity,
        params.StopBits);
    printf_s("\nUpdated Parameters");
}

void DeviceConnection::setTimeouts() {
    //Setting Timeouts
    COMMTIMEOUTS timeouts = { 0 };  //Initializing timeouts structure
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 50;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 50;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    if (SetCommTimeouts(hComm, &timeouts) == FALSE)
    {
        printf_s("\nError to Setting Time outs");

        CloseHandle(hComm);//Closing the Serial Port

        system("pause");
        return;
    };
}

[1]: https://i.stack.imgur.com/ZKSP0.png

Michael Collins
  • 380
  • 1
  • 4
  • 19
  • Please try this: `wchar_t PortNo[20] = { 'C', 'O', 'M', '3', '\0'};` – paladin Mar 11 '21 at 16:58
  • I tried this with no luck I also tried adding \0 to the command. Same results. :/ – Michael Collins Mar 11 '21 at 18:10
  • Refer to :[SerialPort not receiving any data](https://stackoverflow.com/a/8910167/13566062) – Zeus Mar 12 '21 at 03:22
  • There is no option for handshakes in c++ but thanks helpful – Michael Collins Mar 12 '21 at 05:48
  • So have you tested whether you can send and receive information normally through the serial port debugging tool, can it be successful? – Zeus Mar 12 '21 at 06:06
  • Serial port debugging tool? here I will update my code to make it more readable and print bette too. – Michael Collins Mar 12 '21 at 06:53
  • Many parts of your code are not printed correctly, for example: `printf_s("\nNumber of bytes received = ", ReadData);` should be `printf_s("\nNumber of bytes received = %d", ReadData);`. Can't determine where your mistake is. If you check WriteFile and ReadFile, the return value Status is TRUE. It indicates that the writing/reading is successful, and you have to confirm whether the serial port can write information correctly. – Zeus Mar 12 '21 at 07:56
  • Thanks for that.I am updating my code to make it easier to read. It gets stuck at the wait comm part. – Michael Collins Mar 12 '21 at 16:40
  • It's now reading a single character back (-52) after I take out the comm wait – Michael Collins Mar 12 '21 at 17:04
  • It did not return -52 characters, because your characters were not initialized, and `ReadFile` returned 0 characters, so there was no assignment to `ReadData`.According to [MSDN](https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms891445(v=msdn.10)?redirectedfrom=MSDN#return-values):If the return value is nonzero and the number of bytes read is zero, the file pointer was beyond the current end of the file at the time of the read operation. – Zeus Mar 15 '21 at 02:49
  • Returning seemingly random symbols is typically a sign of a baud rate mismatch. Are you certain the speed is correct on both ends? Also the data, stop and parity bits? If the port setup is not exactly right, the rest won't matter. Also - there's no terminating symbol or delimiter in your commands. What's the protocol? After sending `XEXSULF` should you send a terminating symbol or is it strictly fixed length? Can you use Miniterm to manually send commands? What about PySerial? It's much easier to get something up and running. Consider Boost::asio for a much better API. – gavinb Mar 19 '21 at 10:52

2 Answers2

2

you have problems with buffering. I'm not fixing other errors, like not declared variables, sending objects by value or reading by values, because they aren't related to the question.

bool DeviceConnection::write(std::string command){
    //strcpy_s(SerialBuffer, command.c_str());
    printf_s("\nwriting:  %s \n", command.c_str());
    //Writing data to Serial Port
    bool Status = WriteFile(hComm,// Handle to the Serialport
        command.c_str(),    // Data to be written to the port <----- YOU MUST USE REAL SIZE OF THE BUFFER, otherwise you will get undefined behaviour 
        command.length(),   // No of bytes to write into the port
        &BytesWritten,  // No of bytes written to the port
        NULL);
    if (Status == FALSE)
    {
        CloseHandle(hComm);//Closing the Serial Port
        printf_s("\nFailed to Write at %d " + BytesWritten + '\n');
        return false;
    }
    printf_s("\nbytes written to the serail port: %d \n", BytesWritten);

    
    return 1;
}

void DeviceConnection::read() {
    //Read data and store in a buffer
    char ReadData;        //temperory Character
    char Output[64] = "";
    unsigned char loop = 0;
    do
    {
            Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL); 
            printf(ReadData); //<- PRINIT VALUE NOT POINTER
            printf("\nreading(%d): %c", loop, ReadData); //<- PRINIT VALUE NOT POINTER
            Output[loop] = ReadData;
           ++loop;
    } while (NoBytesRead > 0);
    // --loop; //Get Actual length of received data // <- incorrect
    printf("\nbytes received = %s\n", Output);
}

I strongly recommend to read something about pointers in C/C++

Tania Chistyakova
  • 3,928
  • 6
  • 13
2

Your comment seems to imply that you want 9600, but you requested 38,400:

params.BaudRate = CBR_38400;      //BaudRate = 9600

If you truly wanted/needed to communicate at 9600, but you are talking at 38400, that could be your issue. Try replacing the line with:

params.BaudRate = CBR_9600;

Garbage characters are typical when using an incorrect baud rate.

Lynn Crumbling
  • 12,985
  • 8
  • 57
  • 95