Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Не могу прочитать данные с COM-порта 
:(
    Опции темы
EKoshelev
Дата 26.12.2012, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Всем привет.
Встала задача - работать с COM-портом. Надыбал тут h-ник и cpp-шник, которые всё это позволяют. Инициализация и запись у меня получаются. А вот с чтением возникли проблемы. Там всё сделано через CreateFile. Вот инициализация:

Код

COMPort::COMPort ( const char * const portName )
  : theDCB (NULL)
{

thePortHandle = (unsigned ) CreateFileA ( portName
                                       , GENERIC_READ | GENERIC_WRITE
                                       , 0
                                       , NULL
                                       , OPEN_EXISTING
                                       , FILE_FLAG_NO_BUFFERING
                                       , NULL
                                       );
if (thePortHandle == HFILE_ERROR)
{
   throw runtime_error ("COMPort: failed to open.");
} // endif

theDCB = new char [sizeof(DCB)];
getState();
setBlockingMode();
setHandshaking();

} // end constructor


А вот чтение (немного измененное мной):

Код

bool COMPort::read(char &ch)
{
//    char buffer;
    DWORD charsRead = 0;

       if (! ReadFile ( (HANDLE(thePortHandle))
                      , &ch
                      , sizeof(char)
                      , &charsRead
                      , NULL
                      )
          )    return false;
       else return true;
}


Дак вот, когда прога доходит до ReadFile она сидит, собака, и ждёт, пока на порт что-нибудь придёт. А до этого её даже через диспетчер задач не вырубить. Собственно вопрос: можно ли сделать так, чтобы ReadFile завершал работу даже в том случае, если на порт ничего не пришло и возвращал false?



--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
kuzulis
Дата 26.12.2012, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 154
Регистрация: 5.9.2007

Репутация: нет
Всего: 1



Читай до просветления: http://msdn.microsoft.com/en-us/library/ff802693.aspx

Или в гугле забанили?  smile 

Это сообщение отредактировал(а) kuzulis - 26.12.2012, 16:55
PM MAIL   Вверх
Dem_max
Дата 27.12.2012, 04:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



Вот готовая реализация
Исходник от Microsoft


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
EKoshelev
Дата 26.4.2013, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Не прошло и полгода, ага.

kuzulis, читал, спасибо.

Слабал следующее (на Qt):

.h
Код

#include <windows.h> 

enum QParity {pNone, pOdd, pEven, pMark, pSpace};
enum QDataBits {db5 = 5, db6, db7, db8};
enum QStopBits {sb1, sb15, sb2};
enum QFlowControl {fcNone, fcSoftware, fcHardware};

struct QComPortParams
{
    QString portName;
    unsigned long baudRate;
    QDataBits dataBits;
    QStopBits stopBits;
    QParity parity;
    QFlowControl flowControl;
};


class QComPorts : public QObject
{
    Q_OBJECT

public:
    QComPorts();
    ~QComPorts();

    // Достать список всех COM-портов
    QStringList getComPortsNames();
    // Открыть порт
    bool open(QComPortParams* params);
    // Закрыть порт
    bool close();
    // Отправить данные
    void write(QByteArray* sendedData);

private:
    // Таймер, который читает
    QTimer* m_pReceiveTime;
    // Хэндл COM-порта
    HANDLE m_hComm;
    // Настройки порта
    char* m_theDCB;
    
private slots:
    // Слот на таймер
    void timerSlot();

signals:
    // Сигнал на получение 
    void receivePackSignal(QByteArray* sendedData);
};



.cpp
Код

QComPorts::QComPorts()
{
    // Таймер, который читает
    m_pReceiveTime = new QTimer();

    connect(m_pReceiveTime, SIGNAL(timeout()), this, SLOT(timerSlot()));
}


QComPorts::~QComPorts()
{
    delete m_pReceiveTime;
}


// Достать список всех COM-портов
QStringList QComPorts::getComPortsNames()
{
    TCHAR szDevices[65535];
    DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);

    // Перекинем эту строку в QString
    QString szDeviceList = "";
    QChar chTmp;
    QStringList strList;
    QStringList result;


    if (dwChars) 
    {
        int nZeroCnt = 0;
        int i = 0;
        for (;;)
        {
            // Если текущий символ нулевой, то увеличим к-во нулевых символов
            if (szDevices[i] == 0) nZeroCnt++;
            // Иначе обнулим счетчик нулей
            else nZeroCnt = 0;

            // Если более одного нуля подряд, то выходим из цикла
            if (nZeroCnt > 1) break;

            chTmp = szDevices[i];
            szDeviceList += chTmp;

            i++;
        }
    }

    // Разобьем эту строку на несколько по символу #0
    strList = szDeviceList.split(QChar(0));

    // Выберем только COM-порты
    for (int i = 0; i < strList.size(); i++)
    {
        // Если строка начинается с "COM"
        if ((strList[i].left(3).toUpper() == "COM") &&
            // А оставшийся кусок - это число от 1 до 255
            (strList[i].mid(3).toInt() >= 1) &&
            (strList[i].mid(3).toInt() <= 255))
        {
            result.push_back(strList[i]);
        }
    }

    return result;
}


// Открыть порт
bool QComPorts::open(QComPortParams* params)
{
    QString szPort;
    szPort = QString("\\\\.\\") + params->portName;

    // Связаться с портом
    m_hComm = CreateFileA(szPort.toAscii().data(),  
                        GENERIC_READ | GENERIC_WRITE, 
                        0, 
                        0, 
                        OPEN_EXISTING,
                        FILE_FLAG_OVERLAPPED,
                        0);

    // 
    if (m_hComm == INVALID_HANDLE_VALUE)
    {
        showMessage("Метод bool QComPorts::open" + QString(10) + 
                    "Ошибка в при открытии порта");
        return false;
    }

    m_theDCB = new char [sizeof(DCB)];

    // Достанем состояние порта
    if (!GetCommState(m_hComm, LPDCB(m_theDCB)))
    {
        showMessage("Метод bool QComPorts::open" + QString(10) + 
                    "Ошибка при исполнения GetCommState()");
        return false;
    }


    // Устанавливаем параметры соединения
    LPDCB(m_theDCB)->BaudRate = params->baudRate;
    LPDCB(m_theDCB)->ByteSize = params->dataBits;
    LPDCB(m_theDCB)->StopBits = params->stopBits;
    LPDCB(m_theDCB)->Parity = params->parity;

    // FlowControl
    // Эти всегда одинаковые
    LPDCB(m_theDCB)->XonChar = 17;
    LPDCB(m_theDCB)->XoffChar = 19;
    LPDCB(m_theDCB)->fOutxDsrFlow = false;
    LPDCB(m_theDCB)->fDtrControl = 0;
    LPDCB(m_theDCB)->fDsrSensitivity = false;
    LPDCB(m_theDCB)->fTXContinueOnXoff = false;

    // Эти почти не меняются
    LPDCB(m_theDCB)->fOutxCtsFlow = false;
    LPDCB(m_theDCB)->fRtsControl = 0;
    LPDCB(m_theDCB)->fOutX = false;
    LPDCB(m_theDCB)->fInX = false;

    switch (params->flowControl)
    {
    case fcNone:
        break;

    case fcHardware:
        LPDCB(m_theDCB)->fOutxCtsFlow = true;
        LPDCB(m_theDCB)->fRtsControl = 2;
        break;

    case fcSoftware:
        LPDCB(m_theDCB)->fOutX = true;
        LPDCB(m_theDCB)->fInX = true;
        break;
    }


    // Изменим настройки порта
    if (!SetCommState(m_hComm, LPDCB(m_theDCB)))
    {
        showMessage("Метод bool QComPorts::open" + QString(10) + 
                    "Ошибка при исполнения SetCommState()");
        return false;
    }

    // Запускаем таймер
    m_pReceiveTime->setInterval(50);
    m_pReceiveTime->start();

    return true;
}


// Закрыть порт
bool QComPorts::close()
{
    delete [] m_theDCB;
    if (CloseHandle ((HANDLE)m_hComm))
    {
        showMessage("Метод bool QComPorts::close" + QString(10) + 
                    "Ошибка при закрытии порта");
        return false;
    } 

    // Останавливаем таймер
    m_pReceiveTime->stop();

    return true;
}


// Отправить данные
void QComPorts::write(QByteArray* sendedData)
{
    DWORD dwToWrite = sendedData->size();

    OVERLAPPED osWrite = {0};
    DWORD dwWritten;
    DWORD dwRes;
    BOOL fRes;
    int nLastError;

    // Create this write operation's OVERLAPPED structure's hEvent.
    osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (osWrite.hEvent == NULL)
    {
        showMessage("Ошбика создания события");
        return;
    };


    // Issue write.
    if (!WriteFile(m_hComm, sendedData->data(), dwToWrite, &dwWritten, &osWrite)) {
        nLastError = GetLastError();
        if (nLastError != ERROR_IO_PENDING) { 
            // WriteFile failed, but isn't delayed. Report error and abort.
            fRes = FALSE;
    }
      else
      {
         // Write is pending.
         dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);

         switch(dwRes)
         {
            // OVERLAPPED structure's event has been signaled. 
            case WAIT_OBJECT_0:
                 if (!GetOverlappedResult(m_hComm, &osWrite, &dwWritten, FALSE))
                       fRes = FALSE;
                 else
                  // Write operation completed successfully.
                  fRes = TRUE;
                 break;
            
            default:
                 // An error has occurred in WaitForSingleObject.
                 // This usually indicates a problem with the
                // OVERLAPPED structure's event handle.
                 fRes = FALSE;
                 break;
         }
      }
   }
   else
      // WriteFile completed immediately.
      fRes = TRUE;

   CloseHandle(osWrite.hEvent);
}


