Performance na escrita utilizando Rxtxcomm

31 respostas
laudenpower

Boa tarde,

Gostaria de saber se alguém já conseguiu utilizar o rxtxcomm para enviar dados (118 caracteres) pela porta serial em tempo menor que 10ms.
Preciso me comunicar em uma rede rs-485 e para não ter problemas no processamento do protocolo do dispositivo preciso escrever extretamente rápido, porém o melhor tempo que eu consegui foi de 11ms utilizando o OutputStreamWriter. Nesse caso estou notando que perco tempo quando eu chamo o método flush da classe (se não chamo ele os dados não chegam ao outro lado da comunicação).

Desde já agradeço a todos pela atenção.

31 Respostas

E

Qual é a baud rate que você usa? 118 caracteres (118 * 10 bits), a 4800 baud, deve dar 250 milissegundos. Bem mais que os 10 ms que você citou.

laudenpower

Opa! foi mal esqueci de dar a configuração utilizada na porta serial.
A porta está configurada para:
-Baud: 57600
-Paridade: none
-DataBit: 8
-StopBit: 1
-Controle de fluxo: None

Tava pensando em utilizar o java.nio para tentar otimizar esse tempo.
Alias além do rxtxcomm você conhece mais alguma outra api serial (que não seja a finada java.comm e a giovynet).

E

Fazendo as contas ainda não está batendo.

Você quer mandar 118 caracteres (1062 bits, já que você tem 1 stop bit e 8 bits de dados - eu tinha feito a conta de 10 bits porque supunha que você poderia usar 2 stop bits), e isso a 57600 baud dá 18,3 milissegundos - você disse 11, tem alguma coisa errada nessa história aí.

E

Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

laudenpower

Pera, tais certo. Eu fiz a medição errada…
Para enviar 73 caracteres eu levo 11ms não 118 como eu havia dito. Nesse caso eu pensei no java.nio por estar ficando sem opção, mas agora depois de ler alguns materiais eu vi que não serve para o meu caso.
Tipo a situação em que eu me encontro é uma rede rs-485 onde o servidor realiza uma comunicação com o dispositivo (e mais outros 4) com um intervalo minimo de 20ms entre uma comunicação e outra. Dessa forma a minha comunicação deve chegar ao servidor antes dele iniciar a comunicação com o próximo dispositivo. Se isso acontecer o protocolo não é respeitado e o software não funciona.

J

entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

laudenpower

juliocbq:
entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

Pois é, minha ficha já caiu.
Agora tenho que achar uma forma de melhorar esse tempo. Já tivesse que fazer algo assim?

J

laudenpower:
juliocbq:
entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

Pois é, minha ficha já caiu.
Agora tenho que achar uma forma de melhorar esse tempo. Já tivesse que fazer algo assim?

Não há muito o que fazer, porque o dispositivo com o qual você vai se comunicar é quem vai ditar a taxa de transferência de bits.
Agora se o hardware é projeto seu ae você pode configurar a taxa que achar melhor.

laudenpower

juliocbq:
laudenpower:
juliocbq:
entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

Pois é, minha ficha já caiu.
Agora tenho que achar uma forma de melhorar esse tempo. Já tivesse que fazer algo assim?

Não há muito o que fazer, porque o dispositivo com o qual você vai se comunicar é quem vai ditar a taxa de transferência de bits.
Agora se o hardware é projeto seu ae você pode configurar a taxa que achar melhor.

Mas nesse caso, existe alguma forma de eu baixar o tempo de escrita? Pelo que eu andei vendo o servidor foi desenvolvido em VB, nesse caso acho que a manipulação de porta serial deve ser muito mais apurada pelo fato de ser algo que já além de rodar nativo ainda tem a vantagem de utilizar o SO de uma maneira melhor para escrever na porta.

J

laudenpower:
juliocbq:
laudenpower:
juliocbq:
entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

Pois é, minha ficha já caiu.
Agora tenho que achar uma forma de melhorar esse tempo. Já tivesse que fazer algo assim?

Não há muito o que fazer, porque o dispositivo com o qual você vai se comunicar é quem vai ditar a taxa de transferência de bits.
Agora se o hardware é projeto seu ae você pode configurar a taxa que achar melhor.

