Открытие последовательного порта в visual studio: работает в отладчике, но не в консоли - PullRequest
0 голосов
/ 10 октября 2018

Я создал каркас кода для открытия последовательного порта в Visual Studio C ++ v 14. Мне нужно это как DLL, поэтому я создал проект DLL, а затем добавил консольный проект в решение для тестирования, котороетребует вывода в качестве статической библиотеки для компоновки.Я следовал планам последовательной связи, доступным в StackOverflow и других местах, и программа работает, как и ожидалось, при запуске в режиме отладки из Visual Studio;например, я могу открыть порт и все настроить, если порт используется другой программой, такой как TeraTerm, это выдаст мне ошибку отказа в доступе, и если я попытаюсь открыть неиспользуемый порт, я получу соответствующую ошибку ввода-вывода.Я еще не пытался установить полный обмен данными по несвязанным практическим причинам.

Однако, когда я пытаюсь запустить исполняемый файл из командной строки, я получаю сообщение об ошибке «Отказано в доступе» (# 5) при попытке открыть порт (INVALID_HANDLE_VALUE).Опять же, если я пытаюсь открыть какой-то другой случайный порт, я получаю соответствующую ошибку, но я никогда не могу подключиться к нужному.Это поведение сохраняется после перезапуска до повторного открытия Visual Studio.Я пробовал в режимах компиляции x64, x86, Debug и Release, а также в качестве администратора.

Любое направление будет оценено.Я также отмечу, что я успешно протестировал последовательную связь C # с точно такой же сборки Visual Studio на этом компьютере.

РЕДАКТИРОВАТЬ: Это частично аппаратная проблема.Я подключил новое устройство и смог подключиться с консоли.Однако остается вопрос, почему отладчик мог подключиться, а консоль - нет.Хотя моя конкретная проблема решена, я оставлю это открытым, поскольку это может быть полезно для других.

Полный код здесь не приводится для краткости.

Определение класса, IMUComms.cpp

#include "stdafx.h"
#include "IMUComms.h"

namespace Magnolia {

std::ostream &operator<<(std::ostream &stream,
    IMUComms &ob) {
    stream << "Class: IMUComms\r\n";
    stream << ob.getCfgFromObj() << std::endl;
    return stream;
}

IMUComms::IMUComms()
{
    this->portSet = FALSE;
}

IMUComms::~IMUComms()
{
}

IMUComms* IMUComms::New() {
    return new IMUComms;
}

void IMUComms::Delete() {
    delete this;
}

void IMUComms::setCOMParams(std::string p, int baud,std::string pm) 
{
    this->setComPort(p);
    this->setBaudRate(baud);
    this->setPortMode(pm);
    this->portSet = true;

}

void IMUComms::setComPort(std::string comPort) {
    std::string cp;
#ifdef _WIN32
    cp = "\\\\.\\" + comPort;
    //cp = comPort;
#else
    cp = comPort;
#endif
    this->comPort = cp;
}

void IMUComms::setBaudRate(int baud) {
    this->baudRate = baud;
}

void IMUComms::setPortMode(std::string pm) {
    //Check port mode first
    if (pm.length() != 3) {
        throw std::invalid_argument("Invalid port mode");
    }
    //\TODO perform better checks

    std::string mode;
    mode = "baud=" + std::to_string(this->baudRate);
    mode = mode + " data=" + pm.at(0);
    mode = mode + " parity=" + pm.at(1);
    mode = mode + " stop=" + pm.at(2);
    mode = mode + " dtr=on rts=on";

    this->portMode = mode;
}

void IMUComms::openCOMPort() {
    if (this->portSet == false) {
        throw std::invalid_argument("Com port parameters not set");
        return;
    }
    //std::wstring temp = std::wstring(this->comPort.begin(), this->comPort.end());
    this->Cport = CreateFileA(this->comPort.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        0,
        0,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        NULL);
    std::cout << "Cport object created" << std::endl;
    std::chrono::seconds dura(1);
    std::this_thread::sleep_for(dura);
    if (this->Cport == INVALID_HANDLE_VALUE) {
        DWORD e = GetLastError();
        if (e == 5) {
            std::string emsg;
            emsg = "Unable to open Com port (" + this->comPort + "). Access is denied.\r\n";
            throw std::invalid_argument(emsg);
            return;
        }
        else if (e == 2) {
            throw std::invalid_argument("Unable to open Com port.  Port not found.\r\n");
            return;
        }
        else {
            throw std::invalid_argument("Unable to open Com port. Invalid handle value.\r\n");
            return;
        }
    }

    std::cout << "Com port opened." << std::endl;
    //DCB port_settings;
    memset(&this->port_settings, 0, sizeof(this->port_settings));
    this->port_settings.DCBlength = sizeof(this->port_settings);
    if (!BuildCommDCBA(this->portMode.c_str(), &this->port_settings)) {
        throw std::invalid_argument("Unable to set DCB settings.");
        CloseHandle(this->Cport);
        return;
    }
    std::cout << "DCB settings set." << std::endl;
    if (!SetCommState(this->Cport, &this->port_settings)) {
        throw std::invalid_argument("Unable to set Com port cfg settings.");
        CloseHandle(this->Cport);
        return;
    }
    std::cout << "Cfg settings set." << std::endl;

    //COMMTIMEOUTS Cptimeouts;

    this->Cptimeouts.ReadIntervalTimeout = MAXDWORD;
    this->Cptimeouts.ReadTotalTimeoutMultiplier = 0;
    this->Cptimeouts.ReadTotalTimeoutConstant = 0;
    this->Cptimeouts.WriteTotalTimeoutMultiplier = 0;
    this->Cptimeouts.WriteTotalTimeoutConstant = 0;
    if (!SetCommTimeouts(this->Cport, &this->Cptimeouts)) {
        throw std::invalid_argument("Unable to set Com port timeout settings.");
        CloseHandle(this->Cport);
        return;
    }
    std::cout << "Timeout settings set." << std::endl;
}

void IMUComms::closeCOMPort() {
    CloseHandle(this->Cport);
}

std::string IMUComms::getCfgFromObj() {
    std::string outp;
    outp = "----------------------------\r\n";
    outp = outp + "User defined parameters:\r\n";
    outp = outp + "Port: " + this->comPort + "\r\n";
    outp = outp + "Baud rate: " + std::to_string(this->baudRate) + "\r\n";
    outp = outp + "Cfg: " + this->portMode + "\r\n";
    outp = outp + "----------------------------\r\n";
    outp = outp + "Parameters set in Com object:\r\n";
    if (this->Cport != INVALID_HANDLE_VALUE) {
        outp = outp + "Baud rate: " + std::to_string(this->port_settings.BaudRate) + "\r\n";
        outp = outp + "Byte length: " + std::to_string(this->port_settings.ByteSize) + "\r\n";
        outp = outp + "Parity (0-4: none, odd, even, mark, space): " + std::to_string(this->port_settings.Parity) + "\r\n";
        outp = outp + "Stop bits (0-2: 1, 1.5, 2): " + std::to_string(this->port_settings.StopBits) + "\r\n";
        outp = outp + "DTR control: " + std::to_string(this->port_settings.fDtrControl) + "\r\n";
        outp = outp + "RTS control: " + std::to_string(this->port_settings.fRtsControl) + "\r\n";
        outp = outp + "----------------------------\r\n";
        return outp;
    }
    outp = outp + "No available settings.\r\n";
    outp = outp + "----------------------------\r\n";
    return outp;
}
}

Файл заголовка

#ifndef __IMUComms_h
#define __IMUComms_h

#include "IMUC.h"
#include "Magnolia.h"
#include <chrono>

namespace Magnolia {

class IMUComms : public IMUC
{
    friend std::ostream &operator<<(std::ostream &stream,
        IMUComms &ob);

public:

    static IMUComms* New();
    void Delete();

    void setCOMParams(std::string p, int baud, std::string pm);

    void openCOMPort();
    void closeCOMPort();

    std::string getCfgFromObj();

protected:
    IMUComms();
    ~IMUComms();
    void setComPort(std::string comPort);
    void setBaudRate(int baud);
    void setPortMode(std::string pm);



// ========== Data Members ==========

    std::string comPort;
    int baudRate;
    int dataLen;
    std::string portMode;
    bool portSet;

    HANDLE Cport;
    DCB port_settings;
    COMMTIMEOUTS Cptimeouts;

};
}

#endif

Файл заголовка "Магнолия"

#ifndef __magnolia_h
#define __magnolia_h

#include <complex>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <stdexcept>
#include <memory>
#include <thread>
#include "stdafx.h"

//#include <Eigen/Core>
//#include <Eigen/StdVector>
#if defined(__linux__) || defined(__FreeBSD__)
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
#else
#include<Windows.h>
#endif

namespace Magnolia {

///Typedef Real set as double
typedef double Real;

///Typedef Complex set as double
typedef std::complex<Real> Complex;

//typedef Eigen::Matrix<Real, Eigen::Dynamic, 1> VectorXr;

//typedef Eigen::Matrix<Real, 3, Eigen::Dynamic> Vector3Xr;

//typedef Eigen::Matrix<Real, 4, Eigen::Dynamic> Vector4Xr;

//For the UM7 IMU
typedef struct UM7_packet_struct 
{
    uint8_t Address;
    uint8_t PT;
    uint16_t Checksum;
    uint8_t data_length;
    uint8_t data[30];
} UM7_packet;

}
#endif

Код теста

#include "stdafx.h"
#include "../IMURead/IMURead/Magnolia_base"
#include <iostream>

using namespace Magnolia;

int main(int argc, char **argv)
{
IMUComms *comms = IMUComms::New();
std::string port = argv[1];
int baud = std::stoi(argv[2]);
std::string pm = argv[3];

comms->setCOMParams(port,baud,pm);
std::cout << *comms << "\r\n";
try {
    comms->openCOMPort();
}
catch (const std::invalid_argument& e ) {
    std::cout << e.what() << std::endl;
    //std::cout << GetLastError() << std::endl;
}
std::cout << *comms << std::endl;
std::cin.ignore();
comms->closeCOMPort();
comms->Delete();
return 0;
}

Вывод при запуске изв Visual Studio:

Class: IMUComms  
----------------------------    
User defined parameters:    
Port: \\.\COM8    
Baud rate: 9600    
Cfg: baud=9600 data=8 parity=n stop=1 dtr=on rts=on    
----------------------------    
Parameters set in Com object:    
Baud rate: 0    
Byte length: 0    
Parity (0-4: none, odd, even, mark, space): 0    
Stop bits (0-2: 1, 1.5, 2): 0    
DTR control: 0    
RTS control: 0    
----------------------------   
Cport object created
Com port opened.
DCB settings set.
Cfg settings set.
Timeout settings set.
Class: IMUComms    
----------------------------    
User defined parameters:    
Port: \\.\COM8    
Baud rate: 9600    
Cfg: baud=9600 data=8 parity=n stop=1 dtr=on rts=on    
----------------------------    
Parameters set in Com object:    
Baud rate: 9600    
Byte length: 8    
Parity (0-4: none, odd, even, mark, space): 0    
Stop bits (0-2: 1, 1.5, 2): 0    
DTR control: 1    
RTS control: 1    
----------------------------

И вывод при запуске из командной строки (обратите внимание, что когда объект * comms передается в потоковом режиме, он проверяет наличие недопустимого дескриптора и печатает то, что вы видите ниже):

Class: IMUComms    
----------------------------    
User defined parameters:    
Port: \\.\COM8    
Baud rate: 9600    
Cfg: baud=9600 data=8 parity=n stop=1 dtr=on rts=on
----------------------------
Parameters set in Com object:    
Baud rate: 0    
Byte length: 0    
Parity (0-4: none, odd, even, mark, space): 0    
Stop bits (0-2: 1, 1.5, 2): 0    
DTR control: 0    
RTS control: 0    
----------------------------   
Cport object created
Unable to open Com port (\\.\COM8). Access is denied.
Class: IMUComms    
----------------------------    
User defined parameters:    
Port: \\.\COM8    
Baud rate: 9600    
Cfg: baud=9600 data=8 parity=n stop=1 dtr=on rts=on    
----------------------------    
Parameters set in Com object:    
No available settings.    
----------------------------
...