RS232 w C++

0

Witam. Chce stworzyć aplikację która będzie działała jak terminal portu COM, czyli możliwe będzie wysyłanie i odbieranie danych. Stworzyłem taki program (kod zamieszczam poniżej). Odbiór i nadawanie umieszczone są w oddzielnych wątkach. Problem jest taki, że po uruchomieniu programu odbiór znaków (danych) działa poprawnie, natomiast nadawanie nie działa w ogóle. Wygląda to tak jakby funkcja WriteFile() zawieszała się. Dodam jeszcze, że kiedy wykomentuje linię WaitCommEvent() w wątku odbioru to wtedy wszystko jest ok (no oczywiście poza tym że cały czas wywoływana jest funkcja WriteFile()). Czy ktoś wie w czym może być problem.
Pozdrawiam.

#include <windows.h>
#include <stdio.h>
#include <iostream.h>
#include <conio.h>

//////////////////////////////////////////////////////////////////////
DWORD WINAPI watek1(PVOID hCom){

   cout<<"Watek1"<<endl<<flush;

      BOOL fSuccess;
      DWORD eventMask,error,ilosc;
      eventMask=EV_RXCHAR;
      COMSTAT stats;

      char znaki[20];

      SetCommMask(hCom,eventMask);

 while(znaki[0]!='q')
   { 

      WaitCommEvent(hCom,&eventMask,NULL);
      ClearCommError(hCom,&error,&stats);
      cout<<"Bufor:"<<stats.cbInQue<<endl<<flush;
        fSuccess = ReadFile( hCom, znaki, stats.cbInQue, &ilosc, 0);
      *(znaki+ilosc)=NULL;
        if (!fSuccess)
        {
            printf ("ReadFile failed with error %d.\n", GetLastError());
            return 5;
        }

      cout<<znaki<<endl<<flush;   
   }

 cout<<"Koniec watku 1"<<endl;
   return 0;
}

/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI watek2(PVOID hCom){

   cout<<"Watek2"<<endl<<flush;

      BOOL fSuccess;
      char znak='w';
      DWORD ilosc;

   while (znak!='q'){
      znak=getch();
      cout<<znak<<endl;

   fSuccess = WriteFile( hCom, &znak, 1, &ilosc, 0);
   if (!fSuccess)
   {
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return 3;
   }

   }

cout<<"Koniec watku 2"<<endl;

   return 0;
}

////////////////////////////////////////////////////////////////////////////////
int main()
{

    HANDLE hCom;      //uchwyt portu
    DCB dcb;         //konfiguracja portu
    BOOL fSuccess;      //flaga pomocnicza

   //otwarcie portu COM1 z prawami RW
    hCom = CreateFile( TEXT("COM2"), GENERIC_READ | GENERIC_WRITE,
        0,    // exclusive access
        NULL, // default security attributes
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hCom == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile failed with error %d.\n", GetLastError());
        return 1;
    }

   //pobranie aktualnych ustawien portu
    fSuccess = GetCommState(hCom, &dcb);
    if (!fSuccess)
    {
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return 2;
    }

   //ustawienie naszej konfiguracji
   dcb.BaudRate = CBR_9600;     // predkosc transmisji
   dcb.ByteSize = 8;             // ilosc bitow danych
   dcb.Parity = NOPARITY;        // brak bitu parzystosci
   dcb.StopBits = ONESTOPBIT;    // dwa bity stopu

   dcb.fDtrControl = DTR_CONTROL_ENABLE;

    dcb.fRtsControl = RTS_CONTROL_DISABLE;

   fSuccess = SetCommState(hCom, &dcb);

   if (!fSuccess)
   {
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return 3;
   }
 ////////////////////////////////////////////////////////////////////// 

   DWORD watek1_id,watek2_id;
   HANDLE w1,w2;

w1=CreateThread(NULL,0,watek1,(PVOID)hCom,0,&watek1_id);
w2=CreateThread(NULL,0,watek2,(PVOID)hCom,0,&watek2_id);

WaitForSingleObject(w1,INFINITE);
WaitForSingleObject(w2,INFINITE);

CloseHandle(w1);
CloseHandle(w2);

  CloseHandle(hCom);
   return 0;
}
0

Moim zdaniem problem jest w tym że po wykryciu zapisu
znaku do bufora , jest on czytany , ale jego zawartość może sie w tym czasie
zmienic . Proponuję dołożyć sprawdzenie stanu bufora (czy wszystkie znaki zostały przeczytane) ,
bez tego można gubić dane [nie będą odczytywane , pozostaną w buforze nie zauważone 'przez program' ] .

#include <iostream.h>
#include <windows.h>
#include <conio.h>

DWORD WINAPI watek1( LPVOID lpvcom )  // czyta
{
  COMSTAT Stat ;
  DWORD Error ;
  char znak ;
  DWORD d ;
  DWORD mask = EV_RXCHAR ;

      cout << "Watek 1." << endl ;

       SetCommMask(lpvcom,mask) ;

      while(true)
      {
         ClearCommError(lpvcom,&Error,&Stat);
         WaitCommEvent(lpvcom,&mask,NULL);
         while(Stat.cbInQue >0)
         {
          ReadFile(lpvcom,&znak,1,&d,NULL);
          ClearCommError(lpvcom,&Error,&Stat); // aktualizacja Stat.cbInQue 
           cout << znak ;
         }

      }
       return 0 ;
}
//-------------------------------------------
DWORD WINAPI watek2( LPVOID lpvcom )     // pisze
{
 DWORD d ;
 char znak ;
    cout << "Watek 2." << endl ;

    while( 'q'!=(znak=getch()))
    {
        cout << znak ;

      WriteFile(lpvcom,&znak,1,&d,NULL);
    }
     return 0 ;
}
//-------------------------------------------
HANDLE OpenComm(const char*lpFileName)
{
     DCB dcb ;
     HANDLE hCom = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE
                              ,0,NULL,OPEN_EXISTING,0,NULL);

     if(INVALID_HANDLE_VALUE == hCom)
     {
       cout << "Blad ,nie mozna otworzyc portu ." << endl ;
       cin.get();
       return INVALID_HANDLE_VALUE ;
     }

       dcb.DCBlength = sizeof(dcb);

       GetCommState(hCom,&dcb);

       dcb.BaudRate = CBR_9600;
       dcb.fParity = NOPARITY;
       dcb.StopBits = ONESTOPBIT;
       dcb.ByteSize = 7 ;

       SetCommState(hCom,&dcb);

       return hCom ;
}
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char **argv)
{
HANDLE hCom ;
HANDLE w2 ;
DWORD id1;
DWORD id2;

  hCom = OpenComm("COM2");
  if(INVALID_HANDLE_VALUE == hCom)
  {
     return 0 ;
  }
     CreateThread(NULL,0,watek1,hCom,0,&id1);
     w2 = CreateThread(NULL,0,watek2,hCom,0,&id2);

WaitForSingleObject(w2,INFINITE);

CloseHandle(hCom);
        return 0;
}
         while(Stat.cbInQue >0)
         {
          ReadFile(lpvcom,&znak,1,&d,NULL);

Użyłem czytania po jednym znaku , można przerobić na większy buf...
tyle że to bez znaczenia ,wątpię aby się przydał , WaitCommEvent(
zadziała chyba szybciej od klawiatury i piszącego .

Jeszcze dodatkowo WaitCommEvent blokuje , przynajmniej u mnie wątek2 dopóki
wątek1 nie otrzyma jakiegoś znaku , dziwna sprawa ,,,
A więc proponuję wywalić całkiem WaitCommEvent :

#include <windows.h>
#include <iostream.h>
#include <cstring.h>

using namespace std ;

const int SizeBuf = 56 ;
const int MaxLen  = SizeBuf - 1 ;

unsigned char OutBuf[SizeBuf]={0};

DWORD WINAPI watek1( LPVOID lpvcom )  // czyta
{
  COMSTAT Stat ;
  DWORD Error ;
  DWORD d ;
  DWORD mask  ;

      cout << "Watek 1." << endl ;

       GetCommMask(lpvcom,&mask);
       SetCommMask(lpvcom,mask|EV_RXCHAR) ;

      while(true)
      {
         ClearCommError(lpvcom,&Error,&Stat);
         while(Stat.cbInQue >0)
         {
             if(Stat.cbInQue < MaxLen)
            {
               ReadFile(lpvcom,OutBuf,Stat.cbInQue,&d,NULL);
               OutBuf[Stat.cbInQue]='\0' ;
               cout << OutBuf ;
            }else{
                    ReadFile(lpvcom,OutBuf,MaxLen,&d,NULL);
                    OutBuf[MaxLen]='\0' ;
                    cout << OutBuf ;
                 }

            ClearCommError(lpvcom,&Error,&Stat); // aktualizacja
                  // COMSTAT Stat.cbInQue
         }
                // WaitCommEvent(lpvcom,&mask,NULL);
      }
       return 0 ;
}
//-------------------------------------------
DWORD WINAPI watek2( LPVOID lpvcom )     // pisze
{
    cout << "Watek 2." << endl ;
 string a = "" ;
 string info = "odebrano - " ;
 DWORD mask  ;
 DWORD d ;
       GetCommMask(lpvcom,&mask);
       SetCommMask(lpvcom,mask|EV_TXEMPTY) ;

    while( 'q'!= a[0] )
    {
     getline(cin,a);
     info += a ;
     info += "\n" ;
       WriteFile(lpvcom,info.c_str(),info.length(),&d,NULL);
      WaitCommEvent(lpvcom,&mask,NULL);
     info = "odebrano - " ;
    }
         return 0 ;
}
//-------------------------------------------
HANDLE OpenComm(const char*lpFileName)
{
     DCB dcb ;
HANDLE hCom = CreateFile(lpFileName,GENERIC_READ|GENERIC_WRITE
                              ,0,NULL,OPEN_EXISTING,0,NULL);
     if(INVALID_HANDLE_VALUE == hCom)
     {
       cout << "Blad ,nie mozna otworzyc portu ." << endl;
       cin.get();
       return INVALID_HANDLE_VALUE ;
     }

       dcb.DCBlength = sizeof(dcb);

       GetCommState(hCom,&dcb);

       dcb.BaudRate = CBR_9600;
       dcb.fParity = NOPARITY;
       dcb.StopBits = ONESTOPBIT;
       dcb.ByteSize = 7 ;

       SetCommState(hCom,&dcb);

       return hCom ;
}
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char **argv)
{
HANDLE hCom ;
HANDLE w2 ;
DWORD id1;
DWORD id2;

  hCom = OpenComm("COM2");
  if(INVALID_HANDLE_VALUE == hCom)
  {
     return 0 ;
  }
     w2 = CreateThread(NULL,0,watek2,hCom,0,&id2);
          CreateThread(NULL,0,watek1,hCom,0,&id1);

WaitForSingleObject(w2,INFINITE);
CloseHandle(hCom);
        return 0;
}

Ale i tak d..pa , pod Win98 działa a pod XP nie [?] ...zwiecha .
Program działa prawidłowo po usunięciu WaitCommEvent z wątku 1 czytającego pod XP .
Pod 98 działa i z WaitCommEvent .[?]
Przemyślę ,,,,
Testowałem na jednej maszynie .
Pod win98 chodzi po spięciu pin 2 i 3 na COM . [ nie spr. na oddzielnych comach]
w jednej konsoli chodzi zapis i odczyt bez problemu .

Pod XP nie chodzi na spiętych COM1 i COM2 jak i na pojedyńczym COM spięte końcówki 2 i 3
Nie sprawdzałem na połączonych komputerach , ale chyba nie powinno mieć to znaczenia .
na razie nie wiem o co chodzi , widzę ciemność ...

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0