Mas nesse caso, existe alguma forma de eu baixar o tempo de escrita? Pelo que eu andei vendo o servidor foi desenvolvido em VB, nesse caso acho que a manipulação de porta serial deve ser muito mais apurada pelo fato de ser algo que já além de rodar nativo ainda tem a vantagem de utilizar o SO de uma maneira melhor para escrever na porta.

Deixa eu entender uma coisa primeiro.

Você está usando rs232 para comunicação(porta serial)?
O servidor que você está dizendo é uma máquina na rede ou um hardware específico?
Essa comunicação é pela rede?

laudenpower

juliocbq:
laudenpower:
juliocbq:
laudenpower:
juliocbq:
entanglement:
Mais uma coisinha - como você iria usar java.nio nisso? Não consigo entender. rxtx não lida com a interface serial como se fosse um arquivo em disco ou um socket, que são as formas que são tratadas por java.nio

E outra, o código java por melhor ou pior que seja não vai influenciar na velocidade. A biblioteca rxtx é “nativa”, ou seja quem manda é ela.

Pois é, minha ficha já caiu.
Agora tenho que achar uma forma de melhorar esse tempo. Já tivesse que fazer algo assim?

Não há muito o que fazer, porque o dispositivo com o qual você vai se comunicar é quem vai ditar a taxa de transferência de bits.
Agora se o hardware é projeto seu ae você pode configurar a taxa que achar melhor.

Mas nesse caso, existe alguma forma de eu baixar o tempo de escrita? Pelo que eu andei vendo o servidor foi desenvolvido em VB, nesse caso acho que a manipulação de porta serial deve ser muito mais apurada pelo fato de ser algo que já além de rodar nativo ainda tem a vantagem de utilizar o SO de uma maneira melhor para escrever na porta.

Deixa eu entender uma coisa primeiro.

Você está usando rs232 para comunicação(porta serial)?
O servidor que você está dizendo é uma máquina na rede ou um hardware específico?

Sim estou usando rs232 em um barramento rs485 (nesse caso muda o padrão elétrico, mas ta valendo). O servidor é um aplicativo feito em VB que fica realizando uma comunicação (query) em cada dispositivo do barramento (são 5) verificando se ocorreu algum evento (pressionamento de um botão por exemplo). Meu objetivo é tomar o lugar de um desses dispositivos (que são hardwares específicos) e agir como se fosse um deles emulando exatamente o protocolo que o dispositivo real utiliza. O protocolo já foi “desvendado” utilizando um sniffer de porta serial, mas agora falta sincronizar a troca de comunicação, sendo que nesse caso se eu comunicar na vez de outro dispositivo da rede o processo de comunicação não acontece.

E

RS-485 serve para criar uma espécie de rede industrial via interface serial. É realmente meio tosco - veja http://en.wikipedia.org/wiki/EIA-485 - e cada sistema normalmente tem de definir como é que um computador fala com os outros, via half-duplex. Normalmente você tem um computador central, que fala com vários dispositivos.

laudenpower

Realmente, o negócio é bem tosco mesmo, mas nesse caso esse é o primeiro passo de migração desse sistema. Tipo eu tava precisando gastar o mínimo de tempo possível para não ter problemas na comunicação do outro dispositivo, sendo que já enxuguei tudo que podia no software e só falta isso. Tipo tava medindo e para realizar a leitura de um bloco de 97 caracteres levo menos de 10ms mas a escrita de 73 caracteres ferra tudo, pois leva 11 ms. Pelo tanto de coisa que eu já tentei to ficando sem opção. E tem mais uma tipo não é sempre que eu estoro o tempo de escrita na maioria das vezes eu consigo escrever no tempo certo.

E

Se você puser um osciloscópio na linha, provavelmente vai ver que deve haver um intervalo significativo entre o tempo em que você recebe a mensagem do servidor e o tempo em que os bytes são jogados no fio. Se isso estiver ocorrendo, não adianta você se preocupar com rxtx, e sim com o tempo de processamento da mensagem em si.

Estou chutando que você está é com problemas para receber a mensagem, não para mandá-la. Se for isso, provavelmente você terá de ver como é que se recebe algo via rxtx e isso não fique “muito” bufferizado.

