Tcl/Tk
Curso On-Line de Programação

Exemplos

A seguir são apresentados os códigos-fontes de algumas bibliotecas Tcl. Estas bibliotecas podem ser utilizadas tanto com o interpretador tclsh quanto com o interpretador wish.
 

Índice

    1. Biblioteca para acesso a arquivos de recursos
    2. Biblioteca para criação de relatórios PostScript
    3. Biblioteca para comunicacao serial
    4. Biblioteca para comunicação TCP/IP
Biblioteca para acesso a arquivos de recursos
# rc.tcl
#    Suporte a arquivos de recursos.
#
# Copyright (c) 2000,2001 by Roberto Luiz Souza Monteiro
#
# Este arquivo e distribuido nos termos da licenca GNU GPL.
namespace eval rc {
    namespace export *
}
# rc::loadRc RcArray RcFile
#
#    Carrega um arquivo de recursos em um vetor associativo.
#
# Argumentos:
#    RcArray    Vetor associativo onde cada elemento corresponde
#               a uma variavel no arquivo de recursos.
#
#    RcFile     Arquivo de recursos.
#
# Retorno:
#    1          Arquivo encontrado.
#    0          Arquivo nao encontrado.
#
# Linhas de comentarios comecam com o caractere sustenido(#).
# Linhas em branco sao ignoradas.
# Recursos devem estar no formato: variavel=valor.
proc rc::loadRc {RcArray RcFile} {
    global $RcArray
 
    set RcFound 1
 
    if {[file exists $RcFile]} {
        set Handle [open $RcFile r]
        set Rc [read $Handle]
        close $Handle
 
        set RcList [split $Rc "\n"]
 
        if {[llength $RcList] > 0} {
            for {set i 0} {$i < [llength $RcList]} {incr i} {
                set RcLine [lindex $RcList $i]
                set RcLine [string trim $RcLine]
 
                if {[string index $RcLine 0] != "#"} {
                    if {[string trim $RcLine] != ""} {
                        set RcLineList [split $RcLine "="]
                        if {[llength $RcLineList] == 2} {
                            set Name [string trim [lindex $RcLineList 0]]
                            set Value [string trim [lindex $RcLineList 1]]
 
                            # Cria os elementos do vetor associativo
                            set ${RcArray}($Name) $Value
                        }
                    }
                }
            }
        }
    } else {
        set RcFound 0
    }
 
    return $RcFound
}
# rc::saveRc RcArray RcFile
#
#    Salva um vetor associativo em um arquivo de recursos.
#
# Argumentos:
#    RcArray    Vetor associativo onde cada elemento corresponde
#               a uma variavel no arquivo de recursos.
#
#    RcFile     Arquivo de recursos.
#
# Recursos estarao no formato: variavel=valor.
proc rc::saveRc {RcArray RcFile} {
    global $RcArray
 
    set RcList [array get $RcArray]
 
    set Handle [open $RcFile w+]
    for {set i 0} {$i <= [expr "[llength $RcList] - 2"]} {incr i} {
        set RcLine ""
        append RcLine [lindex $RcList $i] "=" [lindex $RcList [expr "$i + 1"]]
 
        incr i
 
        puts $Handle $RcLine
    }
 
    close $Handle
}
Biblioteca para criação de relatórios PostScript
# postscript.tcl --
#
#     Suporte a impressao PostScript.
#
# RCS: @(#) $Id: postscript.tcl,v 1.0 2001/06/23 15:31:00 monteiro Exp $
#
# Copyright (c) 2001 Roberto Luiz Souza Monteiro.
#
# Este arquivo e distribuido nos termos da licenca GNU GPL.
namespace eval ::postscript {}
# ::postscript::beginDocument
#     Cria o cabecalho PostScript Adobe 3.0.
#
# Resultados:
#     Codigo do cabecalho PostScript Adobe 3.0.
proc ::postscript::beginDocument {} {
    set PS "%!PS-Adobe-3.0 \r\n"
    append PS "%%BoundingBox: 0 0 612 792 \r\n"
    append PS "%%Pages: (atend) \r\n"
    append PS "%%PageOrder: Ascend \r\n\r\n"
 
    append PS "% Funcao para centralizar o texto na pagina. \r\n"
    append PS "/center { \r\n"
    append PS "    dup stringwidth pop \r\n"
    append PS "    2 div neg 0 rmoveto \r\n"
    append PS "} bind def \r\n\r\n"
 
    append PS "% Funcao para alinhar o texto a direita na pagina. \r\n"
    append PS "/right {dup stringwidth pop neg 0 rmoveto} bind def \r\n\r\n"
 
    return $PS
}
# ::postscript::beginPage Page
#     Inicia uma pagina.
#
# Argumentos:
#     Page    Numero da pagina.
#
# Resultados:
#     Codigo para iniciar uma pagina.
proc ::postscript::beginPage {{Page 1}} {
    set PS "% Inicio da pagina. \r\n"
    append PS "%%Page: $Page $Page \r\n\r\n"
 
    return $PS
}
# ::postscript::endPage Page
#     Finaliza a pagina.
#
# Argumentos:
#     Page    Numero da pagina.
#
# Resultados:
#     Codigo para finalizar a pagina.
proc ::postscript::endPage {{Page 1}} {
    set PS "% Final da pagina. \r\n"
    append PS "showpage \r\n"
    append PS "%%EndPage: $Page $Page \r\n\r\n"
 
    return $PS
}
# ::postscript::endDocument Pages
#     Finaliza um documento.
#
# Argumentos:
#     Pages    Numero de paginas.
#
# Resultados:
#     Codigo para finalizar o documento.
proc ::postscript::endDocument {{Pages 1}} {
    set PS "% Final do documento. \r\n"
    append PS "%%Trailer \r\n"
    append PS "%%Pages: $Pages \r\n"
    append PS "%%EOF \r\n"
 
    return $PS
}
# ::postscript::drawText X Y Text Font Size Justify
#     Desenha um texto no documento.
#
# Argumentos:
#     X          Coordenada X em polegadas.
#     Y          Coordenada Y em polegadas.
#     Text       Texto.
#     Font       Nome da fonte.
#     Size       Corpo da fonte.
#     Justify    Alinhamento do texto em relacao a coordenada X. Pode ser "", center ou right.
#
# Resultados:
#     Codigo para desenha um texto no documento.
proc ::postscript::drawText {{X 0} {Y 0} {Text ""} {Font Times} {Size 10} {Justify ""}} {
    set PS "% Desenha uma string na pagina. \r\n"
    append PS "/$Font findfont \r\n"
    append PS "$Size scalefont \r\n"
    append PS "setfont \r\n"
    append PS "[expr $X * 72] [expr $Y * 72] moveto \r\n"
    append PS "($Text) $Justify show \r\n\r\n"
 
    return $PS
}
# ::postscript::drawLine X1 Y1 X2 Y2
#     Desenha uma linha no documento.
#
# Argumentos:
#     X1              Coordenada X1 em polegadas.
#     Y1              Coordenada Y1 em polegadas.
#     X2              Coordenada X2 em polegadas.
#     Y2              Coordenada Y2 em polegadas.
#
# Resultados:
#     Codigo para desenha uma linha no documento.
proc ::postscript::drawLine {{X1 0} {Y1 0} {X2 0} {Y2 0}} {
    set PS "% Desenha uma linha na pagina. \r\n"
    append PS "[expr $X1 * 72] [expr $Y1 * 72] moveto \r\n"
    append PS "[expr $X2 * 72] [expr $Y2 * 72] lineto \r\n"
    append PS "stroke \r\n\r\n"
 
    return $PS
}
# ::postscript::drawRectangle X1 Y1 X2 Y2
#     Desenha um retangulo no documento.
#
# Argumentos:
#     X1              Coordenada X1 em polegadas.
#     Y1              Coordenada Y1 em polegadas.
#     Width           Largura em polegadas.
#     Height          Altura em polegadas.
#
# Resultados:
#     Codigo para desenha um retangulo no documento.
proc ::postscript::drawRectangle {{X1 0} {Y1 0} {Width 0} {Height 0}} {
    set PS "% Desenha um retangulo na pagina. \r\n"
    append PS "[expr $X1 * 72] [expr $Y1 * 72] moveto \r\n"
    append PS "[expr $Width * 72] 0 rlineto \r\n"
    append PS "0 [expr $Height * 72] rlineto \r\n"
    append PS "-[expr $Width * 72] 0 rlineto \r\n"
    append PS "closepath \r\n"
    append PS "stroke \r\n\r\n"
 
    return $PS
}
 

 
 
 