// Слот на таймер
void QComPorts::timerSlot()
{
    _COMSTAT cs;
    DWORD error;
    ClearCommError(m_hComm, &error, &cs);
    QByteArray result;


    // Если пришли данные
    if (cs.cbInQue != 0) 
    {
        char* lpBuf;
        lpBuf = (char*)(malloc(cs.cbInQue));

        DWORD dwRead;
        BOOL fWaitingOnRead = FALSE;
        OVERLAPPED osReader = {0};
        bool bReadResult;

        osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

        if (osReader.hEvent == NULL)
        {
//            showMessage("Ошбика создания события");
            return;
        }

        bReadResult = ReadFile(m_hComm, lpBuf, cs.cbInQue, &dwRead, &osReader);
        if (bReadResult)
        {
            result.append(lpBuf, cs.cbInQue);
        }

        ClearCommError(m_hComm, &error, &cs);

        free(lpBuf);
    }

    if (result.size() > 0) 
        emit receivePackSignal(&result);
}



Это сообщение отредактировал(а) EKoshelev - 7.5.2013, 12:23


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
Alca
Дата 26.4.2013, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 7
Всего: 50



Цитата(EKoshelev @ 26.4.2013,  15:52)
Не прошло и полгода, ага.

kuzulis, читал, спасибо.

Слабал следующее (на Qt):

http://qt-project.org/wiki/QtSerialPort

Это сообщение отредактировал(а) Alca - 26.4.2013, 17:48


--------------------
PM WWW ICQ Skype Jabber   Вверх
EKoshelev
Дата 29.4.2013, 07:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Alca, боян. 

В смысле, работает криво местами.


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
kuzulis
Дата 29.4.2013, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 154
Регистрация: 5.9.2007

Репутация: нет
Всего: 1



Цитата

В смысле, работает криво местами. 


Так надожеж баг-репорты слать, а не лялякать, а то так и будет криво работать.  smile 
PM MAIL   Вверх
EKoshelev
Дата 30.4.2013, 07:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Цитата

а то так и будет криво работать

Ну и пусть. Я свои проблемы решил. Вроде.


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
bsa
Дата 30.4.2013, 07:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



EKoshelev, если не секрет, а что же там криво работает? Этот класс уже часть Qt, так что может поделишься?
PM   Вверх
xvr
Дата 30.4.2013, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(EKoshelev @  29.4.2013,  07:37 Найти цитируемый пост)
В смысле, работает криво местами. 

Твоя версия работает криво не местами, а всегда.  smile На каждое чтение из порта гарантированная утечка памяти и ресурсов.

PM MAIL   Вверх
EKoshelev
Дата 7.5.2013, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



bsa, чё, серьёзно? А какой версии Qt? 

Криво работало? Сам не проверял толком, но коллеги говорят, что не всегда устанавливались настройки порта (в частности скорость передачи) и осцилограф вместо прямоугольной диаграммы местами показывал короткие аналоговые. Возможно, я где-то накосячил, но там вроде и ошибаться-то негде.

Я, кстати, почему спрашиваю про версию Qt. Не помню где, слышал, что в пятую SerialPort не попал. По крайней мере в самую первую из пятых. И если я не ошибаюсь, значит на то, видимо, были причины.




xvr, Может подскажешь в каком месте? Если malloc, то уже поправил.

Это сообщение отредактировал(а) EKoshelev - 7.5.2013, 12:21


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
chaos
Дата 7.5.2013, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 6
Всего: 44



Если не изменяет память: конфигурировать порт нужно после его открытия! "Наступал" давненько
PM WWW   Вверх
Dem_max
Дата 8.5.2013, 06:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



Цитата

Если не изменяет память: конфигурировать порт нужно после его открытия! "Наступал" давненько

Все верное. А иначе что конфигурировать то ???


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
bsa
Дата 8.5.2013, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(EKoshelev @  7.5.2013,  13:08 Найти цитируемый пост)
bsa, чё, серьёзно? А какой версии Qt? 

Если не ошибаюсь, будет в 5.1: http://doc-snapshot.qt-project.org/qt5-sta...oc/modules.html
Цитата(EKoshelev @  7.5.2013,  13:08 Найти цитируемый пост)
Я, кстати, почему спрашиваю про версию Qt. Не помню где, слышал, что в пятую SerialPort не попал.
Пропихнули туда только после выхода 5-й версии.

PM   Вверх
xvr
Дата 16.5.2013, 10:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(EKoshelev @  7.5.2013,  12:08 Найти цитируемый пост)
xvr, Может подскажешь в каком месте? Если malloc, то уже поправил.

Угу, а еще в строке 256:
Код

        osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
не закрывается handle на osReader.hEvent - будет утекать по 1 Event'у на каждый вызов

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0701 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.