Accesso alle Porte Seriali

Da Gambas-it.org - Wikipedia.

Possiamo accedere alle Porte Seriali [nota 1] aprendo e leggendo direttamentre i dati provenienti dai relativi file-device.

Poniamo l'esempio di avere una penna USB per la connessione ad Internet, e che alla sua connessione il sistema operativo abbia generato due relativi file-device: "/dev/ttyUSB0 " e "/dev/ttyUSB1 " [nota 2].
Possiamo leggere i dati provenienti dalla porta mediante due modalità:

  • direttamente dal relativo file-device, ad esempio, "/dev/ttyUSB1 ";
  • mediante l'apposita classe "SerialPort".

Mediante lettura diretta dal corrispondente file-device

Per il seguente esempio è necessario attivare anche il componente "gb.desktop", ed aver installato il programma "x-term":

Private fl As File


Public Sub Button1_Click()

' Se il file non possiede i più ampi permessi...
   If Stat("/dev/ttyUSB1").Auth <> "rwsrwxrwx" Then
' ...allora modificheremo in quel senso i permessi del file:
     Desktop.RunAsRoot("chmod 4777 /dev/ttyUSB1")
' Restiamo in attesa fino a che i permessi non vengono modificati, come desiderato:
     Do
       Wait 0.01
     Loop Until Stat("/dev/ttyUSB1").Auth = "rwsrwxrwx"
   Endif

' In alternativa all'algoritmo precedente,
' si potrà utilizzare il seguente codice per impostare il setUID
' e consentire l'apertura del file protetto:
   Exec ["gksu", "chmod 4777", "/dev/ttyUSB1"] Wait

' ...o ancor più facilmente:
   Shell "echo < mia_password > | sudo -S chmod 4777 '/dev/ttyUSB1'" Wait

' Apriamo il file-device aggiungendo la parola chiave "Watch":
   fl = Open "/dev/ttyUSB1" For Read Watch

End


Public Sub File_Read()

 Dim s As String

   While Not Eof(fl)
' Leggiamo i dati provenienti dal file-device...:
     Line Input #fl, s
' ...e li mostriamo in console:
     Print s
   Wend

End


Lettura mediante la classe SerialPort

La lettura della Porta Seriale portà avvenire anche mediante l'uso della Classe "SerialPort" attivando il componente gb.net.

Private SerialPort1 As SerialPort


Public Sub Button1_Click()

  SerialPort1 = New SerialPort As "portaseriale"


' Facciamo in modo da poter inserire la password di root
' per impostare il setUID e consentire l'apertura del file protetto:
   Shell "echo 'mia_password' | sudo -S chmod 4777 '/dev/ttyUSB1'" Wait
 
   With SerialPort1
     .PortName = "/dev/ttyUSB1"
     .Speed = 19200
     .Parity = 0
     .DataBits = 8
     .StopBits = 1
     .FlowControl = 0
     .Open
   End With

 End


Public Sub portaseriale_Read()

 Dim s As String

' Legge i dati dalla porta....
       Read #SerialPort1, s, Lof(SerialPort1)

' ...e li mostra in console:
       Print s

End


Public Sub Form_Close()
 
  If SerialPort1.Status = Net.Active Then SerialPort1.Close
 
End

Mostriamo, di seguito, un altro codice [nota 3] più complesso che possiede alcune funzioni capaci di inviare richieste cicliche e di dare risposte a seconda dei dati giunti dalla seriale, nonché di conteggiare richieste e risposte.

Private SPort As SerialPort
Private Timer1 As Timer
Private ChkDTR As CheckBox
Private ChkRTS As CheckBox
Private ChkCTS As CheckBox
Private ChkDCD As CheckBox
Private ChkDSR As CheckBox
Private ChkRNG As CheckBox
Private TextLabel1 As TextLabel
Private TextLabel2 As TextLabel
Private TextLabel3 As TextLabel
Private TextLabel4 As TextLabel
Private TextLabel5 As TextLabel
Private Label1 As Label
Private TxtPort As TextBox
Private CmbSpeed As ComboBox
Private CmbParity As ComboBox
Private CmbData As ComboBox
Private CmbStop As ComboBox
Private Button1 As Button
Private ComboBox1 As ComboBox
Private Esci As Button
Private Separator1 As Separator
Private CicloCheck As CheckBox
Private SERIALE As TextLabel
Private Label3 As Label
Private CheckBox1 As CheckBox
Private TEMPO As TextBox
Private Label2 As Label
Private TxtSend As TextBox
Private TextLabel6 As TextLabel
Private RUN_COUNT As TextLabel
Private RUN As Button
Private TextArea1 As TextArea
Private COMPARA_BOX As CheckBox
Private VALORE_COMPARA As TextBox
Private NUMERO_CARATTERI As ComboBox
Private Separator2 As Separator
Private RISPONDI As CheckBox
Private RISPOSTA As TextBox
Private Label4 As Label
Private COMP_OK As TextLabel
Private RISPOSTE_OK As Label
Private RISP_OK As TextLabel