Biblioteca para comunicacao serial

# serial.tcl --
#
#     Biblioteca para envio e recebimento de bytes pela porta serial.
#
# RCS: @(#) $Id: serial.tcl,v 1.0 2001/03/10 08:31:00 monteiro Exp $
#
# Copyright (c) 2001 Roberto Luiz Souza Monteiro.
#
# Este arquivo e distribuido nos termos da licenca GNU GPL.

# Informacoes Tecnicas
#     Protocolo:
#         Dependendo da aplicacao, pode-se usar um dos protocolos abaixo:
#
#         <STX>dados<ETX>
#         <STX>dados<ETX><LRC>
#
#         <SI>dados<SO><LRC>
#
#         <STX><NBL><NBH>dados
#         <STX><NBL><NBH>dados<CSL><CSH>
#         <STX><NBL><NBH>dados<LRC>
#         dados<ETX>
#         dados<CR>
#
#         Onde LRC( Longitudinal Redundancy Check ) e um caractere de verificacao,
#         calculado da seguinte forma:
#
#         LRC = dado1 XOR dado2 XOR ... dadosN XOR ETX.
#         LRC = dado1 XOR dado2 XOR ... dadosN XOR SO.
#
#         NBL = Byte menos significativo da soma do numero de bytes que serao
#                enviados( dados + CSL + CSH ).
#         NBH = Byte mais significativo da soma do numero de bytes que serao
#                enviados( dados + CSL + CSH ).
#         CSL = Byte menos significativo da soma dos valores dos bytes que estao
#               sendo enviados.
#         CSH = Byte mais significativo da soma dos valores dos bytes que estao
#               sendo enviados.
#
#         Em alguns casos, pode ser conveniente que a cada byte, ou pacote
#         enviados, o receptor responda com um caractere ENQ, a fim de
#         sincronizar a comunicacao.
#
#     Caracteres ASCII de Controle:
#         NUL          00h    Null.
#         SOH          01h
#         STX          02h    Star of Text.
#         ETX          03h    End of Text.
#         EOT          04h    End of Transmission.
#         ENQ          05h    Enquire.
#         ACK          06h    Acknowledge.
#         BEL          07h    Soa um beep.
#         BS           08h    Backspace.
#         HT           09h    Horizontal Tabulation.
#         NL           0Ah
#         VT           0Bh    Vertical Tabulation.
#         NP,   FF     0Ch    Form Feed.
#         CR           0Dh    Carriage Return.
#         SO           0Eh    Shift Out.
#         SI           0Fh    Shift In.
#         DLE          10h
#         XON,  DC1    11h
#         DC2          12h
#         XOFF, DC3    13h
#         DC4          14h
#         NAK          15h    Negative Acknowledge.
#         SYN          16h
#         ETB          17h
#         CAN          18h
#         EM           19h
#         SUB          1Ah
#         ESC          1Bh    Escape.
#         FS           1Ch    Field Separator.
#         GS           1Dh
#         RS           1Eh
#         US           1Fh
#
# Status:
#     SERIAL_OK                Operacao bem sucedida.
#     SERIAL_ERROR_OPEN        Nao foi possivel abrir a porta serial.
#     SERIAL_ERROR_CLOSE       Nao foi possivel fechar a porta serial.
#     SERIAL_ERROR_READ        Nao foi possivel ler a porta serial.
#     SERIAL_ERROR_WRITE       Nao foi possivel escrever na porta serial.
#     SERIAL_ERROR_TIMEOUT     Ocorreu um Time Out ao tentar ler a porta serial.
#     SERIAL_ERROR_CHECKSUM    Soma de verificacao incorreta.

namespace eval serial:: {
    global tcl_platform
    
    variable handle ""
    # Configura a porta serial default, de acordo com a plataforma.
    if {$tcl_platform(platform) == "unix"} {
        variable port "/dev/ttyS0"
    } else {
        variable port "com1:"
    }
    variable baund 9600
    variable parity "n"
    variable data 8
    variable stop 1
    variable timeout 2000
    variable status "SERIAL_OK"
    variable binarySent ""
    variable asciiSent {}
    variable binaryChar ""
    variable asciiChar ""
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
}

# serial::init
#     Cria e inicializa as variaveis do namespace.
proc serial::init {} {
    global tcl_platform
    
    variable handle ""
    # Configura a porta serial default, de acordo com a plataforma.
    if {$tcl_platform(platform) == "unix"} {
        variable port "/dev/ttyS0"
    } else {
        variable port "com1:"
    }
    variable baund 9600
    variable parity "n"
    variable data 8
    variable stop 1
    variable timeout 2000
    variable status "SERIAL_OK"
    variable binarySent ""
    variable asciiSent {}
    variable binaryChar ""
    variable asciiChar ""
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
}

# serial::openport Port Baund Parity Data Stop
#     Abre e configura a porta serial.
#
# Argumentos:
#     Port      Porta serial.
#     Baund     Velocidade( 110, 300, 1200, 2400, 4800, 9600, 19200, 38400,
#               57600, 115200, 230400, 460800, 921600 ).
#     Parity    Paridade( n, o, e, m, s ).
#     Data      Numero de bits de dados( 5 a 8 ).
#     Stop      Numero de bits de parada( 1 ou 2 ).
#
# Resultados:
#     Handle para a porta serial.
proc serial::openport {{Port ""} {Baund ""} {Parity ""} {Data ""} {Stop ""}} {
    variable handle
    variable port
    variable baund
    variable parity
    variable data
    variable stop
    variable status "SERIAL_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Port] > 0} {
        set port $Port
    }
    if {[string length $Baund] > 0} {
        set baund $Baund
    }
    if {[string length $Parity] > 0} {
        set parity $Parity
    }
    if {[string length $Data] > 0} {
        set data $Data
    }
    if {[string length $Stop] > 0} {
        set stop $Stop
    }
    
    # Abre e configura a porta serial.
    set Result [catch {
        set handle [open $port r+]
        fconfigure $handle -blocking 0 -translation binary -mode "$baund,$parity,$data,$stop"
    }]
    
    if {$Result != 0} {
        set status "SERIAL_ERROR_OPEN"
    }
    
    return $handle
}

# serial::closeport Handle
#     Fecha a porta serial.
#
# Argumentos:
#     Handle    Handle para a porta serial.
#
# Resultados:
#     0 se a operacao for concluida com exito.
proc serial::closeport {{Handle ""}} {
    variable handle
    variable status "SERIAL_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Fecha a porta serial.
    set Result [catch {
        close $handle
    }]
    
    if {$Result != 0} {
        set status "SERIAL_ERROR_CLOSE"
    }
    
    set handle ""
    
    return $Result
}

# serial::putchar Handle Byte
#     Envia um byte para a porta serial.
#
# Argumento:
#     Handle    Handle para a porta serial.
#     Byte      Byte a ser enviado.
proc serial::putchar {{Handle ""} {Byte ""}} {
    variable handle
    variable status "SERIAL_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Envia o byte para a porta serial.
    set Result [catch {
        puts -nonewline $handle $Byte
        flush $handle
    }]
    
    if {$Result != 0} {
        set status "SERIAL_ERROR_WRITE"
    }
}

# serial::putstring Handle String
#     Envia uma string para a porta serial.
#
# Argumento:
#     Handle    Handle para a porta serial.
#     String    String a ser enviada.
proc serial::putstring {{Handle ""} {String ""}} {
    variable handle
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        serial::putchar $handle [string index $String $i]
    }
}

# serial::getchar Handle TimeOut
#     Recebe um byte da porta serial.
#
# Argumentos:
#     Handle     Handle para a porta serial.
#     TimeOut    Tempo, em milisegundos para que ocorra um TIMEOUT.
#
# Resultados:
#     Byte recebido.
proc serial::getchar {{Handle ""} {TimeOut ""}} {
    variable handle
    variable timeout
    variable status "SERIAL_OK"
    variable binaryChar ""
    variable asciiChar ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Configura as variaveis do namespace.
    if {[string length $TimeOut] > 0} {
        set timeout $TimeOut
    }
    
    # Aguarda, time milisegundos, por um byte vindo da porta serial.
    set Byte ""
    
    set Begin [clock clicks -milliseconds]
    
    while {[expr [clock clicks -milliseconds] - $Begin] < $timeout} {
        set Result [catch {
            set Byte [read $handle 1]
        }]
        
        if {$Result != 0} {
            set status "SERIAL_ERROR_READ"
        }
        
        if {[string length $Byte] == 1} {
            break
        }
    }
    
    # Salva o byte em formato binario e ASCII para fins de depuracao.
    set binaryChar $Byte
    binary scan $Byte c asciiChar
    
    return $Byte
}

# serial::getstring Handle Size TimeOut
#     Recebe uma string pela porta serial.
#
# Argumentos:
#     Handle     Handle para a porta serial.
#     Size       Tamanho em bytes.
#     TimeOut    Tempo, em milisegundos para que ocorra um TIMEOUT.
#
# Resultados:
#     String recebida.
proc serial::getstring {{Handle ""} {Size 254} {TimeOut ""}} {
    variable handle
    variable timeout
    variable status "SERIAL_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set String ""
    
    # Configura as variaveis do namespace.
    if {[string length $TimeOut] > 0} {
        set timeout $TimeOut
    }
    
    for {set i 1} {$i <= $Size} {incr i} {
        # Aguarda, time milisegundos, por um byte vindo da porta serial.
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            break
        }
        
        append String $Byte
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $String
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    return $String
}

# serial::calculateLRC String
#     Calcula o LRC ( um XOR de todos od bytes ) da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o LRC.
#
# Resultados:
#     LRC.
proc serial::calculateLRC {{String ""}} {
    set LRC 0
    set ASCII 0
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        set LRC [expr $LRC ^ $ASCII]
    }
    
    return [binary format c $LRC]
}

# serial::calculateCheckSum String
#     Calcula o CheckSum ( soma de todos os bytes ) da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o CheckSum.
#
# Resultados:
#     Lista contendo {CSL CSH} do CheckSum.
proc serial::calculateCheckSum {{String ""}} {
    set CheckSum 0
    set ASCII 0
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        incr CheckSum $ASCII
    }
    
    if {$CheckSum >= 256} {
        set CSL [binary format c [expr "int($CheckSum % 256)"]]
        set CSH [binary format c [expr "int($CheckSum / 256)"]]
    } else {
        set CSL [binary format c $CheckSum]
        set CSH [binary format c 0]
    }
    
    return [list $CSL $CSH]
}

# serial::calculateBytes String
#     Calcula o numero de bytes da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o numero de bytes.
#
# Resultados:
#     Lista contendo {NBL NBH} do numero de bytes.
proc serial::calculateBytes {{String ""}} {
    set Bytes 0
    set ASCII 0
    
    set Bytes [string length $String]
    
    if {$Bytes >= 256} {
        set NBL [binary format c [expr "int($Bytes % 256)"]]
        set NBH [binary format c [expr "int($Bytes / 256)"]]
    } else {
        set NBL [binary format c $Bytes]
        set NBH [binary format c 0]
    }
    
    return [list $NBL $NBH]
}

