Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Программирование интерфейса RS232


Автор: Gremlin 28.8.2006, 11:03
Если ктото имеет информацию по данному вопросу или писал программы большая просьба выложить здесь листинги функций или ссылки на них  где люди смогут найти ответы на свои вопросы! А меня собственно интересует список апи функций для работы с этим интерфейсом! Заранее благодарен! 

Автор: _hunter 28.8.2006, 11:25
Цитата(Gremlin @  28.8.2006,  11:03 Найти цитируемый пост)
А меня собственно интересует список апи функций для работы с этим интерфейсом

если интересует -- почему поиском не воспользовался?
http://www.izone.kiev.ua/articles/delphi/16/282.htm

Автор: chozen 28.8.2006, 23:34
bugtraq.ru/library/programming/rs232.html
www.opennet.ru/openforum/vsluhforumID9/5319.html 

- первые же строчки гугла smile  smile 

Автор: bel_nikita 28.8.2006, 23:53
Цитата(Gremlin @ 28.8.2006,  10:03)
А меня собственно интересует список апи функций для работы с этим интерфейсом!

Собственно одним списком не отделаешься smile 
Тема не раз уже обсуждалась. http://www.codeproject.com/system/serial.asp, правда сделано через MFC, но можешь "заточить" под себя

Автор: Gremlin 29.8.2006, 21:01
ой а нет ли случайно у кого Агуров П. - Последовательные интерфейсы ПК. в электронном варианте выложите сцылочку

Добавлено @ 21:08 
да и ешо вот посмотрел я все выложенные сцылки! у меня в ммануале на прибор сказано типа команда LVn - выбор канала (n=1..10)
или экзамплы (Pc->Instrument) TS4.85E+0 типа выставить погрешность
дак вот я не понял как мне послать данные команды smile 

Автор: GremlinProg 30.8.2006, 07:43
В этом мануале и поищи формат команд для твоего девайса, для RS232 нет специализированного языка, каждый может использовать свой интерфейс ввода-вывода

Автор: Gremlin 30.8.2006, 11:27
а вот  я столкнулся с двумя случаями какой выбрать
есть класс CSerial и HANDLE ? оба открывают порты устанавливают скорость и тд и тп

Автор: chozen 30.8.2006, 11:31
Что-то мне сомнительным кажется наличие класса HANDLE... Мож это не класс, а что-нибудь другое smile  smile  smile ???

Если одинаковые, используй тот, название которого передает смысл области применения - CSerial.

Автор: Gremlin 30.8.2006, 11:39
Код

HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);

lpFileName — указатель на строку с нулевым завершающим символом. Обычно это имя открываемого файла, но в нашем случае это должно быть название порта (COM1, COM2, …). 
dwDesiredAccess — тип доступа. В нашем случае должен быть равен GENERIC_READ|GENERIC_WRITE. 
dwShareMode — параметр совместного доступа. Для коммуникационных портов всегда равен 0. 
lpSecurityAttributes — атрибут защиты. Для коммуникационных портов всегда равен NULL. 
dwCreationDistribution — режим автосоздания. Для коммуникационных портов всегда равен OPEN_EXESTING. 
dwFlagsAndAttributes — атрибут режима обработки. Для коммуникационных портов должен быть равен 0 или FILE_FLAG_OVERLAPPED. 
hTemplateFile — описатель файла-шаблона. Для коммуникационных портов должен быть равен NULL. 
При успешном открытии порта функция возвращает его описатель, а в случае ошибки возвращает INVALID_HANDLE_VALUE.

Добавлено @ 11:49 
Цитата(GremlinProg @  30.8.2006,  07:43 Найти цитируемый пост)
В этом мануале и поищи формат команд для твоего девайса, для RS232 нет специализированного языка, каждый может использовать свой интерфейс ввода-вывода 

Написано так
The protocol structure is defined in the syntax below. Data transfer takes place as simple ASCII protocol with
Command code - 2 characters
Parameters: 1..8 characters
Separator: ,;:/
Terminators: <cr><lf>, <cr> or <lf>
Blanks are ignored
Upper and lower case letters are allowed
и пример дан
Command(PC -> Instrument): TS<cr>
Replay(Instrument -> PC): TS4.26E+0<cr>

Автор: GremlinProg 30.8.2006, 14:11
ну, эта команда, по крайней мере понятна:

Код

struct command_TS{
  char name[2];
  byte args_size;
  char separator;// = '.'
  float param
  char terminator;// = '\r' or '\n'
};

вот, к примеру её инициализация и посылка
Код

command_TS cmd = {{'T','S'},sizeof(float),'.',26E+0,'\n'};
RS232Write(&cmd,sizeof(cmd));

