PDA

Visualizza la versione completa : [VC++] Porta seriale e thread


cicciodevoto
27-11-2008, 14:45
Ciao a tutti,
non so se questo è il posto giusto dove postere questo messaggio, se no scusatemi.
Arrivo subito al punto, sto realizzando un programma con il Microsoft Visual C++ 2008 Express Edition che dialoga con una scheda mediante seriale.
Dato che non ne sapevo niente di come comunica il VC++ con seriale, ho cercato un pò in rete e alla fine trovato dei tutorial, ma ora mi si pone un problema.
Il codice realizzato è il seguente:



#include<iostream>
#include "stdafx.h"
#include "windows.h"
#include "conio.h"
using namespace std;

BOOL setComm(HANDLE hComm)
{
DCB dcb;
BOOL res;

FillMemory(&dcb, sizeof(dcb), 0);
res = GetCommState(hComm, &dcb);
if (!res)
return FALSE;

dcb.ByteSize = 8;
dcb.StopBits = TWOSTOPBITS;
dcb.BaudRate = CBR_57600;
dcb.Parity = NOPARITY;
dcb.fAbortOnError = 0;

res = SetCommState(hComm, &dcb);

if (!res)
return FALSE;

DWORD err = GetLastError();
if ( err)
cout << "Errore " << err << endl;

return TRUE;
}

void state(HANDLE hComm)
{
DCB dcb;
BOOL res;

FillMemory(&dcb, sizeof(dcb), 0);
res = GetCommState(hComm, &dcb);

DWORD err = GetLastError();
if ( err)
cout << "Errore ricevuto " << err << endl;

SetLastError(0);
}

BOOL write(HANDLE hComm, char * buf)
{
DWORD nNumberOfBytesToWrite = strlen(buf);
DWORD NumberOfBytesWritten;
LPOVERLAPPED lpOverlapped = NULL;
BOOL res = WriteFile(
hComm,
buf,
nNumberOfBytesToWrite,
&NumberOfBytesWritten,
lpOverlapped
);
if (res)
cout << "Scrittura OK " << endl;
else
{
DWORD err = GetLastError();
cout << "Errore in Scrittura " << err;
}

return res;
}


int main(int argc, char* argv[])
{
char gszPort[] = "COM1";

HANDLE hComm;
hComm = CreateFile( gszPort,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);

if (hComm == INVALID_HANDLE_VALUE)
{
cout << "Errore nell'apertura della porta " << endl;
}
else
{
char comando;
char* com = &comando;
cout << "inserisci un comando ";
cin >> comando;
cout << endl;
cout << "comando inserito " << comando << endl;
if (comando == 't' || comando == 'v')
{
cout << "il comando inserito può essere eseguito" << endl;

// qui devo modificare
char c;
char CR[] = {13,10,0};
DWORD nNumberOfBytesToRead = 1;
DWORD NumberOfBytesRead=0;
LPOVERLAPPED lpOverlapped = NULL;
BOOL bResult;

bResult = setComm(hComm);

// questo deve essere modificato
write(hComm, com);
//write(hComm, CR);
//write(hComm, CR);

for(;;)
{
nNumberOfBytesToRead = 1;
bResult = ReadFile(
hComm,
&c,
nNumberOfBytesToRead,
&NumberOfBytesRead,
lpOverlapped
);

if (NumberOfBytesRead>0)
cout << c;
//printf("%c", c);
}
}
else
{
cout << "il comando inserito non appartiene ai comandi che possono essere eseguiti" << endl;
}

CloseHandle(hComm);
}
cout << endl;
getch();
return 0;
}


Con la seriale riesco a comunicare ma, come dice anche il tutorial, il programma va in "wait", quindi si blocca tutto.
Il tutorial suggeriva di "threadare" la lettura e scrittura su seriale.
Ho provato a lavorare su questo punto ma trovo delle difficoltà, mi potete dare qualche suggerimento o dove posso trovare materiale?
Grazie mille
Ciccio

MItaly
27-11-2008, 15:36
In che senso trovi delle difficoltà? Cosa non ti è chiaro?

cicciodevoto
27-11-2008, 15:50
Quello che ho capito è che per usare i thread devo scrivere una cosa del genere:



DWORD WINAPI ThreadProc (LPVOID lpParameter)
{
...

qui scrivo la funzione che deve essere "threaderata" di nome "ThreadProc"
...
}

int main (int argc, char* argv[])
{
...

scrivo il programma e per far eseguiere la funzione ThreadProc scrivo:

DWORD ID1;
HANDLE funz = CreateThread(NULL, 0, ThreadProc, &Param, 0, &ID1);

...
}


Giusto?
Ora mi chiedo se le funzioni che devo threaderare sono le funzioni di scrittura e lettura su seriale, che hanno parametri in ingresso, così come le ho scritte nel programma, come si legano le cose?
Devo scrivere una cose del genere:



DWORD WINAPI write (LPVOID lpParameter)
{
BOOL write(HANDLE hComm, char * buf)
{
DWORD nNumberOfBytesToWrite = strlen(buf);
DWORD NumberOfBytesWritten;
LPOVERLAPPED lpOverlapped = NULL;
BOOL res = WriteFile(
hComm,
buf,
nNumberOfBytesToWrite,
&NumberOfBytesWritten,
lpOverlapped
);
if (res)
cout << "Scrittura OK " << endl;
else
{
DWORD err = GetLastError();
cout << "Errore in Scrittura " << err;
}

return res;
}

}


Non credo che funzioni così.
Non riesco a capire come conciliare le cose.
Grazie
Ciccio

MItaly
27-11-2008, 16:02
struct writeParams
{
HANDLE hComm;
char * buf;
};

BOOL write(HANDLE hComm, char * buf)
{
DWORD nNumberOfBytesToWrite = strlen(buf);
DWORD NumberOfBytesWritten;
LPOVERLAPPED lpOverlapped = NULL;
BOOL res = WriteFile(
hComm,
buf,
nNumberOfBytesToWrite,
&NumberOfBytesWritten,
lpOverlapped
);
if (res)
cout << "Scrittura OK " << endl;
else
{
DWORD err = GetLastError();
cout << "Errore in Scrittura " << err;
}

return res;
}

DWORD WINAPI WriteThreadProc (LPVOID lpParameter)
{
writeParams * wp=(writeParams *)lpParameter;
return (DWORD) write(wp->hComm,wp->buf);
}

int main (int argc, char* argv[])
{
//...
writeParams wp;
wp.hComm=quello che ci devi mettere;
wp.buf=quello che ci devi mettere;
HANDLE hWriteThread = CreateThread(NULL, 0, WriteThreadProc, &wp, 0, NULL);
//...
}

cicciodevoto
27-11-2008, 16:30
Ti ringrazio per l'aiuto.
Ora penso che dovrò fare la stessa cosa anche con la funzione di lettura.
Grazie mille
Ciccio

MItaly
27-11-2008, 20:48
Di niente, ciao! :ciauz:

cicciodevoto
28-11-2008, 11:46
Scusatemi ragazzi ma ho un altro problema su questo programma.
Se vedete nel codice, pongo alla fine il comando:


CloseHandle(hComm);

questo dovrebbe essere il comando di chiusura della porta COM, giusto?
O sto prendendo una cantonata?

Mi è sorto il dubbio perchè se avvio il programma e do un comando questo me lo esegue e ottengo il risultato atteso, se lo riavvio il programma me lo esegue ma non mi da nessun risultato.
Ho la sensazione che la porta COM rimanga aperta dopo che il programma è terminato, infatti devo resettare la scheda in maniera hardware.
Avete qualche suggerimento?
Grazie
Ciccio

MItaly
28-11-2008, 21:27
Prima della chiusura dell'handle attendi che i thread abbiano terminato il loro lavoro con la API WaitForMultipleObjects.


//...
HANDLE threadHandles[2];
writeParams wp;
//...
threadHandles[0] = CreateThread(NULL, 0, WriteThreadProc, &wp, 0, NULL);
//...
readParams rp;
//...
threadHandles[1] = CreateThread(NULL, 0, ReadThreadProc, &rp, 0, NULL);
//...
WaitForMultipleObjects(2,threadHandles,TRUE,INFINI TE);
CloseHandle(threadHandles[0]);
CloseHandle(threadHandles[1]);
CloseHandle(hComm);

cicciodevoto
02-12-2008, 15:38
Ciao MItaly,
ti ringrazio dei suggerimenti, ma avrei ancora bisogno del tuo aiuto e di quello di altri...

Trascurando il fatto che ieri sera il programma funzionava e questa mattina non aveva proprio voglia di andare...
Ho creato un thread solo per la scrittura e, fino a ieri sera, tutto funzionava.
Questa mattina ho fatto rigirare il programma e si bloccava, non mi dava ne scrittura ne lettura.
Ho messo questo pezzo di codice:



...
HANDLE threadHandles[1];
...
threadHandles[0] = CreateThread(NULL, 0, WriteThreadProc, &wp, 0, NULL);
WaitForMultipleObjects(1,threadHandles,TRUE,INFINI TE);
...


e in questo modo riuscivo a inviare il comando e a leggerne la risposta.
Penso che sia tutto un problema di sincronizzazione con la seriale.
Ho provato a creare un thread per la funzione di lettura, e ho scritto:



BOOL read(HANDLE hComm, char read_c)
{
DWORD nNumberOfBytesToRead = 1;
DWORD NumberOfBytesRead;
LPOVERLAPPED lpOverlapped = NULL;

BOOL res1 = ReadFile(
hComm,
&read_c,
nNumberOfBytesToRead,
&NumberOfBytesRead,
lpOverlapped
);
return res1;
}

struct readParams
{
HANDLE hComm;
char read_c;
};

DWORD WINAPI ReadThreadProc (LPVOID lpParameter)
{
readParams * rp=(readParams *)lpParameter;
return (DWORD) read(rp->hComm, rp->read_c);
}


e dove mi serve:



for(;;)
{
rp.read_c=c;
threadHandles[1] = CreateThread(NULL, 0, ReadThreadProc, &rp, 0, NULL);

if (NumberOfBytesRead>0)
cout << c;

int keydown = _kbhit();
if (keydown)
break;
}


ma dopo la lettura del buffer non esce dal for.
Non esce dal for anche se non utilizzo il thread di lettura e scrivo:



for(;;)
{

nNumberOfBytesToRead = 1;
bResult = ReadFile(
hComm,
&c,
nNumberOfBytesToRead,
&NumberOfBytesRead,
lpOverlapped
);

if (NumberOfBytesRead>0)
cout << c;

int keydown = _kbhit();
if (keydown)
break;
}


Sinceramente non so proprio che fare.
Avete dei suggerimenti?
Grazie
Ciccio

cicciodevoto
03-12-2008, 15:11
Ciao a tutti,
il problema legato all'uscita da quel for l'ho risolto, era legato al _kbhit() che non funzionava a dovere.
Grazie
Ciccio

Loading