# serial::sendText Handle String sendLRC
#     Envia uma string para a porta serial usando o protocolo:
#     <STX>dados<ETX><LRC>
#
# Argumentos:
#     Handle     Handle para a porta serial.
#     String     String a ser enviada.
#     sendLRC    Se 1, sera enviado um LRC de verificacao dos dados,
#                se 0, nao sera enviado um LRC de verificacao dos dados.
proc serial::sendText {{Handle ""} {String ""} {sendLRC 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }

    set Text ""
    
    append Text $String
    
    # Inclui o caractere ETX.
    append Text "\x03"
    
    # Envia o caractere STX.
    serial::putchar $handle "\x02"
    
    # Envia a string.
    serial::putstring $handle $Text
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x02"
    append binarySent $Text
    
    # Envia o caractere LRC.
    if {$sendLRC == 1} {
        serial::putchar $handle [serial::calculateLRC $Text]
        
        append binarySent [serial::calculateLRC $Text]
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# serial::receiveText Handle receiveLRC
#     Recebe uma string pela a porta serial usando o protocolo:
#     <STX>dados<ETX><LRC>
#
# Argumentos:
#     Handle        Handle para a porta serial.
#     receiveLRC    Se 1, sera calculado um LRC de verificacao dos dados,
#                   se 0, nao sera calculado um LRC de verificacao dos dados.
#
# Resultados:
#     String recebida.
proc serial::receiveText {{Handle ""} {receiveLRC 1}} {
    variable handle
    variable status "SERIAL_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Continua a receber os bytes ate encontrar um caractere STX.
        if {$Byte == "\x02"} {
            # Armazena o byte recebido.
            append Text $Byte
            
            break
        }
    }
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere ETX.
        if {$Byte == "\x03"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Recebe o caractere LRC.
    if {$receiveLRC == 1} {
        set LRC [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$LRC == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        set checkSumReceived $LRC
        set checkSumCalculated [serial::calculateLRC [string range $Text 1 [expr [string length $Text] - 1]]]
        
        if {$checkSumReceived != $checkSumCalculated} {
            set status "SERIAL_ERROR_CHECKSUM"
            
            return
        }
        
        # Monta a string binaria para fins de depuracao.
        append binaryReceived $LRC
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    if {[string length $Text] > 3} {
        return [string range $Text 1 [expr [string length $Text] - 2]]
    }
}

# serial::sendShift Handle String sendLRC
#     Envia uma string para a porta serial usando o protocolo:
#     <SI>dados<SO><LRC>
#
# Argumentos:
#     Handle     Handle para a porta serial.
#     String     String a ser enviada.
#     sendLRC    Se 1, sera enviado um LRC de verificacao dos dados,
#                se 0, nao sera enviado um LRC de verificacao dos dados.
proc serial::sendShift {{Handle ""} {String ""} {sendLRC 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }

    set Text ""
    
    append Text $String
    
    # Inclui o caractere SO.
    append Text "\x0E"
    
    # Envia o caractere SI.
    serial::putchar $handle "\x0F"
    
    # Envia a string.
    serial::putstring $handle $Text
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x0F"
    append binarySent $Text
    
    # Envia o caractere LRC.
    if {$sendLRC == 1} {
        serial::putchar $handle [serial::calculateLRC $Text]
        
        append binarySent [serial::calculateLRC $Text]
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# serial::receiveShift Handle receiveLRC
#     Recebe uma string pela a porta serial usando o protocolo:
#     <SI>dados<SO><LRC>
#
# Argumentos:
#     Handle        Handle para a porta serial.
#     receiveLRC    Se 1, sera calculado um LRC de verificacao dos dados,
#                   se 0, nao sera calculado um LRC de verificacao dos dados.
#
# Resultados:
#     String recebida.
proc serial::receiveShift {{Handle ""} {receiveLRC 1}} {
    variable handle
    variable status "SERIAL_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Continua a receber os bytes ate encontrar um caractere SI.
        if {$Byte == "\x0F"} {
            # Armazena o byte recebido.
            append Text $Byte
            
            break
        }
    }
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere SO.
        if {$Byte == "\x0E"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Recebe o caractere LRC.
    if {$receiveLRC == 1} {
        set LRC [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$LRC == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        set checkSumReceived $LRC
        set checkSumCalculated [serial::calculateLRC [string range $Text 1 [expr [string length $Text] - 1]]]
        
        if {$checkSumReceived != $checkSumCalculated} {
            set status "SERIAL_ERROR_CHECKSUM"
            
            return
        }
        
        # Monta a string binaria para fins de depuracao.
        append binaryReceived $LRC
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    if {[string length $Text] > 3} {
        return [string range $Text 1 [expr [string length $Text] - 2]]
    }
}

# serial::sendBinary Handle String sendCheckSum
#     Envia uma string para a porta serial usando o protocolo:
#     <STX><NBL><NBH>dados<CSL><CSH>
#
# Argumentos:
#     Handle          Handle para a porta serial.
#     String          String a ser enviada.
#     sendCheckSum    Se 1, sera enviado um CheckSum de verificacao dos dados,
#                     se 0, nao sera enviado um CheckSum de verificacao dos dados.
proc serial::sendBinary {{Handle ""} {String ""} {sendCheckSum 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    append Text $String
    
    # Inclui a soma de verificacao.
    if {$sendCheckSum == 1} {
        append Text [join [serial::calculateCheckSum $String] ""]
    }
    
    # Inclui o numero de bytes que serao enviados.
    set TextToSend ""
    
    append TextToSend [join [serial::calculateBytes $Text] ""] $Text
    
    # Envia o caractere STX.
    serial::putchar $handle "\x02"
    
    # Envia a string.
    serial::putstring $handle $TextToSend
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x02"
    append binarySent $TextToSend
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# serial::receiveTextETX Handle receiveLRC
#     Recebe uma string pela a porta serial usando o protocolo:
#     dados<ETX>
#
# Argumentos:
#     Handle        Handle para a porta serial.
#
# Resultados:
#     String recebida.
proc serial::receiveTextETX {{Handle ""}} {
    variable handle
    variable status "SERIAL_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere ETX.
        if {$Byte == "\x03"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    return $Text
}

# serial::receiveTextCR Handle receiveLRC
#     Recebe uma string pela a porta serial usando o protocolo:
#     dados<CR>
#
# Argumentos:
#     Handle        Handle para a porta serial.
#
# Resultados:
#     String recebida.
proc serial::receiveTextCR {{Handle ""}} {
    variable handle
    variable status "SERIAL_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [serial::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SERIAL_OK"} {
                set status "SERIAL_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere CR.
        if {$Byte == "\x0d"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    return $Text
}

# serial::binary2ascii String
#     Converte uma string binaria para ASCII.
#
# Argumentos:
#     String     String a ser convertida.
#
# Resultados:
#     String em formato ASCII.
proc serial::binary2ascii {{String ""}} {
    set ASCII 0
    set asciiString ""
    
    # Monta a string em formato ASCII.
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        append asciiString $ASCII
    }
    
    return $asciiString
}
 

 
 
 

Biblioteca para comunicação TCP/IP

# Socket.tcl --
#
#     Biblioteca para envio e recebimento de bytes por um socket TCP/IP.
#
# RCS: @(#) $Id: Socket.tcl,v 1.0 2001/07/03 16:16:00 monteiro Exp $
#
# Copyright (c) 2001 Roberto Luiz Souza Monteiro.
#
# Este arquivo e distribuido nos termos da licenca GNU GPL.

# Informacoes Tecnicas
#     Protocolo:
#         Dependendo da aplicacao, pode-se usar um dos protocolos abaixo:
#
#         <STX>dados<ETX>
#         <STX>dados<ETX><LRC>
#
#         <SI>dados<SO><LRC>
#
#         <STX><NBL><NBH>dados
#         <STX><NBL><NBH>dados<CSL><CSH>
#         <STX><NBL><NBH>dados<LRC>
#         dados<ETX>
#         dados<CR>
#
#         Onde LRC( Longitudinal Redundancy Check ) e um caractere de verificacao,
#         calculado da seguinte forma:
#
#         LRC = dado1 XOR dado2 XOR ... dadosN XOR ETX.
#         LRC = dado1 XOR dado2 XOR ... dadosN XOR SO.
#
#         NBL = Byte menos significativo da soma do numero de bytes que serao
#                enviados( dados + CSL + CSH ).
#         NBH = Byte mais significativo da soma do numero de bytes que serao
#                enviados( dados + CSL + CSH ).
#         CSL = Byte menos significativo da soma dos valores dos bytes que estao
#               sendo enviados.
#         CSH = Byte mais significativo da soma dos valores dos bytes que estao
#               sendo enviados.
#
#         Em alguns casos, pode ser conveniente que a cada byte, ou pacote
#         enviados, o receptor responda com um caractere ENQ, a fim de
#         sincronizar a comunicacao.
#
#     Caracteres ASCII de Controle:
#         NUL          00h    Null.
#         SOH          01h
#         STX          02h    Star of Text.
#         ETX          03h    End of Text.
#         EOT          04h    End of Transmission.
#         ENQ          05h    Enquire.
#         ACK          06h    Acknowledge.
#         BEL          07h    Soa um beep.
#         BS           08h    Backspace.
#         HT           09h    Horizontal Tabulation.
#         NL           0Ah
#         VT           0Bh    Vertical Tabulation.
#         NP,   FF     0Ch    Form Feed.
#         CR           0Dh    Carriage Return.
#         SO           0Eh    Shift Out.
#         SI           0Fh    Shift In.
#         DLE          10h
#         XON,  DC1    11h
#         DC2          12h
#         XOFF, DC3    13h
#         DC4          14h
#         NAK          15h    Negative Acknowledge.
#         SYN          16h
#         ETB          17h
#         CAN          18h
#         EM           19h
#         SUB          1Ah
#         ESC          1Bh    Escape.
#         FS           1Ch    Field Separator.
#         GS           1Dh
#         RS           1Eh
#         US           1Fh
#
# Status:
#     SOCKET_OK                Operacao bem sucedida.
#     SOCKET_ERROR_OPEN        Nao foi possivel abrir a porta TCP/IP.
#     SOCKET_ERROR_CLOSE       Nao foi possivel fechar a porta TCP/IP.
#     SOCKET_ERROR_READ        Nao foi possivel ler a porta TCP/IP.
#     SOCKET_ERROR_WRITE       Nao foi possivel escrever na porta TCP/IP.
#     SOCKET_ERROR_TIMEOUT     Ocorreu um Time Out ao tentar ler a porta TCP/IP.
#     SOCKET_ERROR_CHECKSUM    Soma de verificacao incorreta.

namespace eval Socket:: {
    variable handle ""
    variable address ""
    variable port ""
    variable timeout 2000
    variable status "SOCKET_OK"
    variable binarySent ""
    variable asciiSent {}
    variable binaryChar ""
    variable asciiChar ""
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
}

# Socket::init
#     Cria e inicializa as variaveis do namespace.
proc Socket::init {} {
    variable handle ""
    variable address ""
    variable port ""
    variable timeout 2000
    variable status "SOCKET_OK"
    variable binarySent ""
    variable asciiSent {}
    variable binaryChar ""
    variable asciiChar ""
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
}

# Socket::openport Address Port
#     Abre e configura a porta TCP/IP.
#
# Argumentos:
#     Address    Endereco IP do servidor.
#     Port       Porta no servidor.
#
# Resultados:
#     Handle para a porta TCP/IP.
proc Socket::openport {{Address ""} {Port ""}} {
    variable handle
    variable address
    variable port
    variable status "SOCKET_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Address] > 0} {
        set address $Address
    }
    if {[string length $Port] > 0} {
        set port $Port
    }
    
    # Abre e configura a porta TCP/IP.
    set Result [catch {
        set handle [socket $address $port]
        fconfigure $handle -blocking 0 -translation binary
    }]
    
    if {$Result != 0} {
        set status "SOCKET_ERROR_OPEN"
    }
    
    return $handle
}

# Socket::configure Handle
#     Abre e configura a porta TCP/IP.
#
# Argumentos:
#     Handle    Handle para a porta TCP/IP.
#
# Resultados:
#     Handle para a porta TCP/IP.
proc Socket::configure {{Handle ""}} {
    variable handle
    variable status "SOCKET_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
        
    # Abre e configura a porta TCP/IP.
    set Result [catch {
        fconfigure $handle -blocking 0 -translation binary
    }]
    
    if {$Result != 0} {
        set status "SOCKET_ERROR_OPEN"
    }
    
    return $handle
}

# Socket::closeport Handle
#     Fecha a porta TCP/IP.
#
# Argumentos:
#     Handle    Handle para a porta TCP/IP.
#
# Resultados:
#     0 se a operacao for concluida com exito.
proc Socket::closeport {{Handle ""}} {
    variable handle
    variable status "SOCKET_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Fecha a porta TCP/IP.
    set Result [catch {
        close $handle
    }]
    
    if {$Result != 0} {
        set status "SOCKET_ERROR_CLOSE"
    }
    
    set handle ""
    
    return $Result
}

# Socket::putchar Handle Byte
#     Envia um byte para a porta TCP/IP.
#
# Argumento:
#     Handle    Handle para a porta TCP/IP.
#     Byte      Byte a ser enviado.
proc Socket::putchar {{Handle ""} {Byte ""}} {
    variable handle
    variable status "SOCKET_OK"
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Envia o byte para a porta TCP/IP.
    set Result [catch {
        puts -nonewline $handle $Byte
        flush $handle
    }]
    
    if {$Result != 0} {
        set status "SOCKET_ERROR_WRITE"
    }
}

# Socket::putstring Handle String
#     Envia uma string para a porta TCP/IP.
#
# Argumento:
#     Handle    Handle para a porta TCP/IP.
#     String    String a ser enviada.
proc Socket::putstring {{Handle ""} {String ""}} {
    variable handle
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        Socket::putchar $handle [string index $String $i]
    }
}

# Socket::getchar Handle TimeOut
#     Recebe um byte da porta TCP/IP.
#
# Argumentos:
#     Handle     Handle para a porta TCP/IP.
#     TimeOut    Tempo, em milisegundos para que ocorra um TIMEOUT.
#
# Resultados:
#     Byte recebido.
proc Socket::getchar {{Handle ""} {TimeOut ""}} {
    variable handle
    variable timeout
    variable status "SOCKET_OK"
    variable binaryChar ""
    variable asciiChar ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    # Configura as variaveis do namespace.
    if {[string length $TimeOut] > 0} {
        set timeout $TimeOut
    }
    
    # Aguarda, time milisegundos, por um byte vindo da porta TCP/IP.
    set Byte ""
    
    set Begin [clock clicks -milliseconds]
    
    while {[expr [clock clicks -milliseconds] - $Begin] < $timeout} {
        set Result [catch {
            set Byte [read $handle 1]
        }]
        
        if {$Result != 0} {
            set status "SOCKET_ERROR_READ"
        }
        
        if {[string length $Byte] == 1} {
            break
        }
    }
    
    # Salva o byte em formato binario e ASCII para fins de depuracao.
    set binaryChar $Byte
    binary scan $Byte c asciiChar
    
    return $Byte
}

# Socket::getstring Handle Size TimeOut
#     Recebe uma string pela porta TCP/IP.
#
# Argumentos:
#     Handle     Handle para a porta TCP/IP.
#     Size       Tamanho em bytes.
#     TimeOut    Tempo, em milisegundos para que ocorra um TIMEOUT.
#
# Resultados:
#     String recebida.
proc Socket::getstring {{Handle ""} {Size 254} {TimeOut ""}} {
    variable handle
    variable timeout
    variable status "SOCKET_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set String ""
    
    # Configura as variaveis do namespace.
    if {[string length $TimeOut] > 0} {
        set timeout $TimeOut
    }
    
    for {set i 1} {$i <= $Size} {incr i} {
        # Aguarda, time milisegundos, por um byte vindo da porta TCP/IP.
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            break
        }
        
        append String $Byte
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $String
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    return $String
}

# Socket::calculateLRC String
#     Calcula o LRC ( um XOR de todos od bytes ) da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o LRC.
#
# Resultados:
#     LRC.
proc Socket::calculateLRC {{String ""}} {
    set LRC 0
    set ASCII 0
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        set LRC [expr $LRC ^ $ASCII]
    }
    
    return [binary format c $LRC]
}

# Socket::calculateCheckSum String
#     Calcula o CheckSum ( soma de todos os bytes ) da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o CheckSum.
#
# Resultados:
#     Lista contendo {CSL CSH} do CheckSum.
proc Socket::calculateCheckSum {{String ""}} {
    set CheckSum 0
    set ASCII 0
    
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        incr CheckSum $ASCII
    }
    
    if {$CheckSum >= 256} {
        set CSL [binary format c [expr "int($CheckSum % 256)"]]
        set CSH [binary format c [expr "int($CheckSum / 256)"]]
    } else {
        set CSL [binary format c $CheckSum]
        set CSH [binary format c 0]
    }
    
    return [list $CSL $CSH]
}

# Socket::calculateBytes String
#     Calcula o numero de bytes da string dada.
#
# Argumentos:
#     String    String para a qual sera calculado o numero de bytes.
#
# Resultados:
#     Lista contendo {NBL NBH} do numero de bytes.
proc Socket::calculateBytes {{String ""}} {
    set Bytes 0
    set ASCII 0
    
    set Bytes [string length $String]
    
    if {$Bytes >= 256} {
        set NBL [binary format c [expr "int($Bytes % 256)"]]
        set NBH [binary format c [expr "int($Bytes / 256)"]]
    } else {
        set NBL [binary format c $Bytes]
        set NBH [binary format c 0]
    }
    
    return [list $NBL $NBH]
}

# Socket::sendText Handle String sendLRC
#     Envia uma string para a porta TCP/IP usando o protocolo:
#     <STX>dados<ETX><LRC>
#
# Argumentos:
#     Handle     Handle para a porta TCP/IP.
#     String     String a ser enviada.
#     sendLRC    Se 1, sera enviado um LRC de verificacao dos dados,
#                se 0, nao sera enviado um LRC de verificacao dos dados.
proc Socket::sendText {{Handle ""} {String ""} {sendLRC 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }

    set Text ""
    
    append Text $String
    
    # Inclui o caractere ETX.
    append Text "\x03"
    
    # Envia o caractere STX.
    Socket::putchar $handle "\x02"
    
    # Envia a string.
    Socket::putstring $handle $Text
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x02"
    append binarySent $Text
    
    # Envia o caractere LRC.
    if {$sendLRC == 1} {
        Socket::putchar $handle [Socket::calculateLRC $Text]
        
        append binarySent [Socket::calculateLRC $Text]
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# Socket::receiveText Handle receiveLRC
#     Recebe uma string pela a porta TCP/IP usando o protocolo:
#     <STX>dados<ETX><LRC>
#
# Argumentos:
#     Handle        Handle para a porta TCP/IP.
#     receiveLRC    Se 1, sera calculado um LRC de verificacao dos dados,
#                   se 0, nao sera calculado um LRC de verificacao dos dados.
#
# Resultados:
#     String recebida.
proc Socket::receiveText {{Handle ""} {receiveLRC 1}} {
    variable handle
    variable status "SOCKET_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Continua a receber os bytes ate encontrar um caractere STX.
        if {$Byte == "\x02"} {
            # Armazena o byte recebido.
            append Text $Byte
            
            break
        }
    }
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere ETX.
        if {$Byte == "\x03"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Recebe o caractere LRC.
    if {$receiveLRC == 1} {
        set LRC [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$LRC == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        set checkSumReceived $LRC
        set checkSumCalculated [Socket::calculateLRC [string range $Text 1 [expr [string length $Text] - 1]]]
        
        if {$checkSumReceived != $checkSumCalculated} {
            set status "SOCKET_ERROR_CHECKSUM"
            
            return
        }
        
        # Monta a string binaria para fins de depuracao.
        append binaryReceived $LRC
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    if {[string length $Text] > 3} {
        return [string range $Text 1 [expr [string length $Text] - 2]]
    }
}

# Socket::sendShift Handle String sendLRC
#     Envia uma string para a porta TCP/IP usando o protocolo:
#     <SI>dados<SO><LRC>
#
# Argumentos:
#     Handle     Handle para a porta TCP/IP.
#     String     String a ser enviada.
#     sendLRC    Se 1, sera enviado um LRC de verificacao dos dados,
#                se 0, nao sera enviado um LRC de verificacao dos dados.
proc Socket::sendShift {{Handle ""} {String ""} {sendLRC 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }

    set Text ""
    
    append Text $String
    
    # Inclui o caractere SO.
    append Text "\x0E"
    
    # Envia o caractere SI.
    Socket::putchar $handle "\x0F"
    
    # Envia a string.
    Socket::putstring $handle $Text
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x0F"
    append binarySent $Text
    
    # Envia o caractere LRC.
    if {$sendLRC == 1} {
        Socket::putchar $handle [Socket::calculateLRC $Text]
        
        append binarySent [Socket::calculateLRC $Text]
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# Socket::receiveShift Handle receiveLRC
#     Recebe uma string pela a porta TCP/IP usando o protocolo:
#     <SI>dados<SO><LRC>
#
# Argumentos:
#     Handle        Handle para a porta TCP/IP.
#     receiveLRC    Se 1, sera calculado um LRC de verificacao dos dados,
#                   se 0, nao sera calculado um LRC de verificacao dos dados.
#
# Resultados:
#     String recebida.
proc Socket::receiveShift {{Handle ""} {receiveLRC 1}} {
    variable handle
    variable status "SOCKET_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    variable checkSumReceived ""
    variable checkSumCalculated ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Continua a receber os bytes ate encontrar um caractere SI.
        if {$Byte == "\x0F"} {
            # Armazena o byte recebido.
            append Text $Byte
            
            break
        }
    }
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere SO.
        if {$Byte == "\x0E"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Recebe o caractere LRC.
    if {$receiveLRC == 1} {
        set LRC [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$LRC == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        set checkSumReceived $LRC
        set checkSumCalculated [Socket::calculateLRC [string range $Text 1 [expr [string length $Text] - 1]]]
        
        if {$checkSumReceived != $checkSumCalculated} {
            set status "SOCKET_ERROR_CHECKSUM"
            
            return
        }
        
        # Monta a string binaria para fins de depuracao.
        append binaryReceived $LRC
    }
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    # Retorna a string recebida.
    if {[string length $Text] > 3} {
        return [string range $Text 1 [expr [string length $Text] - 2]]
    }
}

# Socket::sendBinary Handle String sendCheckSum
#     Envia uma string para a porta TCP/IP usando o protocolo:
#     <STX><NBL><NBH>dados<CSL><CSH>
#
# Argumentos:
#     Handle          Handle para a porta TCP/IP.
#     String          String a ser enviada.
#     sendCheckSum    Se 1, sera enviado um CheckSum de verificacao dos dados,
#                     se 0, nao sera enviado um CheckSum de verificacao dos dados.
proc Socket::sendBinary {{Handle ""} {String ""} {sendCheckSum 1}} {
    variable handle
    variable binarySent ""
    variable asciiSent {}
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    append Text $String
    
    # Inclui a soma de verificacao.
    if {$sendCheckSum == 1} {
        append Text [join [Socket::calculateCheckSum $String] ""]
    }
    
    # Inclui o numero de bytes que serao enviados.
    set TextToSend ""
    
    append TextToSend [join [Socket::calculateBytes $Text] ""] $Text
    
    # Envia o caractere STX.
    Socket::putchar $handle "\x02"
    
    # Envia a string.
    Socket::putstring $handle $TextToSend
    
    # Monta a string binaria para fins de depuracao.
    append binarySent "\x02"
    append binarySent $TextToSend
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binarySent]} {incr i} {
        binary scan [string index $binarySent $i] c ASCII
        lappend asciiSent $ASCII
    }
    
    return
}

# Socket::receiveTextETX Handle receiveLRC
#     Recebe uma string pela a porta TCP/IP usando o protocolo:
#     dados<ETX>
#
# Argumentos:
#     Handle        Handle para a TCP/IP Socket.
#
# Resultados:
#     String recebida.
proc Socket::receiveTextETX {{Handle ""}} {
    variable handle
    variable status "SOCKET_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere ETX.
        if {$Byte == "\x03"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    return $Text
}

# Socket::receiveTextCR Handle receiveLRC
#     Recebe uma string pela a porta TCP/IP usando o protocolo:
#     dados<CR>
#
# Argumentos:
#     Handle        Handle para a porta TCP/IP.
#
# Resultados:
#     String recebida.
proc Socket::receiveTextCR {{Handle ""}} {
    variable handle
    variable status "SOCKET_OK"
    variable binaryReceived ""
    variable asciiReceived ""
    
    # Configura as variaveis do namespace.
    if {[string length $Handle] > 0} {
        set handle $Handle
    }
    
    set Text ""
    
    while 1 {
        set Byte [Socket::getchar $handle]
        
        # Se nenhum byte for recebido, ocorreu um TIMEOUT.
        if {$Byte == ""} {
            if {$status == "SOCKET_OK"} {
                set status "SOCKET_ERROR_TIMEOUT"
            }
            
            return
        }
        
        # Armazena o byte recebido.
        append Text $Byte
        
        # Continua a receber os bytes ate encontrar um caractere CR.
        if {$Byte == "\x0d"} {
            break
        }
    }
    
    # Monta a string binaria para fins de depuracao.
    append binaryReceived $Text
    
    # Monta a string em formato ASCII para fins de depuracao.
    set ASCII 0
    
    for {set i 0} {$i < [string length $binaryReceived]} {incr i} {
        binary scan [string index $binaryReceived $i] c ASCII
        lappend asciiReceived $ASCII
    }
    
    return $Text
}

# Socket::binary2ascii String
#     Converte uma string binaria para ASCII.
#
# Argumentos:
#     String     String a ser convertida.
#
# Resultados:
#     String em formato ASCII.
proc Socket::binary2ascii {{String ""}} {
    set ASCII 0
    set asciiString ""
    
    # Monta a string em formato ASCII.
    for {set i 0} {$i < [string length $String]} {incr i} {
        binary scan [string index $String $i] c ASCII
        append asciiString $ASCII
    }
    
    return $asciiString
}


Para aprender mais sobre programação em Tcl/Tk adquira o livro Tcl/Tk Guia de Referência, de minha autoria e editado pela Editora Novatech.

Para maiores informações envie e-mail para info@souzamonteiro.com.


http://www.souzamonteiro.com
info@souzamonteiro.com

Copyright(C) 2000 by Roberto Luiz Souza Monteiro