Public Sub _new()
 
 With Me
   .AutoResize = True
   .Expand = True
   .Center
   .H = 560
   .W = 500
   .Text = "Serial Port Exended"
 End With
 With SPort = New SerialPort As "SPort"
   .DataBits = .Bits8
   .FlowControl = .Hardware
   .Parity = .None
   .Speed = 192000
   .StopBits = .Bits1
 End With
 Timer1 = New Timer
 With ChkDTR = New CheckBox(Me) As "ChkDTR"
   .H = 28
   .W = 76
   .X = 330
   .Y = 7
   .Text = "DTR"
 End With
 With ChkRTS = New CheckBox(Me) As "ChkRTS"
   .H = 28
   .W = 76
   .X = 330
   .Y = 28
   .Text = "RTS"
 End With
 With ChkCTS = New CheckBox(Me)
   .H = 28
   .W = 76
   .X = 330
   .Y = 49
   .Text = "CTS"
 End With
 With ChkDCD = New CheckBox(Me)
   .H = 28
   .W = 76
   .X = 330
   .Y = 70
   .Text = "DCD"
 End With
 With ChkDSR = New CheckBox(Me)
   .H = 28
   .W = 76
   .X = 330
   .Y = 91
   .Text = "DSR"
 End With
 With ChkRNG = New CheckBox(Me)
   .H = 28
   .W = 76
   .X = 330
   .Y = 112
   .Text = "RNG"
 End With
 With TextLabel1 = New TextLabel(Me)
   .H = 28
   .W = 146
   .X = 63
   .Y = 7
   .Alignment = Align.Left
   .Text = "Port Name :"
 End With
 With TextLabel2 = New TextLabel(Me)
   .H = 28
   .W = 146
   .X = 63
   .Y = 35
   .Alignment = Align.Left
   .Text = "Speed :"
 End With
 With TextLabel3 = New TextLabel(Me)
   .H = 28
   .W = 146
   .X = 63
   .Y = 63
   .Alignment = Align.Left
   .Text = "Parity :"
 End With
 With TextLabel4 = New TextLabel(Me)
   .H = 28
   .W = 146
   .X = 63
   .Y = 91
   .Alignment = Align.Left
   .Text = "Data Bits :"
 End With
 With TextLabel5 = New TextLabel(Me)
   .H = 28
   .W = 146
   .X = 63
   .Y = 119
   .Alignment = Align.Left
   .Text = "Stop Bits :"
 End With
 With Label1 = New Label(Me)
   .H = 28
   .W = 105
   .X = 77
   .Y = 175
   .Alignment = Align.Left
   .Text = "Flow control :"
 End With
 With TxtPort = New TextBox(Me)
   .H = 28
   .W = 105
   .X = 217
   .Y = 7
   .Alignment = Align.Center
   .Text = "/dev/ttyUSB0"
 End With
 With CmbSpeed = New ComboBox(Me)
   .H = 28
   .W = 105
   .X = 217
   .Y = 35
   .List = ["1200", "2400", "4800", "9600", "19200", "38400", "57600", "112000"]
   .ReadOnly = True
 End With
 With CmbParity = New ComboBox(Me)
   .H = 28
   .W = 105
   .X = 217
   .Y = 63
   .List = ["None", "Even", "Odd"]
   .ReadOnly = True
   .Text = .List[0]
 End With
 With CmbData = New ComboBox(Me)
   .H = 28
   .W = 105
   .X = 217
   .Y = 91
   .List = ["8", "7", "6", "5"]
   .ReadOnly = True
   .Text = .List[0]
 End With
 With CmbStop = New ComboBox(Me)
   .H = 28
   .W = 105
   .X = 217
   .Y = 119
   .List = ["1", "2"]
   .ReadOnly = True
   .Text = .List[0]
 End With
 With Button1 = New Button(Me) As "Open"
   .H = 28
   .W = 105
   .X = 217
   .Y = 147 
   .Text = "&Open"
   .Tooltip = "Apre la comunicazione"
 End With
 With ComboBox1 = New ComboBox(Me)
   .H = 28
   .W = 140
   .X = 182
   .Y = 175
   .List = ["NONE", "CRTSCTS", "XON/XOFF", "CRTSCTS + XON/XOFF"]
   .ReadOnly = True
   .Text = .List[0]
 End With
 With Esci = New Button(Me) As "Esci"
   .H = 42
   .W = 42
   .X = 440
   .Y = 14
   .Picture = Picture["icon:/32/shutdown"]
   .Tooltip = "Esci"
 End With
 With Separator1 = New Separator(Me)
   .H = 14
   .W = Me.W
   .X = 0
   .Y = 202
 End With
 With CicloCheck = New CheckBox(Me)
   .H = 21
   .W = 21
   .X = 35
   .Y = 224
   .Tooltip = "Invia in maniera ciclica" 
 End With
 With SERIALE = New TextLabel(Me)
   .H = 28
   .W = 28
   .X = 63
   .Y = 217
   .Background = Color.Red
   .Border = Border.Plain
 End With
 With Label3 = New Label(Me)
   .H = 28
   .W = 49
   .X = 105
   .Y = 217
   .Text = "CICLO"
 End With
 With CheckBox1 = New CheckBox(Me)
   .H = 28
   .W = 168
   .X = 182
   .Y = 217
   .Text = "LETTURA SERIALE"
   .Tooltip = "Attiva il monitoraggio della seriale"
   .Value = True
 End With
 With TEMPO = New TextBox(Me)
   .H = 28
   .W = 140
   .X = 63
   .Y = 245
   .Text = "50"
   .Tooltip = "Durata del ciclo X5"
 End With
 With Label2 = New Label(Me)
   .H = 28
   .W = 91
   .X = 210
   .Y = 245
   .Text = "TEMPO ms X 5"
 End With
 With TxtSend = New TextBox(Me)
   .H = 28
   .W = 140
   .X = 63
   .Y = 273
   .Text = "Comando da inviare"
 End With
 With TextLabel6 = New TextLabel(Me)
   .H = 28
   .W = 70
   .X = 210
   .Y = 273
   .Alignment = Align.Left
   .Text = "COMANDO"
 End With
 With RUN_COUNT = New TextLabel(Me)
   .H = 28
   .W = 77
   .X = 287
   .Y = 273
   .Alignment = Align.Right
   .Background = &3F3FFF
   .Text = "0"
   .Tooltip = "Numero di comandi inviati, viene azzerato ad ogni invio manuale, per una statistica usare l'invio ciclico"
 End With
 With RUN = New Button(Me)
   .H = 28
   .W = 70
   .X = 372
   .Y = 273
   .AutoResize = True
   .Text = "RUN"
   .Tooltip = "Invia il comando"
 End With
 With TextArea1 = New TextArea(Me)
   .H = 174
   .W = 482
   .X = 7
   .Y = 308
   .Background = &FFFF9F
   .Tooltip = "Monitor dei dati ricevuti dalla seriale"
 End With
 With COMPARA_BOX = New CheckBox(Me)
   .H = 28
   .W = 84
   .X = 14
   .Y = 490
   .Text = "COMPARA"
   .Tooltip = "Esegui la comparazione del dato ricevuto"
 End With
 With VALORE_COMPARA = New TextBox(Me)
   .H = 28
   .W = 70
   .X = 105
   .Y = 490
   .Tooltip = "Dato da usare per la comparazione"
 End With
 With NUMERO_CARATTERI = New ComboBox(Me)
   .H = 28
   .W = 42
   .X = 182
   .Y = 490
   .List = ["1", "2", "3", "4", "5", "6", "7", "8"]
   .Text = "0"
   .Tooltip = "Numero di caratteri ricevuti da analizzare nella comparazione partendo dalla fine della stringa"
 End With
 With Separator2 = New Separator(Me)
   .H = 70
   .W = 28
   .X = 238
   .Y = 483
 End With
 With RISPONDI = New CheckBox(Me)
   .H = 28
   .W = 90
   .X = 322
   .Y = 490
   .Text = "RISPONDI"
   .Tooltip = "Invia una risposta se il dato di comparazione viene soddisfatto"
 End With
 With RISPOSTA = New TextBox(Me)
   .H = 28
   .W = 70
   .X = 413
   .Y = 490
   .Tooltip = "dato inviato come risposta"
 End With
 With Label4 = New Label(Me)
   .H = 21
   .W = 106
   .X = 14
   .Y = 525
   .Background = &FFDF7F
   .Text = "COMPARAZ. OK"
 End With
 With COMP_OK = New TextLabel(Me)
   .H = 21
   .W = 56
   .X = 119
   .Y = 525
   .Alignment = Align.Right
   .Background = &FF8000
   .Text = "0"
   .Tooltip = "Numero di comparazioni corrette, viene azzerato ad ogni invio manuale, per una statistica usare l'invio ciclico"
 End With
 With RISPOSTE_OK = New Label(Me)
   .H = 21
   .W = 105
   .X = 322
   .Y = 525
   .Background = &FFDF7F
   .Text = "RISPOSTE OK"
 End With
 With RISP_OK = New TextLabel(Me)
   .H = 21
   .W = 56
   .X = 427
   .Y = 525
   .Alignment = Align.Right
   .Background = &FF8000
   .Text = "0"
   .Tooltip = "Numero di risposte inviate"
 End With

