Universalmodul fürs c't-LAB

Um Eigenentwicklungen in das c't-Lab integrieren zu können ist eine Kommunikation über den Opto-Bus erforderlich. Das Universalmodul stellt das Grundgerüst dafür zur Verfügung. Die eingehenden Daten werden im Parser geprüft und abgearbeitet oder, falls diese zu einem anderen Modul gehören, weitergeleitet. Der Parser stellt in Variablen den Mainchannel, Subchannel und der Wert zur Verfügung. Eigene Mnemonics können in der Liste hinzugefügt werden.

Quellcode

'---------------------------------------------------------------------------
'     c't LAB Universal 1.3         Günter Gerold
'
'     Grundgerüst für das C'T-LAB
'
'     Empfangen, prüfen und weiterleiten der Befehle im Opto-Bus
'     c't-Lab konformer Parser zur Befehlsverarbeitung
'     Stefan Esni hat einen Fehler im Mnemonicarr beseitigt, danke!
'---------------------------------------------------------------------------

$regfile = "m32def.dat"
$crystal = 4000000
$baud = 38400

$hwstack = 32
$swstack = 10
$framesize = 40

Config Serialin = Buffered , Size = 63 , Bytematch = 13
Config Serialout = Buffered , Size = 63
Config Watchdog = 512
Config Pind.5 = Input                                       'Modulnummer +1
Config Pind.6 = Input                                       'Modulnummer +2
Config Pind.7 = Input                                       'Modulnummer +4

Enable Interrupts
Echo Off

Declare Sub Writeserinp
Declare Sub Checkserinp
Declare Sub Parser

Dim Serinpstr As String * 63
Dim Serinpbuffer As String * 63
Dim Serinbuffarr(5) As Byte At Serinpbuffer Overlay
Dim Mnemonicbuffer As String * 4
Dim Mnemonicbufferarray(5) As Byte At Mnemonicbuffer Overlay
Dim Cr_received As Bit
Dim Strsize As Byte
Dim Mymainchannel As Byte
Dim Mainchannel As Byte
Dim Subchannel As Word
Dim Wert As Single
Dim Frage As Bit
Dim Zeichenpos As Byte

Dim Doppelpunkt As String * 1
Doppelpunkt = ":"
Dim Istgleich As String * 1
Istgleich = "="

Dim Mnemonicarr(25) As String * 3
Mnemonicarr(1) = "TRG"                                      ' 249 = manuelle Trigger-Ausl?sung
Mnemonicarr(2) = "STR"                                      ' 255 = Status,
Mnemonicarr(3) = "IDN"                                      ' 254 = Identifikation ohne Parameter
Mnemonicarr(4) = "VAL"                                      ' 0 = Value
Mnemonicarr(5) = "OFS"                                      ' 100 = Offsets
Mnemonicarr(6) = "SCL"                                      ' 200 = Skalierungen
Mnemonicarr(7) = "RAW"                                      ' 50 = Roh-AD-Werte
Mnemonicarr(8) = "PIO"                                      ' 30 = Ports I/O
Mnemonicarr(9) = "DIR"                                      ' 40 = Ports Datenrichtung
Mnemonicarr(10) = "DSP"                                     ' 80 = Display-Parameter
Mnemonicarr(11) = "ALL"                                     ' 95..99 = Alle Werte, Liste
Mnemonicarr(12) = "OPT"                                     ' 150...159
Mnemonicarr(13) = "TRM"                                     ' 240..243 = Trigger-Masken 0..7, 10..17, (20..27), 30..37
Mnemonicarr(14) = "TRT"                                     ' 247 = Auto-Trigger-Timing in ms, 0=aus
Mnemonicarr(15) = "TRL"                                     ' 248 = Trigger-Edge-Level 0=neg, 1=pos. auf PB2 (INT2)
Mnemonicarr(16) = "ICB"                                     ' 230 = Generic I2C I/O Byte
Mnemonicarr(17) = "ICW"                                     ' 231 = Generic I2C I/O Word/Integer
Mnemonicarr(18) = "ICS"                                     ' 232 = Generic I2C I/O Word Swapped
Mnemonicarr(19) = "ICT"                                     ' 233 = Generic I2C I/O Temperatur
Mnemonicarr(20) = "ICA"                                     ' 239 = Generic I2C I/O Hardware-Adresse setzen
Mnemonicarr(21) = "REF"                                     ' 246 = Ext. Referenz wenn 1, interne wenn 0
Mnemonicarr(22) = "WEN"                                     ' 250 = Write Enable
Mnemonicarr(23) = "ERC"                                     ' 251 = ErrCount seit letztem Reset
Mnemonicarr(24) = "SBD"                                     ' 252 = SerBaud UBRR-Register mit U2X=1
Mnemonicarr(25) = "NOP"

Dim Cmd2subcharr(25) As Byte
Cmd2subcharr(1) = 249
Cmd2subcharr(2) = 255
Cmd2subcharr(3) = 254
Cmd2subcharr(4) = 0
Cmd2subcharr(5) = 100
Cmd2subcharr(6) = 200
Cmd2subcharr(7) = 50
Cmd2subcharr(8) = 30
Cmd2subcharr(9) = 40
Cmd2subcharr(10) = 80
Cmd2subcharr(11) = 95
Cmd2subcharr(12) = 150
Cmd2subcharr(13) = 240
Cmd2subcharr(14) = 247
Cmd2subcharr(15) = 248
Cmd2subcharr(16) = 230
Cmd2subcharr(17) = 231
Cmd2subcharr(18) = 232
Cmd2subcharr(19) = 233
Cmd2subcharr(20) = 239
Cmd2subcharr(21) = 246
Cmd2subcharr(22) = 250
Cmd2subcharr(23) = 251
Cmd2subcharr(24) = 252
Cmd2subcharr(25) = 0