RS232Write - условная функция для посылки в RS232 с двумя параметрами: 1 - адрес данных, 2 - размер данных
PS: структуру надо упаковыть прагмой.

Автор: Fixin 30.8.2006, 14:12
Пример посылки команды
Цитата(Gremlin @  30.8.2006,  11:39 Найти цитируемый пост)
TS<cr>
а это ответ:
Цитата(Gremlin @  30.8.2006,  11:39 Найти цитируемый пост)
TS4.26E+0<cr>


Автор: Fixin 30.8.2006, 14:31
GremlinProg, ты думаешь? Вообщето, послав такую структуру мы не получим команду вида
Цитата(Gremlin @  30.8.2006,  11:39 Найти цитируемый пост)
 TS<cr>
а что-то вроде
Цитата
TS<0x04>.<00><00><D0><41><cr><lf>
вместо
Цитата
TS<cr><lf>


Автор: GremlinProg 30.8.2006, 16:11
Fixin, может быть...

наверное 4.26E+0 - это и есть параметр, тогда нужно сделать иначе:
Код

char szBuffer[1024];
sprintf(szBuffer,"TS%.2e\n",epsilon);
RS232Write(szBuffer,strlen(szBuffer));

а в общем случае, если параметров несколько, разделять их чем нибудь из ",;:/"

Автор: Gremlin 31.8.2006, 17:53
В хидере класса объявил DCB DcbPort;
В конструкторе класса пишу DcbPort.ByteSize = 8;
Поставил точку остановки после этого и смотрю значение DcbPort.ByteSize = 8 +'пустой квадратик'
т.е. эта переменная имеет тип unsigned char, но как такое может быть если оно должно быть типа BYTE _DcbPort.ByteSize! Подскажите пожалуйста как решить данный трабл!

Автор: _hunter 31.8.2006, 18:17
а BYTE это и есть unsigned char (правой кнопкой по BYTE тыкни и там выбери Goto declaration)

Автор: Fixin 2.9.2006, 21:51
Цитата(Gremlin @  31.8.2006,  17:53 Найти цитируемый пост)
как решить данный трабл!
ну это уже офтоповый трабл - это раз, и в чем проблема-то - это два.
имхо, квадратик после циферки в дебаггере - это отображения символа из таблицы ASCII по номеру, в данном случае, 8 - неотображаемый символ, вот и видишь ты квадратик пустой.

Автор: Gremlin 3.9.2006, 12:43
Как мне послать устройству команды описанные выше например TS
Код

if (!SetCommMask(hPort, EV_RXCHAR)) 
         MessageBox("Error setting port mask");

    DWORD dwWrite;
    OVERLAPPED OverWrite;
    BYTE WriteBytes[2] = "TS"; 
    OverWrite.hEvent = CreateEvent(NULL, true, false, NULL);
    if (OverWrite.hEvent == NULL)
        MessageBox("Error creating write event");
    if (!WriteFile(hPort, WriteBytes, sizeof(WriteBytes), &dwWrite, &OverWrite) && (GetLastError() != ERROR_IO_PENDING))
                              MessageBox("Error writing port"); 

 BYTE WriteBytes[2] = "TS"; --- вот здесь как записать команду


Автор: GremlinProg 3.9.2006, 13:24
показал ведь уже:
Код

double epsilon = 4.26E+0;
CHAR WriteBytes[1024]; 
sprintf(WriteBytes,"TS%.2e\n",epsilon);

после выполнения sprintf, в массиве WriteBytes будет содержаться команда TS4.26E+0<CR>
Здесь epsilon выставили в 4.26E+0, но если её поменяешь, соответственно поменяется и команда в массиве WriteBytes

отправляешь WriteBytes так:
Код

WriteFile(hPort, WriteBytes, strlen(WriteBytes), &dwWrite, &OverWrite)

Автор: Gremlin 3.9.2006, 13:50
ок тока чото я не понимаю запись TS%.2e\n и разве не нужно <cr>? 

Автор: GremlinProg 3.9.2006, 14:21
\n - это и есть <cr>, в принципе, исходя из информации, которую ты тут выложил, можно использовать любой из четырех вариантов завершения команды: \n , \r, \r\n, \n\r, я выбрал первый.
%.2e - строка, форматирующая вещественное число в такой вот, экспоненциальный вид: x.xxE+x

Автор: Gremlin 3.9.2006, 14:59
Аааа понятно!! Вот ешо! Я открываю ком порт у него есть такие свойства как parity, bitssize, stopbits какие значения мне необходимо выставить ибо в мануале только сказано что baudrate = 9600, а остальное не сказано smile