End

Public Sub Form_Close()
 If Sport.Status = Net.Active Then Close Sport
End

Private Sub Check_Status()
 ChkDSR.Value = Sport.DSR
 ChkDTR.Value = Sport.DTR
 ChkCTS.Value = Sport.CTS
 ChkRTS.Value = Sport.RTS
 ChkDCD.Value = Sport.DCD
 ChkRNG.Value = Sport.RNG
'End


Private HACK As String
Private SC As Integer   ' Controllo stabilità connessione
Private RC As Integer   ' Conteggio invii RUN
Private NC As Integer   ' Numero caratteri da comparare (da fine stringa)

Public Sub Open_Click()
 If Sport.Status = Net.Active Then
   Close Sport
   Button1.Text = "&Open"
 Else
' Parametri:
   Sport.PortName = TxtPort.Text
   Sport.Speed = CmbSpeed.Text
   Sport.Parity = CmbParity.Index
   Sport.DataBits = CmbData.Text
   Sport.StopBits = CmbStop.Text
   Sport.FlowControl = ComboBox1.Index
   Sport.Open()
   Check_Status()
   TextArea1.Text = "Port Opened : " & Sport.PortName & " Settings : " &
                    Sport.Speed & "," & Sport.Parity & "," & Sport.DataBits & "," &
                    Sport.StopBits & Chr(13) & Chr(10)
   Button1.Text = "&Close"
   RC = 0
   SC = 0
   RUN_COUNT.Text = "0"
   COMP_OK.Text = "0"
   RISP_OK.Text = "0"
 Endif 
 Catch
   Message.Info("Errore apertura seriale , verificare porta")
End

Public Sub SPort_Read()

 Dim s As String
 
 Read #Sport, s, Lof(Sport)
 If CheckBox1.Value = True Then TextArea1.Text = TextArea1.Text & s
 
'***************************************** ANALISI STRINGA ***************************************

' COMPARAZIONE
 If COMPARA_BOX.Value = True Then
   NC = NUMERO_CARATTERI.Text
   If Right$(TextArea1.Text, (NC)) = VALORE_COMPARA.Text Then 
     SC = SC + 1
     COMP_OK.Text = SC
     If COMP_OK.Text = 300 Then TextArea1.Text = ""
   Endif
 Endif

' RISPOSTA
 If RISPONDI.Value = True Then
   NC = NUMERO_CARATTERI.Text
   If Right$(TextArea1.Text, (NC)) = VALORE_COMPARA.Text Then
     Print #Sport, RISPOSTA.Text;
     SC = SC + 1
     RISP_OK.Text = SC
     If RISP_OK.Text = 300 Then TextArea1.Text = ""
   Endif
 Endif

End

Public Sub RUN_Click()

 Dim T As Integer

 If CicloCheck.Value Then
   If RUN.Text = "RUN" Then
     RUN.Text = "STOP"
   Else
     RUN.Text = "RUN"
   Endif
 Endif
 RC = 0
 SC = 0
 T = TEMPO.Text
 If CicloCheck.Value = True Then
   Timer1.Delay = TEMPO.Text
   If Timer1.Enabled Then
     Timer1.Enabled = False
   Else
     Timer1.Enabled = True
   Endif
 Else
   Print #Sport, TxtSend.Text;
 Endif
 Catch
   Message("Apri la porta!")

End

Public Sub ChkDTR_Click()
 Sport.DTR = ChkDTR.Value
 Check_Status
End

Public Sub ChkRTS_Click()
 Sport.RTS = ChkRTS.Value
 Check_Status
End

Public Sub ComboBox1_Click()
 Sport.FlowControl = ComboBox1.Index
End

Public Sub Form_Open()
 cmbSpeed.Index = cmbSpeed.Find("9600")
End


Private  C As Integer
Private IND As Integer

Public Sub Timer1_Timer()

 If Sport.Status = Net.Inactive Then
   Message("Apri la porta!")
   RUN.Text = "RUN"
   Timer1.Enabled = False
 Else
   If IND < 33 Then IND = 33
   If C = 5 Then
     If IND = 62 Then
       IND = 33
       TextArea1.Clear
     Else
       IND = IND + 1
     Endif
     Print #Sport, TxtSend.Text;
     C = 0
     RC = RC + 1
     RUN_COUNT.Text = RC
   Else
     C = C + 1
   Endif
   SERIALE.Text = C
 Endif

End

Public Sub Esci_Click()
 If Button1.Text = "&Close" Then Open_Click
 Me.Close
End


Note

[1] Vedere anche questa pagina: Approfondimento sull'accesso alle porte USB

[2] In tali altri casi il file-device creato può essere: "/dev/ttyACM0"

[3] Il codice è stato realizzato dal utente "astragalo ".


Approfondimenti in internet