Preciso ler bytes vindo de um equipamento de medição, já visitei vários tópicos e consegui implementar algumas classes e ler dados atravez da porta serial usando a API Javacomm e RXTXcomm, porem estou com dificuldade de interpretar os bits, acredito que seja devido a forma de leitura.
O equipamento emite um bloco de 8 bytes a cada segundo, os dados são binários, lendo da forma abaixo é correto para preencher o array de bytes?
InputStream in = serialPort.getInputStream();
byte[] buffer = new byte[8];
while ((len = this.in.read(buffer)) > -1)
Quando eu acesso as posições do array pelo metodo abaixo não confere com a especificação que tenho.
[code]
public void imprime(byte b){
int mask = 1 << 7;
for ( int bit = 1; bit <= 8; bit++ )
System.out.print(( b & mask ) == 0 ? '0' : '1');
b <<= 1;
}
[/code]
Tentei ser breve, se alguem puder me ajudar fico grato, preciso de aprender muito ainda.
Você está tratando o sincronismo?
Como você está só lendo, pode estar faltando sincronismo entre os dados enviados e que você precisa…
Tentando explicar, a porta serial é um imenso buffer e o equipamento está sempre enviando dados… digamos que na hora que você mandou ler o equipamento já estava na metade da transmissão dos dados. O seu Buffer vai estar com os dados incompletos, ai você não conseguirá trata-los da maneira correta.
Todos os equipamentos seriais utilizam algum tipo de protocólo para as mensagens enviadas (a maioria proprietário) então veja a documentação do equipamento e como funciona o envio de mensagens.
Normalmente é enviado um byte indicando o inicio e um indicando o fim da mensagem. Esses bytes não aparacem no corpo da mensagem então para saber se você recebeu o pacote inteiro você tem que ver se tem esses dois bytes no seu buffer…
Espero ter sido claro…
[quote=x@ndy]Você está tratando o sincronismo?
Como você está só lendo, pode estar faltando sincronismo entre os dados enviados e que você precisa…
Tentando explicar, a porta serial é um imenso buffer e o equipamento está sempre enviando dados… digamos que na hora que você mandou ler o equipamento já estava na metade da transmissão dos dados. O seu Buffer vai estar com os dados incompletos, ai você não conseguirá trata-los da maneira correta.
Todos os equipamentos seriais utilizam algum tipo de protocólo para as mensagens enviadas (a maioria proprietário) então veja a documentação do equipamento e como funciona o envio de mensagens.
Normalmente é enviado um byte indicando o inicio e um indicando o fim da mensagem. Esses bytes não aparacem no corpo da mensagem então para saber se você recebeu o pacote inteiro você tem que ver se tem esses dois bytes no seu buffer…
Espero ter sido claro…
[/quote]
Fala x@ndy
Obrigado pela atenção
Preciso estudar mais sobre esse buffer, assim ainda não assimilei como ele é esvaziado de acordo vou lendo.
Quando ao protocolo, a informação é a seguinte o equipamento a cada segundo cheio envia um pacote de 8 bytes, ou seja tenho 1000ms entre os pacotes, considerando o pacote esse tempo pode diminuir um pouco, e o mesmo se dá em cima dos bits ( creio eu ), por exemplo os bits 0-7 do 1 Octeto representam o LSB de uma deteminada quantidade de tempo enquanto os bits 0-3 do 2 Octeto o MSB já os bits 4-7 um determinado estado.(ativado ou desativado).
Agora o padrão da porta é RS232 está configurada para 110 bauds, 1sartbit, 8 bits de dados, 1stopbit, Sem controle de fluxo, e sem paridade.
Em relação ao sincronismo que vc citou, tem uma thread com o evento abaixo é isso ?
case SerialPortEvent.DATA_AVAILABLE:
Andei lendo uns artigos informados aqui no GUJ sobre “Java utiliza a ordenação big-endian” e no meu caso o equipamento que estou lendo utiliza little endian será que pode estar relacionado tambem a meu problema ?, tem alguma ideia de como resolver isso ?
Nessa caso você não tem sincronismo automático. É como se fosse um telefone em que um lado só fala e o outro só escuta! Agora imagina que por algum motivo quando você vai escutar a mensagem que a pessoa está falando você a pega pela metade! A mensagem fica truncada! Então a pessoa que está enviando a mensagem antes de fala-la ela diz uma frase ou palavra chave, tipo “VOU INICIAR A MENSAGEM”, ai ela fala toda mensagem e ao final ela diz “MENSAGEM TERMINADA”. As frases “VOU INICIAR A MENSAGEM” e “MENSAGEM TERMINADA” não aparecem no corpo da mensagem. Então se alguém que estiver escutando a mensagem pegar a mensagem pela metade ele a desconsidera e escuta até “VOU INICIAR A MENSAGEM”, ai ele começa a anotar a mensagem até que ele escuta “MENSAGEM TERMINADA” ai ele sabe que terminou, e fica novamente aguardando “VOU INICIAR A MENSAGEM” até a receber a próxima exemplo:
Considerando que o seu início e vim de mensagem sejam STX e ETX (01 e 02 Hexa)
então eu posso receber a seguinte mensagem pela porta serial:
GEM01ETXSTXMENSAGEM01ETX
Analisando a mensagem vemos que que a recebemos truncada podemos receber também, GEM01ETX, já que temos um tempo de leitura ou até STXMENSAG
O que é necessário fazer é tratar esses dados se você recebeu GEM01ETXSTXMENSAGEM01ETX deve varrer o vetor até encontrar o caracter STX ai sabe que inicio a mensagem e deve desconsiderar o inicio, ai você deve verificar se no restante da mensagem está contido o ETX, senão você deve aguardar o seu recebimento, entendeu?
Considerando a velocidade da transmissão e o tamanho do pacote, um byte leva cerca de 90 ms para ser transmitido, já o pacote todo (8x90=727ms), como os pacotes são transmitidos a cada 1s (1000ms) tenho aproximadamente 273ms (1000-727) entre os pacotes.
Vou ter que sincronizar com base nesse tempo 273 ms, daí leio 8 vezes e o oitavo byte é tipo um check do pacote ( complento do ou exclusivo dos outros bytes ), dessa forma da para controlar o buffer e verificar se o sincronismo está ok e se a leitura foi feita correta.
Se der certo vai faltar apenas a questão do big_endian e litte_endian, mas vou ter uma ideia melhor se a leitura tiver correta.
Aproveitando…
Será que alguem se habilita a me informar se na conversão de big_endian para litte_endian só os bytes são alterados ou regra tambem para os bits dos bytes.
por exemplo ADAD -> DADA para bytes | 11000000 -> 00000011 para bits
Considerando a velocidade da transmissão e o tamanho do pacote, um byte leva cerca de 90 ms para ser transmitido, já o pacote todo (8x90=727ms), como os pacotes são transmitidos a cada 1s (1000ms) tenho aproximadamente 273ms (1000-727) entre os pacotes.
Vou ter que sincronizar com base nesse tempo 273 ms, daí leio 8 vezes e o oitavo byte é tipo um check do pacote ( complento do ou exclusivo dos outros bytes ), dessa forma da para controlar o buffer e verificar se o sincronismo está ok e se a leitura foi feita correta. [/quote]
Um conselho, não tente sincronizar pelo tempo! Você acabará tendo problemas, pois você não tem controle total sobre o PC, se ele ficar “lento” seu sincronismo pode ir “pro saco”!
O que você deve fazer é criar um buffer maior, digamos de 24 bytes e tratar os bytes recebidos! Se a mensagem chegar truncata, você sabe que ela virá no próximo pacote…
Entendeu?
Depois de bater cabeça, resolvi testar usando C, criei um programa para simular o protocolo e utilizando portas virtuais deu tudo certo, curioso resolvi testar entre o note e CPU e não funcionou.
Li em um topico aqui no Guj no qual o conversor usb-rs232 levantava suspeita, poi eu não tenho dúvida no meu caso o conversor não está funcionando ( para esse caso ), vou entrar em contato com o fabricante e verificar se há alguma inplementação diferente na pinagem, ou tensão visto que estou usando um conversor rs232 - ttl.
Eu fiz o teste usando uma porta real (CPU) e funcionou ( em C ) , agora vou retonar para Java que é o meu objetivo no CPU é claro.
Assim que testar e resolver eu fecho o post.
Depois de bater cabeça, resolvi testar usando C, criei um programa para simular o protocolo e utilizando portas virtuais deu tudo certo, curioso resolvi testar entre o note e CPU e não funcionou.
Li em um topico aqui no Guj no qual o conversor usb-rs232 levantava suspeita, poi eu não tenho dúvida no meu caso o conversor não está funcionando ( para esse caso ), vou entrar em contato com o fabricante e verificar se há alguma inplementação diferente na pinagem, ou tensão visto que estou usando um conversor rs232 - ttl.
Eu fiz o teste usando uma porta real (CPU) e funcionou ( em C ) , agora vou retonar para Java que é o meu objetivo no CPU é claro.
Assim que testar e resolver eu fecho o post.[/quote]
Para você ter certeza de que um dispositivo não está funcionando você vai precisar ler os pacotes de alguma forma. Use um farejador na serial e compare se estão corretos, ou escreva um software em c para ler a porta usando o mesmo protocolo.
Existe uma discução aqui no guj no que se refere a portas seriais que ninguém dá o braço a torcer.
Nós sabemos que todo hardware microcontrolado(99%) usa c ou assembly. Essas duas linguagens(todas praticamente) tem o bit mais significativo diferente da java.
Se você tentar ler a serial e não contornar o problema do bit mais significativo o seu protocolo sempre vai estar furado.
[quote]
Endianness is a problem when a binary file created on a computer is read on another computer with different endianness[/quote]
Eu havia lido um outro post onde vc informou o primeiro link, e foi de grande valia, eu entendi o que vc quis dizer, e resolvi fazer os testes em C antes de prosseguir.
Mas utilizando o conversor rs-232 no notebok não dava certo.
Dai fiz o teste que deveria ter feito muito antes, verificar o padrão aplicado no conversor que apesar de ler RS232 opera com tensão de 5 volts não compatível com o equipamento que trabalha com nivel TTL de 3volts e ainda com lógica invertida, conseguia ler mas de forma errada por isso não conseguia interpretar.
Montei um conversor RS232 - TTL, e as rotinas tanto em C quanto em Java funcionaram no desktop que trabalha com RS232 , porem com a ressalva de não conseguir interpretar em Java devido a realmente a questão dos endians, mas ficou bem claro essa situação, eu favoritei o segundo link que vc enviou e vou dar uma lida com mais calma.
Esse mesmo entendimento eu consegui implementar utilizando TCP-IP, através de um conversor TCP-IP/RS232(Terminal Server) que vou utilizar junto ao equipamento enviando as informações do mesmo para rede, por isso não vou precisar quebra cabeça com o conversor USB-RS232 agora.
Resumindo eu patinei na parte física, não tinha nada haver com a linguagem.
Vc tem razão a solução é simples mesmo.
Obrigado a vc e ao x@ndy , que disponibilizaram tempo em me ajudar.
[code] Byte octeto0 = 64 // (Representação binária 01000000 ) ( LSB do numero x )
Byte octeto1 = 2 //(Representação binária 00000010) (bits 0,1e 2 MSB do numero x , o restante dos bits representa outras informações)
int x = ((int) (octeto1 & 0x07))<<8) | (int)(octeto0 & 0xff);
// x = 576 (Representação binária 1001000000 ) [/code]