Автор: GremlinProg 3.9.2006, 16:34
обычно на железе сильно не заморачиваются, так что обычно програмят с параметрами Dcb,  выставленными следующим образом
Цитата

  Dcb.Parity    = NOPARITY;
  Dcb.ByteSize  = 8;
  Dcb.StopBits  = ONESTOPBIT;

но для большей надежности, я заполняю Dcb исходя из текущего состояния порта, т.е. пееред тем как выставлять Parity, ByteSize..., вызови GetCommState(port,Dcb). Это установит флаги Dcb так, как они были установлены при последнем обращении к порту.

Автор: Gremlin 4.9.2006, 12:40
Сделал так
Код

// --- Перевод в режим прием данных ---
    if (!SetCommMask(hPort, EV_RXCHAR)) 
         MessageBox("Error setting port mask");
    //--- посылка----
    double epsilon = 4.26E+0;
    CHAR WriteBytes[1024]; 
    sprintf(WriteBytes,"TS%.2e\n",epsilon);
    DWORD dwWrite;
    OVERLAPPED OverWrite;
    
    OverWrite.hEvent = CreateEvent(NULL, true, false, NULL);
    if (OverWrite.hEvent == NULL)
        MessageBox("Error creating write event");
    if (!WriteFile(hPort, WriteBytes, sizeof(WriteBytes), &dwWrite, &OverWrite) && (GetLastError() == ERROR_IO_PENDING))
                              MessageBox("Error writing port"); 
    //--- ответ ---
    COMSTAT ComStat;
    DWORD dwMask, dwError;
    OVERLAPPED OverRead;
    CHAR Buf[1024];                         
    DWORD dwRead; 
    OverRead.hEvent = CreateEvent(NULL, true, false, NULL);
    if (OverRead.hEvent == NULL) 
        MessageBox("Error creating read event");

        
    if  (!WaitCommEvent(hPort, &dwMask, &OverRead)) 
    {
        if (GetLastError() == ERROR_IO_PENDING)
            WaitForSingleObject(OverRead.hEvent, INFINITE); 
        else 
            MessageBox("Error waiting port event");
        
    }
    if (!ClearCommError(hPort, &dwError, &ComStat))
           MessageBox("Error clearing port"); 
    
    dwRead = ComStat.cbInQue; 
    if (dwRead > 0) 
    {
        if (!ReadFile(hPort, Buf, dwRead, &dwRead, &OverRead)) 
             MessageBox("Error reading port");
    }

На месте WaitForSingleObject(OverRead.hEvent, INFINITE); он уходит в раздумья типа ничего с прибора не получает ответа даже опшибки smile

Автор: GremlinProg 4.9.2006, 17:42
Цитата(Gremlin @  4.9.2006,  14:40 Найти цитируемый пост)
На месте WaitForSingleObject(OverRead.hEvent, INFINITE); он уходит в раздумья типа ничего с прибора не получает ответа даже опшибки 

перед тем, как отправлять в порт свои команды, пошли в него просто 1-2 байта для синхронизации, например таких: "\0\n". Это, скорее всего, решит проблему.

Автор: Gremlin 5.9.2006, 07:17
ой а мне сказали нужно разделить потоки Thread для чтения тока не сказали как! И кстати у меня не получается послать команду т.е. прибор не реагирует на команду smile

Автор: GremlinProg 5.9.2006, 10:10
всю прверку WaitCommEvent нужно положить в "бесконечный" цикл, а цикл - в отдельный поток. Любое чтение байт из порта нужно каждый раз сбрасывать в отдельный буфер (организовать очередь), а после добавления новых байт в эту очередь - выполнять, нужную тебе, процедуру обработки буфера. Перед работой потока желательно синхронизировать I/O порта с I/O машины (см. предыдущий пост), иначе будешь практически всегда терять, по крайней мере, первый байт как на прием, так и на передачу(возможно из за рассинхронизации команда и не принимается устройством).

Все это нужно делать в идеальном случае.

Автор: Gremlin 8.9.2006, 06:55
Ошибка первая была в том что нужно инициализировать  OVERLAPPED OverRead ={0}; и теперь я нормально посылаю команды Read еще не пробовал но если можно то мне бы сэмпл по поводу создания отдельного потока

Автор: GremlinProg 8.9.2006, 07:11
по идее, OverRead и OverWrite должны быть инициализированы в ноль перед использованием
Цитата(MSDN)

This structure should always be initialized to zero before it is used in a function call. If it is not, the function may fail and return ERROR_INVALID_PARAMETER.


