vazz 0 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Раньше никогда не сталкивался с необходимостью осваивать WinAPI в части работы с COM-портами, другие способы коммуникации как-то больше волновали. А теперь вот не могу справится с простейшей на мой первоначальный взгляд задачей - реализация асинхронного обмена через "банальный" COM-порт. К COM-порту подключен модем, "понимающий" стандартный набор AT-команд. Вот и решил я далеко не ходить и не разгребать глюки готовых классов и модулей, реализованных другими разработчиками. Лицензионные продукты для своей простой задачи не вижу смысла покупать. Вот пал выбор на WinAPI. Вроде бы и информации в сети валом и msdn внимательно почитал, но у меня то ли неправильно выстроился алгоритм программы то ли дядюшка билли со своими извращенными алгоритмами всевозможных ограничений прав доступа к памяти мешает. Прошу помощи. Успешно открываю порт -- kernel32 - подгружаемая библиотека WinAPI-функций -- comid - номер открываемого порта -- handle - итоговый указатель на порт handle = kernel32.CreateFileA("\\\\.\\COM" .. comid, GENERIC_READ+GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0) Далее я создаю и заполняю структуры BCD и COMMTIMEOUTS. Сохраняю настройки с помощью функций SetCommState, SetCommTimeouts - обе возвращают TRUE. DCB.BaudRate = CBR_9600; DCB.ByteSize = 8; DCB.Parity = NOPARITY; DCB.StopBits = ONESTOPBIT; DCB.fBinary = 1; DCB.fOutxCtsFlow = 0; DCB.fOutxDsrFlow = 0; DCB.fDtrControl = DTR_CONTROL_DISABLE; DCB.fDsrSensitivity = 0; DCB.fNull = 0; DCB.fRtsControl = RTS_CONTROL_DISABLE; DCB.fAbortOnError = 0; COMMTIMEOUTS.ReadIntervalTimeout = 10; COMMTIMEOUTS.ReadTotalTimeoutMultiplier = 1; COMMTIMEOUTS.ReadTotalTimeoutConstant = 100; COMMTIMEOUTS.WriteTotalTimeoutMultiplier = 0; COMMTIMEOUTS.WriteTotalTimeoutConstant = 0; Далее пытаюсь отправить данные в порт -- data - массив с данными -- b - указатель на переменную типа DWORD "счетчик байт" -- t - указатель на буфер с данными -- n - кол-во данных в массиве data local n = Table.Count(data); local b = MemoryEx.Allocate(4); local t = MemoryEx.Allocate(n); if (b and t) then -- сброс счетчика байт MemoryEx.Fill(b, 4, 0, MEMEX_BYTE); -- заполнение буфера данными из массива data local c = 1; repeat MemoryEx.Byte(t + c - 1, data[c]); c = c + 1; until c > n; -- запись в порт if (kernel32.WriteFile(handle, t, n, b, 0) == 0) then local e = kernel32.GetLastError(); Dialog.Message("error", e); end end После попытки записать что-либо в порт функция возвращает 5, т.е. ACCESS DENIED. Что я упустил? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 35 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Попробуйте заменить FILE_FLAG_OVERLAPPED на FILE_FLAG_NO_BUFFERING А еще конкретизируйте номер порта. Т.е. "\\\\.\\COM" замените на COM с номером, типа: "\\\\.\\COM1" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 6 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Поскольку Вы при открытии файла указали флаг FILE_FLAG_OVERLAPPED, то при вызове процедуры WriteFile должны обязательно передавать указатель на OVERLAPPED структуру (этот указатель не может принимать значение NULL). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Xenia, я пробовал играться с этим флагом. Я так понял вариантов для com-портов (не файлов) всего два: 0 (для синхронного обмена, он проще) и FILE_FLAG_OVERLAPPED (для асинхронного). Ни тот ни другой, ни предложенный Вами не меняют итоговый результат - ACCESS DENIED. Дополнительно отмечу несколько моментов: - мое приложение после компиляции запускается от имени администратора (ОС Windows 7 x64); - память под буфер передачи (данных) я формирую аналогично выделению памяти под упомянутые структуры (т.е. данные участки памяти реально доступны для модификации, я перепроверял несколько раз различными способами); - com-порт не используется другими процессами (т.е. работе с ним ничто не мешает); - пробовал работать с портом программами типа putty - все получается (и открыть и отправить и принять); Есть несколько подозрительных вопросов: 1. Я самостоятельно могу запросить кусок памяти своими средствами для буфера приема/передачи или я должен пользоваться какими-то дополнительными WinAPI-функциями для задания такой области памяти под буферизацию? В моем коде я "сам" выделяю память и передаю ее поинтер в функцию WriteFile. 2. Необходимо ли для простой отправки данных типа "Hello world" создание каких либо дополнительных структур типа OVERLAPED или структур отвечающих за ошибки обмена и события при обмене? Может из-за отсутствия этих или каких-то либо других дополнительных структур функция WriteFile возвращает ошибку доступа? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 35 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Ну, а номер COM-порту вы назначили? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 6 января, 2015 Опубликовано 6 января, 2015 · Жалоба Поскольку Вы при открытии файла указали флаг FILE_FLAG_OVERLAPPED, то при вызове процедуры WriteFile должны обязательно передавать указатель на OVERLAPPED структуру (этот указатель не может принимать значение NULL). Спасибо за ответ. Я пробовал сбрасывать этот флаг до значения 0. При этом ошибка ACCESS DENIED все равно возвращается функцией WriteFile. Ну, а номер COM-порту вы назначили? Обижаете, конечно. Порт успешно открывается. Во-первых возвращается корректный handle (не 0 и не -1). Дополнительно после открытия порта делал проверку - запускал putty и убеждался в занятости порта. Номер порта в моем случае 52, я передаю этот номер в функцию CreateFileA. замените на COM с номером, типа: "\\\\.\\COM1" Для универсальности я беру строку "\\\\.\\COM" и "прилепляю" к концу этой строки номер порта. Т.е. задаю параметр comid = 52 и передаю в функцию. В моем посте #1 в первом куске кода это видно. Я пока играюсь в visual-среде, "движок" которой написан на Lua. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 14 января, 2015 Опубликовано 14 января, 2015 · Жалоба Неужели ни у кого нет опыта написания библиотеки/модуля для работы с com-портом с использованием WinAPI? Если есть опыт, подскажите перечень обязательных структур/переменных, которые необходимо создать/заполнить/передать/вернуть, чтобы можно было отправить данные и принять ответ. Хотя бы в синхронном "топорном" режиме для начала, можно без обработки событий и прочих доп.функций (с ними я по ходу дела ознакомлюсь). В инете ничего не могу найти, кроме обрывков, которые не дают отчетливого представления хотя бы для того, чтобы отправить в порт "Hello world". Хелп! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 14 января, 2015 Опубликовано 14 января, 2015 · Жалоба Да есть опыт... Но ничего такого не видно, почему бы оно не должно у Вас работать.... hc=CreateFile(port,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NU LL); .... BuildCommDCB(DEFDCB_STRING,&dcb); memset(&cc,0,sizeof(cc)); cc.dwSize=sizeof(cc); cc.wVersion=1; cc.dwProviderSubType=PST_RS232; memcpy(&cc.dcb,dcb,sizeof(DCB)); rc=SetCommConfig(hc,&cc,sizeof(cc)); .... memset(&ct,0,sizeof(ct)); ct.ReadIntervalTimeout=200; ct.ReadTotalTimeoutConstant=250; SetCommTimeouts(hc,&ct); .... EscapeCommFunction(hc,SETDTR); EscapeCommFunction(hc,SETRTS); .... WriteFile(hc,ovr->data.buf,bytes,&dummy,(LPOVERLAPPED) ovr); И все арбайтен. Ну то, что ссылка на буфер данных хранится в структуре OVERLAPPED, это уже нюансы реализации. Это совершенно не обязательно. И что NULL перенесло на NU и LL - это не я, это форум глючит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RabidRabbit 0 14 января, 2015 Опубликовано 14 января, 2015 · Жалоба До кучи :) bool CComm6055::exchangeData( QByteArray & cmd ) { COMMTIMEOUTS ct; DCB dcb; HANDLE h; BOOL rc; bool result = false; DWORD bytesWritten, bytesRead; // h = CreateFile( (LPCWSTR)sPort.unicode() , GENERIC_READ | GENERIC_WRITE , 0 , 0 , OPEN_EXISTING , 0 , 0 ); // if ( INVALID_HANDLE_VALUE != h ) { // ZeroMemory( &dcb, sizeof(dcb) ); dcb.BaudRate = CBR_9600; dcb.fBinary = TRUE; dcb.ByteSize = 8; rc = SetCommState( h, &dcb ); // ct.ReadIntervalTimeout = 64; ct.ReadTotalTimeoutConstant = 0; ct.ReadTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; ct.WriteTotalTimeoutMultiplier = 0; rc = SetCommTimeouts( h, &ct ); // makeCheckSum( cmd ); // if ( WriteFile( h , cmd.data() , cmd.size() , &bytesWritten , 0 ) ) { // if ( cmd.size() == bytesWritten ) { // cmd.resize( 32 ); // if ( ReadFile( h , cmd.data() , 32 , &bytesRead , 0 ) ) { // cmd.resize( bytesRead ); // result = true; } } } // CloseHandle( h ); } // return result; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
juvf 10 19 января, 2015 Опубликовано 19 января, 2015 · Жалоба Неужели ни у кого нет опыта написания библиотеки/модуля для работы с com-портом с использованием WinAPI?Опыт есть. Один раз настроил и забыл. Копипаст из проекта в проект. Работает как часы. bool MainWindow::openComPort(bool is19200) { std::string nameComPort = comPort->currentText().toStdString(); std::wstring wComPort; wComPort.resize(nameComPort.size()); for(unsigned int i=0; i<nameComPort.size(); i++) wComPort[i] = (WCHAR)nameComPort.at(i); wComPort.insert(0, L"\\\\.\\"); port=CreateFile( wComPort.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(port == INVALID_HANDLE_VALUE) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Spyhole error", QString("Can not open com port %1").arg(QString::fromStdString(nameComPort))); return false; } else { GetCommState(port,&dcb); //memset(&dcb, 0, sizeof(DCB)); dcb.DCBlength=sizeof(DCB); std::wstring config; std::string tConfig = is19200 ? "baud=19200 parity=N data=8 stop=1" : "baud=115200 parity=N data=8 stop=1"; config.resize(tConfig.size()); for(unsigned int i=0; i<tConfig.size(); i++) config[i] = (WCHAR)tConfig.at(i); BuildCommDCB(config.c_str(),&dcb); dcb.fNull=FALSE; ct.ReadIntervalTimeout=1000; ct.ReadTotalTimeoutMultiplier=0; ct.ReadTotalTimeoutConstant=5000; if( !SetCommState(port,&dcb)) { CloseHandle(port); port = NULL; QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Spyhole error", QString("Cann't set config of %1").arg(QString::fromStdString(nameComPort))); return false; } SetCommTimeouts(port,&ct); PurgeComm(port,PURGE_TXCLEAR|PURGE_RXCLEAR); SetupComm(port,4500,4500); } return true; } bool MainWindow::readCurve(CURVE curve, unsigned char *replay) { unsigned char command[20]; ... WriteFile(port,command, 8, &BytesCnt, NULL); ReadFile(port, replay, 4000, &BytesCnt, NULL); if(BytesCnt != 4000 ) { QApplication::restoreOverrideCursor(); QMessageBox::critical(this, "Spyhole error", QString("Can not receive 4000 byte. Received %1 bytes").arg(BytesCnt)); return false; } return true; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vazz 0 25 декабря, 2016 Опубликовано 25 декабря, 2016 · Жалоба В общем приходится периодически возвращаться к этой теме :) видимо, хочешь не хочешь, а освоить работу с com-портами мне придется. На текущий момент повспоминал все что было, решил создать простенькое windowed приложение для теста com-портов. Так вот, возвращаясь к ранее обсуждаемой на этом форуме проблеме, сообщаю, что как и ранее открыть порт удается, настроить тоже (проверяю записаны ли настройки непосредственно по поинтеру зарезервированного под них куска памяти). Записать данные удалось (вроде бы тут должно быть "уррра!!!"), но только в одном случае - при открытии порта функцией CreateFile я передаю ей параметр dwDesiredAccess равный GENERIC_WRITE. Если при вызове этой функции я указываю GENERIC_READ + GENERIC_WRITE, то запись в порт не происходит. Порт открываю пока обычном режиме (NOT OVERLAPPED). Вопрос: если я открываю порт в НЕ асинхронном режиме, то я могу открыть его только "в одностороннем режиме", т.е. открываю порт для записи, потом закрываю порт и если мне нужно получить ответ от устройства, то я снова открываю порт но уже в режиме чтения и читаю данные? Бредовенько как-то.. В инете куча примеров где в 100% случаев права при вызове функции CreateFile указываются именно как "GENERIC_READ | GENERIC_WRITE", что за фигня у меня, у кого какие мысли? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 25 декабря, 2016 Опубликовано 25 декабря, 2016 · Жалоба что за фигня у меня, у кого какие мысли? Есть такая мысль, что (GENERIC_READ + GENERIC_WRITE) в вашем случае оказывается не равно (GENERIC_READ | GENERIC_WRITE). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 26 декабря, 2016 Опубликовано 26 декабря, 2016 · Жалоба Есть такая мысль, что (GENERIC_READ + GENERIC_WRITE) в вашем случае оказывается не равно (GENERIC_READ | GENERIC_WRITE). хмм... #define GENERIC_READ 0x80000000 #define GENERIC_WRITE 0x40000000 #define GENERIC_EXECUTE 0x20000000 #define GENERIC_ALL 0x10000000 будут они равны, хоть ОРь, хоть складывай Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
gerber 8 27 декабря, 2016 Опубликовано 27 декабря, 2016 · Жалоба будут они равны, хоть ОРь, хоть складывай При сложении будет учтен знак, если константы signed. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
toweroff 0 27 декабря, 2016 Опубликовано 27 декабря, 2016 · Жалоба При сложении будет учтен знак, если константы signed. Ну константы как-то не предполагают знак Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться