Problema (forse noto) con SerialPort

martedì 19 giugno 2007 - 09.13

glannino Profilo | Newbie

Salve a tutti,

premetto che provengo dalla filosofia VB6 per cui ho iniziato a curarmi del multithreading (relativamente) da poco.

Ho un'applicazione con due form, su uno dei quali ho un componente SerialPort.
Appena ricevo i dati sulla seriale, prelevo alcune info da un db (SQL Server) e vorrei visualizzarle sul secondo form... tutto OK se non fosse che il secondo form - pur aprendosi - non visualizza i controlli (label e pulsanti), in pratica la UI non viene disegnata.
Le operazioni vanno tutte a buon fine eccetto che per la visualizzazione del Form2. Quasi certamente si tratta di separare i vari thread ma dopo alcuni tentativi ho ottenuto sempre lo sresso risultato.
Ecco il codice:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Grazie per l'aiuto
G.Lannino

filippo.monti Profilo | Junior Member

Hai provato a mettere la Form2.Show nella COM1_DataReceived?
Inoltre se la card è non registrata presuppongo che la form2 non debba essere visualizzata...
Mettendo inoltre la show sulla form2 questa ti si apre ma poi si dovrebbe chiudere subito in quanto l'applicativo continua nell'esecuzione della HandleData (mettendola come ultima istruzione nella COM1_DataReceived questo non dovrebbe succedere...

Ciao
Filippo

glannino Profilo | Newbie

>Hai provato a mettere la Form2.Show nella COM1_DataReceived?

Si, in realtà sono partito da lì, ma poi credevo che in qualche modo la porta COM fosse gestita come thread critico e quindi impedisse al form di disegnarsi.

>Inoltre se la card è non registrata presuppongo che la form2
>non debba essere visualizzata...

Giusto...

>Mettendo inoltre la show sulla form2 questa ti si apre ma poi
>si dovrebbe chiudere subito in quanto l'applicativo continua
>nell'esecuzione della HandleData (mettendola come ultima istruzione
>nella COM1_DataReceived questo non dovrebbe succedere...

Infatti creando un thread separato la form2 appare solo per un istante e poi scompare.
A dare il problema è la gestione "single-thread" cui ero abituato... Inoltre sono quasi certo che il problema stia nella SerialPort, perchè simulando la ricerca nel db con un dato fisso (non letto dalla seriale) la form2 viene visualizzata senza problemi, con tutte le info :-(

>
>Ciao
>Filippo

Ciao e grazie
Gabriele

filippo.monti Profilo | Junior Member

Sappi che la seriale invia i dati uno alla volta e quindi devi intercettare il fatto che dalla seriale non ci siano più dati da trasmettere...
Io ho realizzato una Sub receiveData per leggere tutti i dati tramite un cliclo e poi quando dalla seriale ricevo un carattere particolare (nel mio caso un carriage return) li mostro a video.
Praticamente la sub gestisce l'evento DataReceived dell'oggetto seriale memorizzando in una variabile "charLetti" la proprietà BytesToRead.
Quando arrivo a leggere il Carriage Return mostro la form a video e ti giuro che funziona.
Ciao

Filippo

glannino Profilo | Newbie

>Sappi che la seriale invia i dati uno alla volta e quindi devi
>intercettare il fatto che dalla seriale non ci siano più dati
>da trasmettere...

Lo so, ma il metodo .ReadExisting dovrebbe svuotare l'intero buffer, senza bisogno di ciclare...

>Io ho realizzato una Sub receiveData per leggere tutti i dati
>tramite un ciclo e poi quando dalla seriale ricevo un carattere
>particolare (nel mio caso un carriage return) li mostro a video.

Siamo sulla stessa barca. Io prelevo i dati da un dispositivo barcode seriale che mi fornisce una stringa + CRLF.

>Praticamente la sub gestisce l'evento DataReceived dell'oggetto
>seriale memorizzando in una variabile "charLetti" la proprietà
>BytesToRead.

Fatto anche questo:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Mi sto convincendo che questa classe SerialPort del framework ha qualche difettuccio, come fu per il suo predecessore MSComm.ocx...
In pratica non so più che pesci pigliare, se per te non ci sono problemi puoi farmi dare un'occhiata alla parte di codice che hai utilizzato per questa operazione? (meglio se VB ma anche C# va bene)

Grazie mille
Gabriele

glannino Profilo | Newbie

Errata corrige sul codice postato:

Public Sub COM1_DataReceived(....

barcode += Chr(ch)
ch = COM1.ReadChar() 'dimenticato

....

End Sub

Ciao

glannino Profilo | Newbie

Prova e riprova, ho risolto utilizzando il metodo ShowDialog() anzichè il metodo Show().

Inutile dire che non mi spiego "esattamente" il perchè della cosa (e qui ogni suggerimento è ben accetto) ma, trattandosi di una soluzione più che accettabile, non indagherò ulteriormente. Questo però mi da la conferma che un ripassino sul multithreading mi farebbe proprio bene... ;->

Ciao e Grazie
Gabriele

filippo.monti Profilo | Junior Member

Il problema è relativo al fatto che la lettura dei dati dalla seriale è asincrona rispetto al resto del programma: utilizzi un gestore di eventi che rimane in attesa e viene scatenato all'arrivo del primo carattere della seriale (e non alla fine di tutti i caratteri letti) mentre il resto del programma è in esecuzione.
La mia procedura per la ricezione dati è la seguente:

' Ricezione dati dalla seriale
Public Sub receiveData(ByVal sender As Object, ByVal e As IO.Ports.SerialDataReceivedEventArgs) Handles m_seriale.DataReceived
Dim bufferChar As Char() = New Char() {"0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c, "0"c}
Dim charLetti As Integer
Dim datiLetti As String = ""
Dim i As Integer = 0

charLetti += m_seriale.BytesToRead
m_seriale.Read(bufferChar, 0, charLetti)

While i < charLetti And (Char.GetNumericValue(bufferChar(i)) <> -1.0)
datiLetti += bufferChar(i)
i += 1
End While

m_dati += datiLetti

' Attendo l'arrivo del carriage return
If Char.GetNumericValue(bufferChar(i)) = -1.0 Then
' Qui ovviamente va la tua procedura
FrmTotem.oTotem.showChar(m_dati, charLetti)
' importante svuotare il buffer usato....
m_dati = ""
End If
End Sub

La variabile m_seriale è all'interno di una classe assieme al metodo sopradescritto ed è definita cosi:
Private WithEvents m_seriale As Ports.SerialPort

Spero che possa esserti utile
Filippo

glannino Profilo | Newbie

>Il problema è relativo al fatto che la lettura dei dati dalla
>seriale è asincrona rispetto al resto del programma: [...]

Concordo. Infatti il metodo form2.ShowModal() blocca l'esecuzione di quanto avviene nella form1 (gestore degli eventi compreso) e per questo motivo la form2 si visualizza correttamente.

A parte il modo diverso per la detection del CRLF vedo che la tua subroutine lavora in modo analogo alla mia, ad eccezione del fatto che la variabile di tipo Ports.SerialPort nel mio caso è interna alla classe form1... proverò anche questo.

Ti ringrazio per il supporto. Alla prossima,

Gabriele

Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5