Recebemos como doação um antigo medidor da WTW™ modelo “MultiLine P4” e desenvolvemos mais um módulo para permitir o uso dos recursos do programa Multipar com esse instrumento.
Consegui encontrar, com muita dificuldade, o manual do instrumento na página de manuais e catálogos da empresa http://www.mikro-polo.com/en/for-customers/documents.aspx. Mas também deixei uma cópia para download aqui.
Com o uso do programa femto600s.tcl observei que o MultiLine P4 envia uma séria de caracteres “não imprimíveis”.
Para identificar esses caractares salvei a saída em um arquivo texto, abri com o programa Vi e digitei o comando :set list para exibir a posição dos caracteres “não imprimíveis” que aparecem como uma série de caracteres “$”. (Fonte: set list command in vi)
Segundo dica no link Advanced Vi Cheat Sheet o caracter “$” significa fim de linha.
O editor Vi exibe “^Q” e “^S” e no editor Gedit essas posições aparecem como 0011 e 0013 respectivamente.
Para identificar a presença de “caracteres especiais” utilizei os seguintes testes “if” no programa femto600s.tcl:
if { [regexp {\u0013} $dados c] } { .tela.dados insert end "\nVariável Ω -> $c\n" } if { [regexp {\u00F8} $dados c] } { .tela.dados insert end "\nVariável ø -> $c\n" } if { [regexp {\u00E6} $dados c] } { .tela.dados insert end "\nVariável æ -> $c\n" } if { [regexp {\u0011} $dados c] } { .tela.dados insert end "\nVariável de controle -> $c\n" } if { [regexp "\n" $dados c] } { .tela.dados insert end "\nVariável nova linha -> $c\n" } if { [regexp {\u21A1} $dados c] } { .tela.dados insert end "\nVariável Form Feed 21A1 -> $c\n" } if { [regexp {\u000C} $dados c] } { .tela.dados insert end "\nVariável Form Feed 000C-> $c\n" } if { [regexp {\x0D} $dados c] } { .tela.dados insert end "\nVariável Carriage Return -> $c\n" }
A letra grega μ das leituras de condutividade na faixa de μS/cm (água destilada) era representada pelo caracter æ. E para identificar a unidade na faixa de mS/cm tive que usar uma solução salina.
Usando o comando gets foi possível identificar que o instrumento envia dados pela porta serial em dois blocos:
pH E3 '0011' '0013' 89 æS/cm 21,7 øC e nLF Tref25 '0011''0013' 04,07,16 10:14
Observei que o instrumento desligava após alguns minutos e tentei desativar o desligamento automático apagando as leituras armazenadas na memória interna seguindo os passos:
Desligar e religar pressionando -> STO + ON/OFF
Deve aparecer na tela Clr Sto Store (Se houver dados armazenados na memória
Em seguida pressionar RUN/ENTER para confirmar a remoção dos dados
Mais tarde descobri que isso não era necessário. :-(
Conforme informação na página 21:
Continuous operation with connected interface cable and/or activated time-controlled output ( SEr 0n ).
Basta conectar o cabo serial e o instrumento permanece ligado continuamente.
O pacote zip está disponível para download aqui.
Para reduzir o espaço ocupado na bancada tomei a iniciativa de experimentar o uso da placa Raspberry Pi para fazer a aquisição das leituras desse medidor.
Os procedimentos de instalação do sistema operacional e dos pacotes necessários estão descritos na seção “Raspbery Pi” da página Diário Linux.
Instalei a Tcl/Tk, o banco de dados Metakit e a biblioteca Plotchart para permitir executar o programa Multipar 04. Em seguida conectei o medidor Multiline P4 na porta USB do Raspberry com um adaptador USB-Serial.
Após alguns ajustes no programa foi possível exibir e armazenar as leituras normalmente. :-)
Em seguida decidi modificar o programa Multipar e implementar no módulo dedicado ao instrumento Multiline P4 recursos para comunicação “cliente/servidor” para que as leituras possam ser enviadas e armazenadas em outro(s) computador(es) em uma rede (a cabo ou wireless).
O modelo cliente/servidor (em inglês client/server), é uma estrutura “modular” de aplicação que distribui as tarefas entre os fornecedores de um serviço, designados como servidores, e os requerentes dos serviços, designados como clientes. Geralmente os clientes e servidores se comunicam através de uma rede de computadores usando frequentemente o protocolo TCP, mas tanto o cliente quanto o servidor podem também estar instalados em um mesmo computador. (Fonte: Wikipedia).
O protocolo TCP é a base das redes modernas e o comando da Tcl que implementa esse protocolo é o socket, que já faz parte do núcleo do interpretador Tcl.
Soquete (socket) é um termo abstrato que representa o ponto final de uma conexão bidirecional através de uma rede. Muitas vezes usamos os termos soquete e canal (channel) de forma intercambiável, embora o termo de canal seja mais geral.
Mas é importante ressaltar que nem todo canal é um soquete, mas todo soquete é um canal. Um canal pode ser um arquivo aberto, um soquete de rede, um “pipe” ou qualquer outro tipo de canal.
Dependendo do tipo de canal, ele pode suportar comandos somente de leitura, somente de escrita ou ambos.
A abertura de um soquete implica no uso de canais e o resultado da execução do comando socket é a criação de uma conexão através do protocolo TCP (o comando socket suporta apenas o protocolo TCP) e o retorno de um identificador de canal, que pode ser usado para receber ou enviar dados através do canal recém-criado, com o uso dos comandos read ou puts.
O comando socket pode ser usado de duas formas: para criar um soquete cliente ou um soquete servidor.
Os socketes clientes servem como uma conexão aberta por um aplicativo cliente para um determinado aplicativo servidor. Mas por outro lado um soquete de servidor não se conecta, por si só, a nenhum outro aplicativo, e sua tarefa principal é “ouvir” as solicitações de conexão enviadas pelos clientes.
Essas conexões (cliente <-> servidor ) são aceitas automaticamente e um novo canal é criado para cada um (cliente e servidor), permitindo a comunicação do servidor com cada um dos diferentes clientes conectados.
Usei como ponto de partida o exemplo Simple TCP/IP to serial port gateway que é um servidor TCP funcionando como um gateway entre a porta USB e um cliente TCP.
Instalei o programa server_gateway_00.tcl
em um Raspberry Pi conectado ao medidor MultiLine P4 através de um adaptador USB-Serial.
#!/usr/bin/env tclsh set tcp_port 1901 set serial_port "/dev/ttyUSB0" socket -server serverProc $tcp_port puts "Server started and waiting for connections..." proc serverProc {channel_ID client_Address client_Port} { global serial_port fconfigure $channel_ID -blocking 0 -buffering none set serial_ID [open $serial_port r+] fconfigure $serial_ID -blocking 0 fileevent $serial_ID readable [list sendData $serial_ID $channel_ID] puts "connection accepted from $client_Address:$client_Port" puts "server socket details: [fconfigure $channel_ID -sockname]" puts "peer socket details: [fconfigure $channel_ID -peername]" puts "serial_ID: $serial_ID" } proc sendData { serial channel } { if { ![eof $serial] } { set data [gets $serial] puts $channel $data } else { puts "Serial closed" close $serial close $channel } } vwait forever
Ao executar o servidor no No Raspberry Pi pode-se acompanhar as mensagens de conexão e desconexão:
./server_gateway.tcl Server started and waiting for connections... connection accepted from 192.168.1.2:54580 server socket details: 192.168.1.3 192.168.1.3 9876 peer socket details: 192.168.1.2 192.168.1.2 54580 serial_ID: file8
E na máquina cliente temos a saída conforme a figura 177:
Figura 177. Saída no terminal das leituras do medidor Multiline P4 enviadas pelo servidor server_gateway.tcl
E quando encerramos o programa cliente o programa servidor mostra no terminal as mensagens de erro:
error writing "sock17ca208": broken pipe while executing "puts $channel $data" (procedure "sendData" line 6) invoked from within "sendData file8 sock17ca208"
Em seguida editamos o módulo wtw_multiline_p4.tcl
, no diretório multipar_04
e editamos o procedimento abrir_porta:
proc abrir_porta { nome_porta_serial } { set serverChannel [socket 192.168.1.3 1901] puts "client socket details: [fconfigure $serverChannel -sockname]" puts "peer socket details: [fconfigure $serverChannel -peername]" fconfigure $serverChannel -blocking 0 return $serverChannel }
Observei que quando o server_gateway.tcl
é executado muito antes do programa cliente, as leituras do instrumento ficam armazenadas no “buffer” de memória, e são enviadas todas de uma vez para o cliente ao se conectar.
Por isso resolvi alterar o server_gateway.tcl
para ele abrir a conexão com a porta USB somente após se conectar a um cliente.
E alterei o procedimento readClient:
proc readClient { serial client_channel } { set len [gets $client_channel request] if {($len <= 0) && [eof $client_channel]} { puts "Client from channel $client_channel disconnected" close $client_channel puts "Serial from channel $serial disconnected" close $serial } else { puts "Request from $client_channel: $request" } }
Mesmo assim o problema persistiu mas de forma irregular, ou seja, às vezes enviava lixo e outras vezes não.
E ao rodar o comando dmesg observei as seguintes mensagens de erro:
[ 3625.361069] pl2303 ttyUSB0: error sending break = -32 [ 3628.967568] pl2303 ttyUSB0: pl2303_get_line_request - failed: -32