Добавлено @ 07:14 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__beginthread.2c_._beginthreadex.asp

Автор: Gremlin 13.9.2006, 07:09
Сходил по ссылке данной в начале топика http://www.izone.kiev.ua/articles/delphi/16/282.htm там пример но в делфи тама написано так:

"Рассмотрение работы с потоками в Windows, в частности того, как это реализовано в Delphi, выходит за рамки данной статьи. Предполагаю, что читатель встречался или по крайней мере знаком с этим. Скажу лишь, что у любого потока есть главная функция, которая начинает выполняться после его создания. В Delphi для потоков существует класс TThread, а его главная процедура называется TThread.Execute(). 

Вот так выглядит главная процедура отдельного потока, которая ожидает появление одного или нескольких символов и считывает их:

Код

procedure TReadThread.Execute;
var ComStat: TComStat; 
dwMask, dwError: DWORD; 
OverRead: TOverlapped; 
Buf: array[0..$FF] of Byte; 
dwRead: DWORD;
begin OverRead.hEvent := CreateEvent(nil, True, False, nil); 
if OverRead.hEvent = Null then  raise Exception.Create('Error creating read event'); 
FreeOnTerminate := True;  
while not Terminated do begin   
if not WaitCommEvent(hPort, dwMask, @OverRead) 
then   begin    
if GetLastError = ERROR_IO_PENDING 
then      WaitForSingleObject(OverRead.hEvent, INFINITE)    
else      raise Exception.Create('Error waiting port event');   
end;   
if not ClearCommError(hPort, dwError, @ComStat) 
then     raise Exception.Create('Error clearing port');   
dwRead := ComStat.cbInQue;  
 if dwRead > 0 then   begin     
if not ReadFile(hPort, Buf, dwRead, dwRead, @OverRead)
 then       raise Exception.Create('Error reading port');     
// В Buf находятся прочитанные байты     
// Далее идет обработка принятых байтов   
end;
end; 
{while}end; 


В приведенном примере в потоке крутится цикл, тем самым инициируется ожидание события порта вызовом функции WaitCommEvent(), ожидание же самого этого события задается функцией WaitForSingleObject(). Для определения количества принятых символов используется функция ClearCommError(). Когда количество принятых символов (dwRead) известно, непосредственное чтение символов выполняется функцией ReadFile(). "

Как это реализовать в Си? не могу найти какой функцией в Си пользоваться вместо TReadThread.Execute помогите плз!

Автор: GremlinProg 13.9.2006, 09:00
Сходи по ссылкам предыдущего поста. 2 ссылки - 2 решения, выбирай любое, какое нравится. Примеры там же, но для первой ищи For an example, see... в конце страницы.

Автор: Gremlin 15.9.2006, 13:40
Код

uintptr_t _beginthread( 
   void( __cdecl *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);
делаю как в примере только своя функция в потоке а объявление тоже как и в примере
  _beginthread( ReadBuff, 0, NULL );
где
Код

void ReadBuff( void *dummy )
{
    
    repeat = 0;    /* _endthread implied */

}
компилю получаю еггог не может преобразовать void(void *) в void(_cdecl *)(void *) None of the functions whith this name in scope match the target type и что делать?

Автор: dumb 15.9.2006, 13:50
дык
Код

void _cdecl ReadBuff( void *dummy )
{
  repeat = 0;
}

Автор: Gremlin 17.9.2006, 20:59
Не там просил void(cdecl *)(void *) я сделал так объявил в хидере void (__cdecl *ReadABuffer)(void *dummy); без описания _beginthread( ReadABuffer, 0, NULL ); компилит без проблем но кагда я её пытаюсь описать эту функцию
void (__cdecl *ReadABuffer)(void *dummy)
{} то на на скобке вылезает еггог d:\C++_Project\Visual C++.NET\Kistler Measuring Hardware\MultiAmp.cpp(833): error C2470: 'ReadABuffer' : looks like a function definition, but there is no formal parameter list; skipping apparent body
тоесть функция выглядит как функция но не функция гыгы и не знаю что и сделать теперь smile

Автор: Gremlin 18.9.2006, 14:01
Возможно в компиляторе нужно чтото включить? хотя там мультитридинг стоит

Автор: GremlinProg 18.9.2006, 15:42
это называется "гадание на кофейной гуще"
покажи код

Автор: GremlinProg 18.9.2006, 17:54
для _beginthread callback должен выглядеть так:
Код

void __cdecl ReadBuff( void * ptr ){
  ...
}
а для _beginthreadex callback должен выглядеть так:
Код

unsigned __stdcall ReadBuff( void * ptr ){
  ...
}
обе функции порождают поток, только _beginthreadex дает больше параметров для настройки этого потока

void(__cdecl*FType)(void *) - это описание ТИПА функции(здесь имя типа FType)
void __cdecl func(void *) - это описание функции(здесь имя функции func)

разницу видишь?

Автор: Gremlin 19.9.2006, 05:31
Ааааааа два дня сижу думаю твою дивизию тоесть я сделал так в хидере void (__cdecl *ReadABuffer)(void *dummy); а в цпп описываю не указатель а саму функцию void __cdecl ReadABuffer(void *dummy); блин как сразу не допенькалsmile огромное вам спасибо за хелп!!!

Автор: Gremlin 19.9.2006, 08:05
Такс серавно чото не получается вопщем у меня есть класс его хидер:
Код

#pragma once
#include "afxwin.h"


// CMultiAmp dialog

class CMultiAmp : public CPropertyPage
{
    DECLARE_DYNAMIC(CMultiAmp)

public:
    CMultiAmp();
    virtual ~CMultiAmp();

// Dialog Data
    enum { IDD = IDD_DIALOG2 };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    RECT m_RectSpaceWhite;
    DECLARE_MESSAGE_MAP()
public:
    HANDLE hPort;
    virtual BOOL OnInitDialog();
    bool WriteABuffer(char* lpBuf, DWORD dwToWrite);
    CMultiAmp *MultiAmp; // временная переменная для хранений полей во вкладке MultiAmp
    //--- Переменные и обработчики Каналов
    ...
    //--- Переменные и обработчики Меток;
    ...
    //--- Переменные и обработчики Чувствительности
    ...
    //--- Переменные и обработчики единиц Чувствительности
    ...
    //--- Переменные и обработчики Диапазона
    ...
    //--- Переменные и обработчики Единиц измерения
    ...
    //--- Переменные и обработчики Фильтров
    ...
    //--- Переменные и обработчики Постоянной по времени
    ...
    
public:
    CMultiAmp& operator = (const CMultiAmp&); //операция присваивания
    void (__cdecl *ReadABuffer)(void *dummy);
    ...
};

СPP:

Код

// MultiAmp.cpp : implementation file
//

#include "stdafx.h"
#include "Kistler Measuring Hardware.h"
#include "MultiAmp.h"
#include ".\multiamp.h"
#include "RSSetup.h"
#include <process.h>    /* _beginthread, _endthread */




#define MAX_THREADS 2
#define BUF_SIZE 255

// CMultiAmp dialog

IMPLEMENT_DYNAMIC(CMultiAmp, CPropertyPage)
CMultiAmp::CMultiAmp()
    : CPropertyPage(CMultiAmp::IDD)
    
{
}

CMultiAmp::~CMultiAmp()
{
}
CMultiAmp& CMultiAmp::operator = (const CMultiAmp& cmultiamp)
{
...
    return *this;
}
void CMultiAmp::DoDataExchange(CDataExchange* pDX)
{
    CPropertyPage::DoDataExchange(pDX);
    ...
}


BEGIN_MESSAGE_MAP(CMultiAmp, CPropertyPage)
    ...
END_MESSAGE_MAP()


// CMultiAmp message handlers


//}    

BOOL CMultiAmp::OnInitDialog()
{
    CPropertyPage::OnInitDialog();
    // TODO:  Add extra initialization here
    

    //--- Начальная инициализация полей------
    // канал 1
    ...
    // канал 2
    ...
    // канал 3
    ...
    // ----------------------------------------    
    
    //--- Ограничения по вводу в поля
    ...
    

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

bool CMultiAmp::WriteABuffer(char* lpBuf, DWORD dwToWrite)
{    
    OVERLAPPED osWrite = {0};
    DWORD dwWritten;
    DWORD dwRes;
    BOOL fRes;

   // Create this write operation's OVERLAPPED structure's hEvent.
    osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (osWrite.hEvent == NULL)
    {
       // error creating overlapped event handle
        MessageBox("Error creating write event");
        return false; 
    }
    // Issue write.
    if (!WriteFile(hPort, lpBuf, dwToWrite, &dwWritten, &osWrite))
    {    
        if (GetLastError() != ERROR_IO_PENDING) 
        { 
            MessageBox("Error writing port"); 
            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(hPort, &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);
    return fRes;
}
BOOL CMultiAmp::OnApply()
{
    // TODO: Add your specialized code here and/or call the base class
    // --- набор команд ---

    //------------------------ 1 Канал -------------------------
    
    ...
    //------------------------ 2 Канал -------------------------
    
    ...
    //------------------------ 3 Канал -------------------------
    ...
    
    WriteABuffer(&Command[0], strlen(Command));
    
    // ----- Чтение параметров ----------

    _beginthread( ReadABuffer, 0, NULL );

    _endthread();
    return CPropertyPage::OnApply();
}
void __cdecl ReadABuffer(void *dummy)
{
    //--- ответ ---
    CMultiAmp MultiAmp;
    HANDLE hPort = MultiAmp.GethPort();
    COMSTAT ComStat;
    DWORD dwMask, dwError;
    OVERLAPPED OverRead;
    CHAR Buf[1024];                         
    DWORD dwRead; 
    OverRead.hEvent = CreateEvent(NULL, true, false, NULL);
    if (OverRead.hEvent == NULL) 
        AfxMessageBox("Error creating write event");
//

//    
    if  (!WaitCommEvent(hPort, &dwMask, &OverRead)) 
    {
        if (GetLastError() == ERROR_IO_PENDING)
            WaitForSingleObject(OverRead.hEvent, INFINITE);
        else 
            AfxMessageBox("Error waiting port event");
        
    }
//    if (!ClearCommError(hPort, &dwError, &ComStat))
//           MessageBox("Error clearing port"); 
//    
//    dwRead = ComStat.cbInQue; 
//    if (dwRead > 0) 
//    {
//        if (!ReadFile(hPort, Buf, dwRead, &dwRead, &OverRead)) 
//             MessageBox("Error reading port");
//    }
//    // В  Buf находятся прочитанные байты
//    // Далее идет  обработка принятых байтов
}

/// далее идут обработчики событий


И блин если я так объявляю то члены класса не видны в функции ReadABuffer 
а мне нужно чтоб это все в классе делалось smile или подскажи другую реализацию

Автор: GremlinProg 19.9.2006, 10:09
Код

class CMultiAmp : public CPropertyPage{
    ...
public:
    //    StaticReadABuffer - статический callback
    static void __cdecl StaticReadABuffer(void *dummy){
        ((CMultiAmp*)dummy)->ReadABuffer();
    }
    ...
    BOOL OnApply()
    {
        ...
        HANDLE hstream    = (HANDLE)_beginthread(StaticReadABuffer,0,(void*)this);
        WaitForSingleObject(hstream,INFINITE);
        //    WaitForSingleObject не вернет результат, пока поток не завершится,
        //    в данном случае, пока не выполнится процедура ReadABuffer
        //    _endthread() вызывать не нужно, иначе поток завершится преждевременно
        //    WaitForSingleObject можешь поставить в любое нужное тебе место,
        //    но тогда и hstream должен быть виден в классе
        ...
    }
    ...
    void ReadABuffer(void){
        // здесь работаешь уже с классом в потоке
        GethPort();
        ...
    }
    ...
};

Автор: Gremlin 19.9.2006, 17:29
ага сибо мудреное объявление но вроде робитsmile

Автор: GremlinProg 19.9.2006, 18:36
у меня не ругается, компилер другой, вынеси реализацию этих методов в cpp или хотя бы StaticReadABuffer

Автор: Gremlin 19.9.2006, 18:50
Код

void CMultiAmp::ReadABuffer(void)
{
    OVERLAPPED OverRead = {0};
    COMSTAT ComStat;
    DWORD dwMask, dwError;
    char Buf[1024];                         
    DWORD dwRead; 
    if (!SetCommMask(hPort, EV_RXCHAR)) 
        MessageBox("Error setting port mask");
    OverRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (OverRead.hEvent == NULL) 
        MessageBox("Error creating write event");
    if  (!WaitCommEvent(hPort, &dwMask, &OverRead)) 
    {
        if (GetLastError() == ERROR_IO_PENDING)
            WaitForSingleObject(OverRead.hEvent, INFINITE);
        else 
            AfxMessageBox("Error waiting port event");
        
    }
    if (!ClearCommError(hPort, &dwError, &ComStat))
           MessageBox("Error clearing port"); 
    
    dwRead = ComStat.cbInQue; 
    if (dwRead > 0) 
    {
        if (!ReadFile(hPort, Buf, dwRead, &dwRead, &OverRead)) 
             MessageBox("Error reading port");
    }
    // В  Buf находятся прочитанные байты
    // Далее идет  обработка принятых байтов
}

Но я думал что создав другой поток я смогу работать с остальным приложением нормально а оно виснет и ждет ответа с ком порта

Автор: GremlinProg 19.9.2006, 19:01
Цитата(GremlinProg @  19.9.2006,  12:09 Найти цитируемый пост)
WaitForSingleObject не вернет результат, пока поток не завершится

Ну убери WaitForSingleObject вообще, либо поставь перед завершением программы.

Автор: Gremlin 19.9.2006, 19:15
Цитата(GremlinProg @  19.9.2006,  19:01 Найти цитируемый пост)
Ну убери WaitForSingleObject вообще, либо поставь перед завершением программы. 
 А как лучше её внутри ReadABuffer или после закрытия потока?

Автор: GremlinProg 19.9.2006, 20:28
Я говорю вот про вэйт после создания потока :
Код

        HANDLE hstream    = (HANDLE)_beginthread(StaticReadABuffer,0,(void*)this);
        WaitForSingleObject(hstream,INFINITE);

Убери его пока, чтобы ничего не висло. Правильнее будет поставить его перед завершением программы, например в WM_DESTROY (это только в случае, если нужно освободить какие-нибудь ресурсы, используемые в потоке, например буфер, в который ты складываешь инфу с кома или сбросить буфера в файл и т.п.)

Автор: Gremlin 20.9.2006, 08:20
При выполнении
Код

void CMultiAmp::ReadABuffer(void)
{
    char Command[1024] = "LV1;OE1;";
    strcat(Command, "TS");
    strcat(Command, "\n");
    WriteABuffer(&Command[0], strlen(Command));
    if (!PurgeComm(hPort, PURGE_TXCLEAR && PURGE_RXCLEAR)) 
        MessageBox("Error purging port");
    OVERLAPPED OverRead = {0};
    COMSTAT ComStat;
    DWORD dwMask, dwError;
    char Buf[1024];                         
    DWORD dwRead; 
    if (!SetCommMask(hPort, EV_RXCHAR)) 
        MessageBox("Error setting port mask");
    OverRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (OverRead.hEvent == NULL) 
        MessageBox("Error creating write event");
    
    if  (!WaitCommEvent(hPort, &dwMask, &OverRead)) 
    {
        if (GetLastError() == ERROR_IO_PENDING)
            WaitForSingleObject(OverRead.hEvent, INFINITE);
        else 
            AfxMessageBox("Error waiting port event");
    }
   
    if (!ClearCommError(hPort, &dwError, &ComStat))
           MessageBox("Error clearing port"); 
    
    dwRead = ComStat.cbInQue; 
    
    if (dwRead > 0) 
    {
        if (!ReadFile(hPort, Buf, dwRead, &dwRead, &OverRead)) 
             MessageBox("Error reading port");
    }
    
    // В  Buf находятся прочитанные байты
    // Далее идет  обработка принятых байтов
}

заметил что переводит в состояние Ожидание байтов, и даже после выполнения функции и завершения потока я не могу записать в порт. поэтому в конце я стал ставить  
Код

if (!SetCommMask(hPort, 0)
        MessageBox("Error setting port mask");

тогда все нормально!
Но вот проблема начинается в другом! Задача у меня следующая: Есть кнопки Старт и Стоп. Нажимаю Старт и открывается поток с функией Write которая причом в цикле посылает команду опрашивать текущее значение!
Нажимаю клавишу Стоп цыкл останавливается. Сразу после открытия потока Write открывается поток с Read
Код

void CKistlerMeasuringHardwareDlg::OnStart()
{
    // TODO: Add your control notification handler code here
    HANDLE hstream  = (HANDLE)_beginthread(StaticWriteCOM,0,(void*)this);
    HANDLE hstreamr  = (HANDLE)_beginthread(StaticReadCOM,0,(void*)this);
}

Но в buf ничего не приходит тк ком порт занят Write, подскажите как мне разрулить эти два потока!

Автор: Gremlin 6.10.2006, 18:41
вот так реализован цикл
Код

void CKistlerMeasuringHardwareDlg::WriteCOM(void)
{
    if (!PurgeComm(hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR) )
        MessageBox("Error purging port");
    
    MultiAmpT1.hPort = hPort;

    CountMeasuring = 0;
    char CommandStart[5]= "RO1";
    char CommandStop[5]= "RO0";
    char Command[100] = "";
    if (!hPort)
    {
        MessageBox("Нет открытых портов!");
        return;
    }
    
    if(!MultiAmpT1.WriteABuffer(&CommandStart[0], strlen(CommandStart)))
        return;
    if (MultiAmpT1.m_Status1 == true)
        strcat(Command, "LV1;V=;");
    if (MultiAmpT1.m_Status2 == true)
        strcat(Command, "LV2;V=;");
    if (MultiAmpT1.m_Status3 == true)
        strcat(Command, "LV3;V=;");
    if (MultiAmpT1.m_Status4 == true)
        strcat(Command, "LV4;V=;");
    // Активизация кнопок 
    CButton* start = (CButton*) GetDlgItem(IDC_START);
    start->EnableWindow(false);
    CButton* stop = (CButton*) GetDlgItem(IDC_STOP);
    stop->EnableWindow(true);
    while (StopFlag == false)
    {
        MultiAmpT1.WriteABuffer(&Command[0], strlen(Command));
        Sleep(100);
        CountMeasuring++;
    }
    
    
    start->EnableWindow(true);
    stop->EnableWindow(false);

    StopFlag = false;
    CString str;
    str.Format("%i",CountMeasuring);
    
    //MessageBox(str);
    if (!SetCommMask(MultiAmpT1.hPort, 0)) 
        MessageBox("Error setting port mask");
    if(!MultiAmpT1.WriteABuffer(&CommandStop[0], strlen(CommandStop)))
        return;
    return;
}

Автор: Gremlin 8.10.2006, 14:28
Это сообщение отредактировал Fixin - 7.10.2006, 09:03 ????????

Автор: Gremlin 8.10.2006, 14:48
 и еше вопрос почему чтобы получить коректно данные мне приходится вводить Sleep и подбирать милисекунды хотя поидее назначая маску EV_RXCHAR (событие получение символа) а потом идет (!WaitCommEvent(hPort, &dwMask, &OverRead))  тоесть ждать до наступления события маски дак почему мне приходится искуственно вводить задержку?

Автор: GremlinProg 8.10.2006, 22:02
писать то в цикле не надо, это читать может понадобится несколько раз.
пишешь 1 раз, затем начинаешь читать и пока не прочитаешь верный отклик от железки, ни чего писать в порт не надо. Дождись ответа, затем можно снова писать команду и снова читать и т.д. Сделай эту операцию парной чтение-запись, тогда все будет ок.

Добавлено @ 22:07 
поток, по сути нужен только для того, чтобы винду не вешать во время чтения.

Автор: Gremlin 9.10.2006, 05:28
дак мне тогда придется чтобы послать кнопочку старт жать smile ведь мне нужно чтобы команды постоянно посылались до того момента пока я не выключу а как это реализовать без цыкла?????

Добавлено @ 05:30 
я то делаю поток на Write  именно для того чтоб из основного потока смог остановить цыкл и завершить поток

Автор: GremlinProg 9.10.2006, 10:26
Это-то понятно, но в любом случае, на каждую команду записи нужно дождаться отклика. Это можно сделать 2-мя способами:

1.  Использовать события. Создай 2 события с помощью функций CreateEvent, допустим hReadCommand и hAbort. В потоке чтения, после того как отклик получен, поднимаешь событие hReadCommand, на которое реагирует поток записи, он проверяет флаг fStopped и если флаг опущен, то посылает очередной запорс в железку. В конце программы поднимай событие hAbort, на которое реагируют оба потока, они по этому событию будут выходить из цикла, тем самым, савершая потоки. После того, как в основной программе поднимаешь событие hAbort, жди оба потока с помощью функции WaitForMultiplyObjects. Можно завести 3-тье событие hWriteCommand, вместо флага fStopped, которое поднимается при нажатии кнопки "Пролдолжить" и "Старт". На это событие будет реагировать поток записи, оно будет сигнализировать, чтобы начать цикл посылки команд в железо.

2. Использовать сообщения. То же самое, но только заводишь не события а дополнительные сообщения(либо с помощью RegisterWindowMessage, либо просто WM_USER + 500), которые обрабатываешь в основном окне, а вместо сигнализации посылаешь из потока чтения SendMessage самому себе, либо крутишь PostMessage. В этом случае достаточно и 1 потока.

Выбирай любой способ, который по душе. Конечно, не просто, но раз уж взялся за такое дело...

ЗЫ: мусор в буфере как раз и обуславливается бесконечной посылкой в железо команд: в то время, как первая команда начинает ложится в буфер, приходит вторая, в буфере собирается кусок первой и кусок второй и т.д., в конечном счете ни одну команду толком разобрать не можешь, поэтому и ставишь искусственно задержку слипом, не хорошо.

Автор: Gremlin 19.10.2006, 07:08
"В конце программы поднимай событие hAbort, на которое реагируют оба потока, они по этому событию будут выходить из цикла, тем самым, савершая потоки. "
Не понял как это реализовать тоесть потоки должны робить и одновременно ожидать этого события! Следовательно по аналогии с hReadCommand WaitForSingleObject(hAbort, 2000) использовать нельзя дак как мне в любом месте выполнения потока отловить это сообщение и закрыть потоки/циклы?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)