laudenpower

Nesse caso estou utilizando a estratégia de receber os dados por meio de eventos (que é algo que o java.comm fazia), nesse caso eu teria algum ganho se eu lesse direto no inputStream em uma thread separada? Tipo com relação a leitura das mensagens eu já medi o processamento e não passa de 5 ms…

laudenpower

Nesse caso você está sugerindo que eu devo utilizar alguma outra forma de ler os dados da porta serial?

J

entanglement:
Se você puser um osciloscópio na linha, provavelmente vai ver que deve haver um intervalo significativo entre o tempo em que você recebe a mensagem do servidor e o tempo em que os bytes são jogados no fio. Se isso estiver ocorrendo, não adianta você se preocupar com rxtx, e sim com o tempo de processamento da mensagem em si.

Estou chutando que você está é com problemas para receber a mensagem, não para mandá-la. Se for isso, provavelmente você terá de ver como é que se recebe algo via rxtx e isso não fique “muito” bufferizado.

Desculpem a demora.
O seu problema não é só a velocidade de transmissão. O protocolo cuida de montar a mensagem, enviá-la e recebêl-a. O problema pode estar na sequência de bits que você envia e recebe.

Eu trabalho com microcontroladores e sei bem o que é fazer um programa java conversar com um micro(hardware normalmente programado em c ou assembly). Isso se deve porque primeiro um byte em c é um valor não sinalizado, enquanto que no java é sinalizado.

A sequencia de bits em java é big endian enquanto em c é little endian.

Dá uma lida aqui, estes links podem te ajudar.

http://pt.w3support.net/index.php?db=so&id=362384

conversão de tipos sinalizados para não sinalizados e vice versa. Você terá que fazer isso também

http://www.darksleep.com/player/JavaAndUnsignedTypes.html

Detalhe, isso vale para linguagens como vb, c, c++ etc…

laudenpower

Mas nesse caso eu recebo caracter por caracter na porta serial e depois monto a mensagem. Quando falei de protocolo estava me referindo a isso.
Eu estava lendo o passado material mas não cheguei a entender qual a diferença entre trocar tipos sinalizados no java com tipos não sinalizados em C. Outro detalhe que deixei de dizer é que para conseguir enviar caracteres da tabela asc pelo outputStream eu embrulhei em um outputStreamWriter, pois se eu enviasse pelo output “normal” ele ao enviar os caracteres acima de 127 acabava enviando o caracter correspondente só que negativo.
Será que esse encapsulamento de objetos pode estar afetando a performance?

J

laudenpower:
Mas nesse caso eu recebo caracter por caracter na porta serial e depois monto a mensagem. Quando falei de protocolo estava me referindo a isso.
Eu estava lendo o passado material mas não cheguei a entender qual a diferença entre trocar tipos sinalizados no java com tipos não sinalizados em C. Outro detalhe que deixei de dizer é que para conseguir enviar caracteres da tabela asc pelo outputStream eu embrulhei em um outputStreamWriter, pois se eu enviasse pelo output “normal” ele ao enviar os caracteres acima de 127 acabava enviando o caracter correspondente só que negativo.
Será que esse encapsulamento de objetos pode estar afetando a performance?

A questão não é o encapsulamento e nem o desempenho. Você não pode conversar uma sequencia de bits big endian com alguém que entenda little endian. Você me disse que o objetivo do seu software era substituir os dispositivos que se encontravam ligados ao servidor. Esses dispositivos são hardwares escritos em c(little endian).

Seu software Java entende bigendian ou seja, a seqüência de bits onde o primeiro bit é o mais importante. Completamente o contrário do outro. Desse jeito você nunca vai conseguir escrever ou ler do servidor, entendeu?

O servidor muda o protocolo e te envia bigendian, ou você adapta seu software java para littleendian. O que está descrito no link que te passei.

laudenpower

Me desculpa a minha ignorância mas não entendi :frowning:

Tipo eu quando vejo o sniffer serial ele mostra todos os caracteres passando pela porta serial sem nenhum tipo de interferência e como eu já disse eu consigo enviar as mensagens para o servidor e o mesmo entende e inicia o processo. O que está acontecendo é que em algumas vezes eu mando a mensagem no meu turno mas ela só chega no servidor no turno do outro dispositivo, fazendo dessa forma o meu simulador se perder no processo.
Pelo o que você me disse se eu estivesse utilizando big endian onde deve ser utilizado little endian o servidor sequer me responderia certo?

Cara mesmo sem termos chegado a uma solução já quero te agradecer muito pela ajuda dada, tais me quebrando um galhão. Valeu mesmo :slight_smile:

J

laudenpower:
Me desculpa a minha ignorância mas não entendi :frowning:

Tipo eu quando vejo o sniffer serial ele mostra todos os caracteres passando pela porta serial sem nenhum tipo de interferência e como eu já disse eu consigo enviar as mensagens para o servidor e o mesmo entende e inicia o processo. O que está acontecendo é que em algumas vezes eu mando a mensagem no meu turno mas ela só chega no servidor no turno do outro dispositivo, fazendo dessa forma o meu simulador se perder no processo.
Pelo o que você me disse se eu estivesse utilizando big endian onde deve ser utilizado little endian o servidor sequer me responderia certo?

Cara mesmo sem termos chegado a uma solução já quero te agradecer muito pela ajuda dada, tais me quebrando um galhão. Valeu mesmo :)

Não necessáriamente não hà comunicação. A comunicação fica atrapalhada, pois o protocolo não entende quando iniciar a transmissão ou quando terminá-la. Isso é um problema comum com java e hardware.
Como seu servidor conversava com hardware, pode ter certeza que é sequencia de bits este problema. Isso diz respeito em como o java ou outra linguagem de baixo nível analiza um byte.
Dá uma estudada nisso ae.

Sem problemas.

laudenpower

Tipo eu li, li e reli e ainda não me passou…
Se eu converter a mensagem para utilizar o little endian isso não vai modificar a representação do caracter?
Por que pelo que eu entendi, a porta serial envia caracteres com representação decimal pelo meio de comunicação (pelo menos é isso que eu vejo no sniffer) logo todo char que eu envio na porta antes é convertido em decimal para depois ser enviado, certo?
Teria como me dar um exemplo dessa conversão de big para little endian?

laudenpower

Outra coisa que esqueci de relatar é que estou utilizando um adptador usb -> rs485. Esse tipo de cabo interfere na performance de comunicação?

J

Pode interferir se ele for muito extenso. Isso pode fazer você perder pacotes.
Voltando ao assunto de big endian e l endian, o problema vai acontecer quando o seu programa java for ler os pacotes com essa estrutura de bytes.
Digamos que a leitura de um byte em um programa java começa pelo bit mais significativo que é o da esquerda, em contra partida o l endian entende como bit mais significativo o da diteita. Essa inversão é o que causa o problema e confunde o protocolo dew comunicação.

Olha, achei um artigo na wiki muito bom e na nossa língua nativa:

http://pt.wikipedia.org/wiki/Extremidade_(ordena%C3%A7%C3%A3o)

laudenpower

Li o material que você mandou, mas ainda não consigo visualizar como uma coisa dessa (a inversão dos bits) não coloca todo a comunicação a perder, sendo que nesse caso ela apenas ocasiona o problema uma vez entre várias vezes.
Outra coisa que não entendi é o esquema de conversão tipo eu tenho que enviar 100 bytes (nesse caso tenho que mandar char’s para representar a tabela asc) tenho que converter caracter por caracter? Pergunto isso por que eu posso escolher o encode quando eu manipulo o OutputStreamWriter e nesse caso tem os encodes que utilizam BigEndian e LittleEndian mas eles mandam 2 bytes na porta serial ao invés de 1 como estava sendo enviado antes.

Essa parte de conversão de bits é realmente complicada para mim por que apesar de estar lendo o material que você está cedendo ta faltando contextualizar isso de alguma forma entende?

J

laudenpower:
Li o material que você mandou, mas ainda não consigo visualizar como uma coisa dessa (a inversão dos bits) não coloca todo a comunicação a perder, sendo que nesse caso ela apenas ocasiona o problema uma vez entre várias vezes.
Outra coisa que não entendi é o esquema de conversão tipo eu tenho que enviar 100 bytes (nesse caso tenho que mandar char’s para representar a tabela asc) tenho que converter caracter por caracter? Pergunto isso por que eu posso escolher o encode quando eu manipulo o OutputStreamWriter e nesse caso tem os encodes que utilizam BigEndian e LittleEndian mas eles mandam 2 bytes na porta serial ao invés de 1 como estava sendo enviado antes.

Essa parte de conversão de bits é realmente complicada para mim por que apesar de estar lendo o material que você está cedendo ta faltando contextualizar isso de alguma forma entende?

Sim,

Eu quero dizer que vai afetar na comunicação, ou seja quando esse pacote chegar na aplicação. Na porta de comunicação(serial) é indiferente.
Quando seu programa ler o byte vai ler de forma errônea, influenciando posteriormente no tempo de leitura(caso o software esteja esperando um bit específico para iniciar, ou até mesmo terminar a comunicação).

Um exemplo é uma leitora de mesa. Passamos o cartão magnético, enquanto nosso software aguarda um bit específico para ler o restante da sequencia(dito trem de bit). De acordo com o protocolo, os 2 primeiros bits com valor 10 iniciam a transmissão e os 2 últimos 00 terminam a transmissão. Entre eles estão as informações referentes a comunicação. Pela inversão algumas vezes líamos valores picados pois o protocolo achava que valores intermediários (10 ) indicavam o início da transmissão.

No seu caso, a inversão ocasiona a leitura tardia, pois o seu software, ou então o servidor do outro lado esperam pelo início da comunicação. A diferença no tempo pode estar ae.

Imagine dessa maneira -

Em 1ms enviei 3 requisições, e meu servidor(ou cliente) recebeu apenas 1(por acaso simplesmente porque os bytes recebidos combinam com o “início-transmissão”). Lembrando que não tem nada haver com rxtx(isso já é o hardware), mas com o java e o c(ou qualquer outra linguagem l endian) e a maneira como interpretam os seus bytes.

Você precisa saber como o servidor e a sua aplicação estão interpretando a troca de mensagens. Isso pode ser feito imprimindo todos os valores do pacote e comparando-os. Lembrando, comparando os tempos da transmissão.

laudenpower

Nesse caso o protocolo tem como inicio os caracteres (em hexa) 10 02 e termina com 3 caracteres (em hexa) 10 03 CRC(nesse caso um byte) em nenhum comando existe esses caracteres no meio entende? Tipo poderia sair picado sim mas para isso teriamos um caracter de fim ou de inicio no meio da mensagem. E como eu leio um a um eu sei que após a chegada do caracter 03 (final) o próximo que chega é o CRC para depois começar tudo de novo (10 02 … 10 03 CRC). Nesse caso já imprimi os pacotes e é isso o que vem do servidor, que bate com o que o sniffer ta mostrando entende?

J

Entendi, o problema pode estar então mais acima, a nivel de aplicação mesmo. Melhor revisar o código.
Só uma coisa, se o server conversa little endian, obrigatóriamente você terá de converter os valores no seu programa java, mesmo que o problema não seja esse.

laudenpower

Entendi, o problema pode estar então mais acima, a nivel de aplicação mesmo. Melhor revisar o código.
Só uma coisa, se o server conversa little endian, obrigatóriamente você terá de converter os valores no seu programa java, mesmo que o problema não seja esse.

Mas nesse caso como eu saberia que o servidor conversa little endian?
Existe alguma forma de confirmar isso pelo sniffer?
Alias o entanglement realizou um calculo para saber o tempo de envio da mensagem pela porta serial. Você sabe realizar esse calculo?

laudenpower

Eu andei pesquisando um bocado e acabei achando o nome do driver usado pelo conversor adaptador USB <-> rs485. O driver do fabricante é o Silabs, nesse caso alguém já teve problemas de performance com esse driver? Eu estou usando a versão 5.4.
Outra coisa que eu gostaria de entender é como esses adaptadores funcionam.

Desde já agradeço a atenção de todos.

:slight_smile:

laudenpower

up

Criado 28 de outubro de 2010
Ultima resposta 8 de nov. de 2010
Respostas 31
Participantes 3