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:
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".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
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).
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 chiamocodice: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
la routine di gestione di overflow del timer (queste operazione vengono effettuate dalla macchina a stati)...cioè questa:
che nel caso di cuscinetto buono (goodPort = 1) copia i valori della porta corrente in un altro oggetto MSComm come spiegato prima.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
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:
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).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
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.
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.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
Grazie mille in anticipo

Rispondi quotando