3
\$\begingroup\$

This code connects to COM 3 which has a broadband card and sends a command that returns the RSSI value. I use this program to see patterns in signal strength in certain areas.

#include <Windows.h>
#include <iostream>
#include <string>

int main()
{
    HANDLE hSerial = CreateFile("COM3",GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

    if(hSerial==INVALID_HANDLE_VALUE)
        std::cout << "Insert error message";

    DCB dcbSerialParams = {0};
    dcbSerialParams.DCBlength=sizeof(dcbSerialParams);

    if (!GetCommState(hSerial, &dcbSerialParams)) 
        std::cout << "Insert error message";

    dcbSerialParams.BaudRate=CBR_9600;
    dcbSerialParams.ByteSize=8;
    dcbSerialParams.StopBits=ONESTOPBIT;
    dcbSerialParams.Parity=NOPARITY;

    if (!SetCommState(hSerial,&dcbSerialParams))
        std::cout << "Insert error message";


    COMMTIMEOUTS timeouts={0};
    timeouts.ReadIntervalTimeout=50;
    timeouts.ReadTotalTimeoutConstant=50;
    timeouts.ReadTotalTimeoutMultiplier=10;
    timeouts.WriteTotalTimeoutConstant=50;
    timeouts.WriteTotalTimeoutMultiplier=10;
    if(!SetCommTimeouts(hSerial, &timeouts))
        std::cout << "Insert error message";



    while(1)
    {
        char szBuff[50+1] = {0};
        char wzBuff[14] = {"AT+CSQ\r"};

        DWORD dZBytesRead = 0;
        DWORD dwBytesRead = 0;


        if(!WriteFile(hSerial, wzBuff, 7, &dZBytesRead, NULL))
            std::cout << "Write error";

        if(!ReadFile(hSerial, szBuff, 50, &dwBytesRead, NULL))
            std::cout << "Read Error";

        std::string subString = std::string(szBuff).substr(8,3);
        std::cout << subString;

        Sleep(500);
    }

    return 0;
}
\$\endgroup\$
1
\$\begingroup\$

In all the test that could be an error. Do you really want to continue if there is an error?
Seems counterproductive to generate an error message and continue running. That will just generate more spurious errors.

if(hSerial==INVALID_HANDLE_VALUE)
{
    throw std::runtime_error("Insert error message");
}

Then just wrap your code in a try catch block:

try
{
    ... Code here
}
catch(std::exception const& e)
{
    std::cerr << "Exception: " << e.what() << "\n";
    throw; // re-throw so the OS can provide help if available.
}
catch(...)
{
    std::cerr << "Exception: Unknown ...\n";
    throw;
}
\$\endgroup\$
1
\$\begingroup\$

In addition to what's already been said, here's some comments and handy things to keep in mind.

  • Good practice is to always open COM ports with a string looking like \.\COM3, otherwise you won't be able to open COM ports above number 10. That's quite a hard bug to catch unless you are aware of it. In C this will look like:

    CreateFile("\\\\.\\COM3" ...
    
  • You should always check the nature of the incoming data no matter if ReadFile was successful. There may be junk data and noise on the RS-232, especially at the moment when a classic 9-pin dsub connector is connected/removed. In your case with AT commands it is easy, you must just check if the data is valid ASCII or a null termination. If not, you received some junk data.

    if(isalnum(ch) || isspace(ch) || ch=='\0')
    {
      // ok
    }
    else
    {
      // error
    }
    
  • If Readfile failed, you might want to add some additional checks, at the very least:

    DWORD last_error = GetLastError();
    if(last_error == ERROR_OPERATION_ABORTED)
    {
      // There is nobody sending any longer, close the port?
    }
    
  • Close the ports when you aren't using them any longer. As long as you haven't closed the port with CloseHandle(), you will block other programs from using that port. Windows will probably do that when the program terminates, but good practice is to always clean up your own mess.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.