[Resolvido] Leitura de bytes e interpretação de bits

Pessoal,

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?

Caminhei um pouco mais.

Quanto a questão do sincronismo vc tinha razão.

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

[quote=rdn]Caminhei um pouco mais.

Quanto a questão do sincronismo vc tinha razão.

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?

aff

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=rdn]aff

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]


http://mindprod.com/jgloss/endian.html

Posso estar enganado, mas existém tópicos aqui que talvez nunca vejamos a solução porque ninguém tratou uma solução simples como essa.

Fala,

juliocbq

Obrigado pelas informações.

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.

Para deixar registrado e marcar como resolvido

[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]