Avatar billede jordan_ulswood Nybegynder
30. november 2004 - 12:15 Der er 9 kommentarer og
1 løsning

Seriel kommunikation i Win32

Hej Eksperter!

Jeg ønsker at skrive og læse fra COM porten fra min Win32 applikation, skrevet i C (og bruger WinAPI). Dette går også fint så længe det er non-overlapped fil-operationer. Problemet er nu, at jeg ikke ved hvornår der modtages noget på COM porten. Er det muligt at lave det interruptstyret (eller lign.) således at når der modtages data på porten kaldes en funktion, som læser på porten og lægger det læste data over i en buffer (evt. en fil).

Vil dette kunne lade sig gøre eller er det nødvendig at starte en separat proces op, som hele tiden overvåger porten?

Jeg har haft kig på det sidste løsning (separat proces), som nok kan laves ved at læse porten som Overlapped, men jeg syntes dokumentationen på MSDN er forvirrende (Har læst http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp), og ville derfor gerne lave det lidt mere "lige til" :)

Håber nogen kan hjælpe! Alt kan bruges, men det ville være perfekt med noget konkret kode.

Hilsen Jesper

NB. Det skal lige tilføjes at jeg har læst andre spm på eksperten angående seriel kommunikation, men syntes ikke at der var noget jeg kunne bruge..
Avatar billede bertelbrander Novice
30. november 2004 - 23:22 #1
Man kan godt lave en separat process til at læse ved Non-overlapped IO.
Ulempen ved denne metode er at skrive operationen vil blive blokeret indtil læse operationen er færdig (og omvendt).
Man kan sætte læse timeout ned til f.ex. et sek, skrive operationen vil da højest blive blokeret i et sek; om det er acceptablet ahænger mest af applikationen, hvis det er kritisk kan man evt bruge to tråde, en til at læse og en til at skrive.
Jeg tror jeg har et eksempel på dette til at ligge.

Jeg har kikket lidt på overlapped, men aldrig fået det til at virke, men jeg kan måske strikke noget sammen på et par dage (overvejer at lave et program til at sende og modtage SMS via en mobil tilsluttet com-porten).
Avatar billede bertelbrander Novice
01. december 2004 - 00:34 #2
Skal det være C, eller må der godt bruges C++?
Hvilken kompiler bruger du?

Jeg har leget lidt mere med non-overlapped IO. Det bedste resultat opnår jeg ved at sætte rx-timeout til 0 så ReadFile returnerer øjeblikkeligt og så lave et lille delay i loopen (Sleep(100)).
Avatar billede jordan_ulswood Nybegynder
01. december 2004 - 13:36 #3
Først og fremmest tak for responsen, jeg var bange for at folk havde fået nok at seriel kommunikation her på eksperten og ikke gad at svare :)
Jeg er pt. i gang med at kigge på noget multithreading i Petzold, men vender lige tilbage i løbet af en times tid med status.
Koden skal holdes i C, og jeg bruger VS.NET
Avatar billede jordan_ulswood Nybegynder
01. december 2004 - 15:23 #4
Jeg har nu arbejdet på at starte en seperat tråd op, som bruger overlapped io til læse og skrive på porten, men det volder en del kvaler..

Du skriver at du måske har et eksempel til at ligge, som starter to tråde op som så hhv. læser og skriver vha non-overlapped io. Er dette skrevet i C (eller nemt at skrive om til C)? Det vil jeg meget gerne prøve at kigge på så.

Hilsen Jesper
Avatar billede jordan_ulswood Nybegynder
01. december 2004 - 16:05 #5
Hvis det beskriver lidt klarere hvad det er jeg prøver på, har jeg lagt koden op på www.tornado-kompagniet.dk/kode/SerialCom.c

Den version, der ligger der nu virker dog ikke :/ Jeg har problemer med at starte tråden op, men kan ikke lige se fejlen..

Håber du kan hjælpe! :)
Avatar billede jordan_ulswood Nybegynder
01. december 2004 - 16:11 #6
Det bør tilføjes at det er noget jeg har forsøg at flække sammen fra en c++ klasse til serial komm, som jeg har fundet på nettet, men da jeg er under lidt af et tidspres, er der desværre ikke lige tid til at opfinde hjulet endnu engang.
Avatar billede bertelbrander Novice
01. december 2004 - 20:34 #7
Det blev til et meget simelt terminal program. Det kan bruges til at sende AT-kommandoer til et modem. Du skriver blot kommandoen (F.ex. AT) og trykker enter, svaret fra modemet vil blive vist øverst.

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

typedef struct
{
  HANDLE Port;
  DWORD  MainThreadId;
}ThreadParamType;

void GotoXY(int x, int y);
BOOL KeyHit(void);
WORD GetChar(void);
HANDLE StdInHandle;
HANDLE StdOutHandle;

void SetTimeOut(HANDLE Port)
{
  COMMTIMEOUTS commtimeouts;
  GetCommTimeouts(Port, &commtimeouts);

  commtimeouts.ReadIntervalTimeout = MAXDWORD;
  commtimeouts.ReadTotalTimeoutMultiplier = 0;
  commtimeouts.ReadTotalTimeoutConstant = 0;
  SetCommTimeouts(Port, &commtimeouts);
}

void Tx(HANDLE Port, const char *data)
{
  DWORD Dummy;
  WriteFile(Port, data, strlen(data), &Dummy, 0);
  WriteFile(Port, "\r\n", 2, &Dummy, 0);
}

DWORD Rx(HANDLE Port, void *Buffer, int MaxSize)
{
  DWORD Length;
  ReadFile(Port, Buffer, MaxSize, &Length, 0);
  return Length;
}