Mymainchannel.0 = Pind.5                                    'Moduladdresse von den Jumpern holen
Mymainchannel.1 = Pind.6
Mymainchannel.2 = Pind.7

Do

If Cr_received = 1 Then                                     'wenn was im ser. Buffer ist abholen
   Cr_received = 0
   Input Serinpstr
   'zum Abtrennen eines oder mehrerer LF am Anfang des Strings, das noch vom Vorgänger-String im Buffer steht
   While Asc(serinpstr) = 10
      Strsize = Len(serinpstr) - 1
      Serinpstr = Right(serinpstr , Strsize)
   Wend
   'Hier ist der String empfangen und ein event. LF entfernt
   Call Checkserinp
End If

Reset Watchdog
Loop

'---------------------------------------------------------------------------
'     Writeserinp
'     Leitet den empfangenen String zum nächsten Modul weiter
'---------------------------------------------------------------------------

Sub Writeserinp
  Print Serinpstr                                           ' Befehl Weiterreichen
End Sub
'---------------------------------------------------------------------------
'     Serial0charmatch
'     Im Eingangspuffer wurde ein "13" empfangen
'---------------------------------------------------------------------------
 Serial0charmatch:
    Cr_received = 1
  Return

'---------------------------------------------------------------------------
'     Checkserinp
'     Hier der String abgeholt
'     Der Mainchannel und der : wird geprüft
'---------------------------------------------------------------------------

Sub Checkserinp
   If Asc(serinpstr) = 35 Then                              'Strings mit # gleich weiterleiten
      Call Writeserinp
      Exit Sub
   End If
   Zeichenpos = Instr(serinpstr , ":")
   If Zeichenpos > 0 Then                                   ' Doppelpunkt Gefunden
      If Instr(serinpstr , "*") > 0 And Instr(serinpstr , "*") < Zeichenpos Then
         Call Writeserinp
         Call Parser
         Exit Sub
      Else                                                  'kein *
         Serinpbuffer = Left(serinpstr , Zeichenpos)
         Mainchannel = Val(serinpbuffer)
         If Mainchannel = Mymainchannel Then
            Call Parser
            Exit Sub
         Else
            Call Writeserinp
            Exit Sub
         End If
      End If
   Else                                                     'kein :
      If Mainchannel = Mymainchannel Then                   'Mainchannel müsste noch von vorigem Durchlauf drinstehen
         Call Parser
         Exit Sub
      Else                                                  'anderes Modul
         Call Writeserinp
         Exit Sub
      End If
   End If
End Sub
'---------------------------------------------------------------------------
'     Parser
'     Hier beginnt der Parser
'
'---------------------------------------------------------------------------
Sub Parser
   Dim I As Byte
   Dim A As Byte
   A = 1
   Serinpbuffer = ""
   Mnemonicbuffer = ""
   Wert = 0
   Subchannel = 0                                           'der ":" und alles davor kommt weg
   Zeichenpos = Len(serinpstr) - Instr(serinpstr , Doppelpunkt)
   Serinpbuffer = Right(serinpstr , Zeichenpos)
   For I = 1 To 4                                           'die nächsten 4 Stellen nach dem Doppelpunkt (4 wegen Leerzeichen)
      If Serinbuffarr(i) >= "A" And Serinbuffarr(i) <= "Z" Or Serinbuffarr(i) >= "a" And Serinbuffarr(i) <= "z" Then
           Mnemonicbufferarray(a) = Serinbuffarr(i)
           Incr A
           Mnemonicbufferarray(a) = 0
      End If
   Next
   If Len(mnemonicbuffer) = 3 Then                          '3 Buchstaben sind angekommen
      Mnemonicbuffer = Ucase(mnemonicbuffer)
      For I = 0 To 25
          If Mnemonicbuffer = Mnemonicarr(i) Then           'passende Zahl suchen
             Subchannel = Cmd2subcharr(i)
             Exit For
          End If
      Next
   End If
   A = 1
   Mnemonicbuffer = ""
   Zeichenpos = Instr(serinpbuffer , Istgleich)
   If Zeichenpos = 0 Then Zeichenpos = Len(serinpbuffer)
   For I = 1 To Zeichenpos                                  'Den ganzen String bis Ende oder = nach Zahlen durchsuchen
       If Serinbuffarr(i) >= "0" And Serinbuffarr(i) <= "9" Then
          Mnemonicbufferarray(a) = Serinbuffarr(i)
          Incr A
          Mnemonicbufferarray(a) = 0
       End If
   Next
   Subchannel = Subchannel + Val(mnemonicbuffer)            'gefundene Zahl mit dem Mnemonic addieren

   If Instr(serinpbuffer , Istgleich) > 0 Then              '= ist vorhanden
      Frage = 0
   Else
      Frage = 1
   End If
   Zeichenpos = Len(serinpbuffer) - Instr(serinpbuffer , Istgleich)
   Serinpbuffer = Right(serinpbuffer , Zeichenpos)          'alles hinter = ist der Wert
   Wert = Val(serinpbuffer)

   Print "#Modulnummer: " ; Str(mainchannel)
   Print "#Subchannel: " ; Subchannel
   If Frage = 0 Then
      Print "#Wert: " ; Wert
   Else
      Print "#"
   End If
   'An dieser Stelle ist alles ausgewertet
   'Mainchannel ist die Kartennummer des Befehls
   'Subchannel ist der Befehl incl. des Subchannels
   'Wert ist der Wert der gesetzt werden soll
   'Frage steht auf 1 wenn ein ? im Datensatz vorgekommen ist

End Sub