Michael Collins
Michael Collins

Reputation: 380

C++ Com Serial Port: Fails to write

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.sstatic.net/ZKSP0.png

Upvotes: 0

Views: 797

Answers (2)

Lynn Crumbling
Lynn Crumbling

Reputation: 13377

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.

Upvotes: 2

Tania Chistyakova
Tania Chistyakova

Reputation: 3968

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++

Upvotes: 2

Related Questions