DWORD WINAPI RxThreadProc(LPVOID Parameter)
{
  ThreadParamType *ThreadParam = (ThreadParamType *)Parameter;
  while(1)
  {
      char Buffer[256], *p;
      int len;
      len = Rx(ThreadParam->Port, Buffer, sizeof(Buffer));
      if(len)
      {
        p = malloc(len);
        memcpy(p, Buffer, len);
        PostThreadMessage(ThreadParam->MainThreadId, 1001, len, (LPARAM )p);
      }
      Sleep(100);
  }
}

DWORD WINAPI TxThreadProc(LPVOID Parameter)
{
  ThreadParamType *ThreadParam = (ThreadParamType *)Parameter;
  while(1)
  {
      MSG msg;
      GetMessage(&msg, NULL, 0, 0xFFFF);
      Tx(ThreadParam->Port, (char *)msg.wParam);
      free((char *)msg.wParam);
      Tx(ThreadParam->Port, "\r\n");
  }
}

int main(void)
{
  DWORD RxThreadId, TxThreadId;
  ThreadParamType ThreadParam;
  MSG msg;
  char InBuffer[60];
  int idx, i;
  DCB dcb;
  HANDLE ComPort = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  if(ComPort == INVALID_HANDLE_VALUE)
  {
      fprintf(stderr, "Failed to open port\n");
      return 0;
  }
  StdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  StdInHandle = GetStdHandle(STD_INPUT_HANDLE);
  ThreadParam.Port = ComPort;
  ThreadParam.MainThreadId = GetCurrentThreadId();

  GetCommState(ComPort, &dcb);
  dcb.BaudRate = 9600;
  dcb.ByteSize = 8;
  dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  dcb.fOutxCtsFlow = 1;
  SetCommState(ComPort, &dcb);
  SetTimeOut(ComPort);
  CreateThread(0, 0, RxThreadProc, (LPVOID )&ThreadParam, 0,  &RxThreadId);
  CreateThread(0, 0, TxThreadProc, (LPVOID )&ThreadParam, 0,  &TxThreadId);

  Sleep(1000);  /* Let the threads start */

  GotoXY(0, 0);
  for(i = 0; i < 22; i++)
      printf("                                                                \n");

  idx = 0;
  GotoXY(idx, 20);
  while(1)
  {
      if(PeekMessage(&msg, NULL, 0, 0xFFFF, PM_REMOVE))
      {
        char *p;
        GotoXY(0, 0);
        for(i = 0; i < 20; i++)
            printf("                                                                \n");
        p = (char *)msg.lParam;
        GotoXY(0, 0);
        for(i = 0; i < (int )msg.wParam; i++)
            if(p[i] != '\r')
              putc(p[i], stdout);
        free(p);
        GotoXY(idx, 20);
      }
      else if(KeyHit())
      {
        WORD Key = GetChar();
        GotoXY(idx, 20);
        if(Key == VK_RETURN)
        {
            char *p = malloc(idx + 1);
            InBuffer[idx] = 0;
            strcpy(p, InBuffer);
            PostThreadMessage(TxThreadId, 1002, (WPARAM )p, 0);
            idx = 0;
        }
        else if(idx < sizeof(InBuffer) - 2)
        {
            InBuffer[idx] = (char )Key;
            GotoXY(idx, 20);
            fputc((char )Key, stdout);
            idx++;
        }
      }
      else
        Sleep(50);
  }
  return 0;
}

void GotoXY(int x, int y)
{
  COORD c;
  c.X = (short )x;
  c.Y = (short )y;
  SetConsoleCursorPosition(StdOutHandle, c);
}

BOOL KeyHit()
{
  DWORD NumEvents, NumEventsRead;
  INPUT_RECORD *InputRecord;
  DWORD i;
  GetNumberOfConsoleInputEvents(StdInHandle, &NumEvents);

  InputRecord = (INPUT_RECORD *)malloc(sizeof(INPUT_RECORD)*NumEvents);
  PeekConsoleInput(StdInHandle, InputRecord, NumEvents, &NumEventsRead);

  for(i = 0; i < NumEventsRead; i++)
  {
    if(InputRecord[i].EventType & KEY_EVENT && InputRecord[i].Event.KeyEvent.bKeyDown)
    {
      if(InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_CONTROL &&
        InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_MENU  &&
        InputRecord[i].Event.KeyEvent.wVirtualKeyCode != VK_SHIFT)
      {
        free(InputRecord);
        return TRUE;
      }
    }
  }
  free(InputRecord);
  return FALSE;
}

WORD GetChar()
{
  DWORD NumEventsRead;
  INPUT_RECORD InputRecord;

  while(1)
  {
    if(!ReadConsoleInput(StdInHandle, &InputRecord, 1, &NumEventsRead))
      return 0;
    if(InputRecord.EventType & KEY_EVENT && InputRecord.Event.KeyEvent.bKeyDown)
    {
      if(InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_CONTROL &&
        InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_MENU  &&
        InputRecord.Event.KeyEvent.wVirtualKeyCode != VK_SHIFT)
      {
        return InputRecord.Event.KeyEvent.wVirtualKeyCode;
      }
    }
  }
}
Avatar billede jordan_ulswood Nybegynder
02. december 2004 - 00:35 #8
Det ser ganske brugbart ud. Jeg kigger lige noget mere på det imorgen, men indtil videre tak for hjælpen; du er velkommen til at smide et svar, hvis du vil? Jeg har ikke umiddelbart brug for andre kommentarer.

Hilsen Jesper
Avatar billede bertelbrander Novice
02. december 2004 - 01:07 #9
Jeg samler ikke på point.
Avatar billede jordan_ulswood Nybegynder
02. december 2004 - 14:45 #10
Ok. Mange tak for hjælpen! :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester