Salve a tutti, avrei bisogno di una grossa mano.
Sto sviluppando un'interfaccia che deve gestire in contemporanea diversi oggetti (di cui ho scritto il firmware).
Non so a priori quanti dispositivi verranno collegati al pc, mi occorre quindi riconoscerli, è stata però fatta la scelta di limitare il numero massimo di dispositivi collegabili a 10.
A questo punto nella finestra di setting del sistema (dove vengono riconosciuti i dispositivi) ho deciso di scrivere una funzione che:
- Prova ad aprire una porta utilizzando un oggetto mscomm temporaneo
- Se viene dato errore passa alla porta successiva
- Se riesce ad aprirla verifica che su quella porta sia collegato uno dei miei dispositivi.
- Se è collegato uno dei miei dispositivi copio le impostazioni di questa porta in uno dei 10 oggetti MSComm "ufficiali" (cioè uno che non sia quello temporaneo che viene utilizzato solo in questa fase).
Questo viene effettuato finchè non ho trovato 10 dispositivi o finchè non ho controllato la porta COM99 (cioè la massima possibile).
A questo punto se non ho dispositivi collegati do errore, altrimenti utilizzo i dispositivi che ho.
La funzione è questa:
codice:
Public Function ComOpener()
Dim i As Integer
' Dalla porta a cui sono arrivato in poi
For i = Portcnt To 10
' Se non ho giù aperto tutte le 10 porte
If Commcnt < 10 Then
' Inizializza temp
With cmmTmp
.CommPort = i
.Settings = COMM_SETTING
.InputMode = comInputModeBinary
.InputLen = 0
.RThreshold = 256
.DTREnable = False
On Error Resume Next
' Apre la prossima porta
.PortOpen = True
' Se c'è stato errore la porta non è disponibile
If Err Then
'MsgBox ("no port" & i)
Else
' Sennò attiva il timer, inizializza le variabili e aspetta il risultato che indica se la porta è disponibile
tmrPortRec.Enabled = True
goodPort = 0
Portcnt = i
'inizializza la SM
PORT_SM_curr = WAIT_ESC
PORT_SM_next = WAIT_ESC
While (tmrPortRec.Enabled <> False) And (goodPort = 0)
DoEvents
Wend
' Arrivati qua la funzione Verify_HW ha già verificato che la porta è disponibile
' O il timer è scaduto e la porta non è disponibile
' Se la porta è disponibile cmmTmp viene copiato sul primo mscomm libero dalla routine del timer
End If
.PortOpen = False
End With
End If
Next
If Commcnt = 0 Then
MsgBox (GStr.REGErrNoDev)
End If
End Function
Dove tutte le variabili non dichiarate ma utilizzate sono globali all'interno del modulo e COMM_SETTING è una costante che vale "115200, N, 8, 1".
In particolare PORT_SM_curr e PORT_SM_next vengono utilizzzate in una macchina a stati che utilizzo per riconoscere il dispositivo.
Questo perchè i miei dispositivi, quando alimentati iniziano ad inviare uno stream continuo di dati, formattati in un certo modo.
Avendo un header, un payload e un footer (con CRC) la mia idea è di controllare che il pacchetto ricevuto sia coerente (CRC corretto, lunghezza dei dati uguale a quella indicata ecc)
con quanto atteso.)
Come si vede sopra se la porta viene aperta attivo un timer che viene inizializzato durante l'evento activate del form e che ha interval = 5000 (in realtà in 5 secondi ricevo
un gran numero di pacchetti, ma per ora ho messo di proposito un tempo lungo per essere sicuro di riceverne almeno uno).
Se il timer va in timeout considero il dispositivo collegato non valido (cioè non uno dei miei dispositivi).
codice:
Private Sub cmmTmp_OnComm()
Dim data() As Byte
Dim i As Integer
data = cmmTmp.Input
For i = 0 To 256
If goodPort = 0 Then
Verify_HW (data(i))
End If
Next
End Sub
Una macchina a stati (Verify_HW) mi permette di verificare che il pacchetto sia corretto, in questo caso fermo il timer tmrPortRec, setto goodPort a 1 e chiamo
la routine di gestione di overflow del timer (queste operazione vengono effettuate dalla macchina a stati)...cioè questa:
codice:
Private Sub tmrPortRec_Timer()
If goodPort = 1 Then
cmmTmp.PortOpen = False
With cmmInput(Commcnt)
.CommPort = Portcnt
.Settings = COMM_SETTING
.InputMode = comInputModeBinary
.InputLen = 0
.RThreshold = 256
.DTREnable = False
If .PortOpen = True Then
.PortOpen = False
End If
End With
Commcnt = Commcnt + 1
End If
tmrPortRec.Enabled = False
End Sub
che nel caso di cuscinetto buono (goodPort = 1) copia i valori della porta corrente in un altro oggetto MSComm come spiegato prima.
Come si nota nel codice gli oggetti MsComm su cui vado a copiare i setting di cmmTmp sono indicizzati, si chiamano cioè tutti cmmInput e
vengono identificati tramite un indice.
Fin qua tutto ok, sembra funzionare tutto...ora vi spiego il problema vero e proprio.
Una volta riconosciuto il numero di dispositivi collegati al pc devo riconoscere il loro ID. per fare ciò agisco come prima: ricevo cioè un pacchetto e ne lo elaboro come necessario...
ciò che cambia rispetto a prima è l'oggetto MSComm.
La routine del pulsante Wait è quella che si comporta in maniera analoga a ComOpener:
codice:
Private Sub btnWait_Click()
Dim i As Integer
btnSave.Enabled = False
lblAddr.Caption = ""
waiting4ID = 1
' Inizializza la SM
ID_SM_curr = WAIT_ESC
ID_SM_next = WAIT_ESC
On Error Resume Next
' Apre le porte
For i = 0 To Commcnt - 1
With cmmInput(i)
.Settings = COMM_SETTING
.InputMode = comInputModeBinary
.InputLen = 0
.RThreshold = 256
.DTREnable = False
.PortOpen = True
End With
Next
tmrIDrec.Enabled = True
' Aspetta l'ID
While (tmrIDrec.Enabled <> False) And (waiting4ID = 1)
DoEvents
Wend
On Error Resume Next
'Chiude le porte
For i = 0 To Commcnt
cmmInput(i).PortOpen = False
Next
' Se non ha trovato nulla
If lblAddr.Caption = "" Then
' Lo segnala
MsgBox (GStr.REGErrNoID)
Else
' Sennò abilita il pulsante Save
btnSave.Enabled = True
End If
End Sub
waiting4id è una variabile globale che ha funzione simile a quella di goodPort con la differenza che questa rimane a 1 fino a che non è stato ricevuto un ID ( o fino a quando non scade il timer).
In pratica da qua in poi il comportamento del programma dovrebbe essere quello di prima, con la differenza che viene chiamata una macchina a stati diversa da quella di prima.
Il mio problema è però che l'evento OnComm dei vari cmmInput non viene mai scatenato, mentre io son sicuro che in quel momento dei dati stannoarrivando sulla seriale.
Non arrivando dati il timer scade e non riconosco nessun ID...
Per togliermi ogni dubbio ho provato anche a creare un ulteriore oggetto MSComm, inizializzarlo allo stesso modo di cmmInput(0) (per ora sto provando il tutto con un solo dispositivo) e vedere se in questo caso
ricevo dati e la risposta è si..funziona correttamente.
Mi viene quindi il dubbio che il problema stia nel fatto che i miei cmmInput sono indicizzati.
Per completezza vi metto anche la routine di gestione dell'evento OnComm deio vari cmmInput.
codice:
Private Sub cmmInput_OnComm(Index As Integer)
Dim data() As Byte
Dim i As Integer
data = cmmInput(Index).Input
For i = 0 To 256
If waiting4ID = 1 Then
Receiver_SM (data(i))
End If
Next
End Sub
Mi rendo conto di aver sbrodolato un po' la faccenda ma spero di essere stato chiaro... vi sarei grato se qualcuno potesse spiegarmi dove sta il problema perchè io non so più dive sbattere la testa.
Grazie mille in anticipo