Comunicacao Serial - Desempenho

Olá Pessoal…

é o seguinte, estou utilizando comunicacao serial para comunicar entre o pc e um microntrolador, montei um protocologo que sempre que o mc manda os dados para o pc o pc retorna para o mc configuracoes ou sem dado.

O problema é que preciso de muito agilidade nos dados do mC para o PC e não to conseguindo…
Poruqe eu sempre estou gerando um atraso após mandar os dados para o pc porque parece que a api não le o buffer corretamente se não gerar um tempo.

o que quero saber é se a api tem essa limitação msm de velocidade entre as chegadas de buffers…

obrigado.

Vlw

existe um tempo de atraso, mas é coisa de milessegundos.

O legal é você implementar um protocolo que o pc fique interrogando a placa.

quanto tempo seria este atraso?

respondendo melhor tua pergunta:

eu uso rxtx, e não tem nenhum delay que seja relevante e me incomode!

Então o atraso minimo que tenho q esperar para transmitir um buffer e outro para o pc que eu consegui foi de aproximadamente 0,075s porém isso ainda é muito…

Como funciona esse rxtx?

Obrigado.

Um Abraço

creio que o tempo de comunicação possa variar, nesse tempo acho dificil funcionar.
como esta seu timeout?

o link abaixo vai lhe ajudar com a API rxtx

http://www.devmedia.com.br/articles/viewcomp.asp?comp=6722

Verifique se:

  1. Seu cabo serial está em bom estado;
  2. Se a sua taxa de transferência é alta (superior a 2400);
  3. Se não é a sua aplicação que está atrasando (é uma boa baixar o serialmon).

Olá

Na comunicação serial, fazer pooling não costuma ser legal porque se pode perder bytes. O ideal seria aproveitar as interrupções do PC. Era muito fácil fazer isto em assembler e em C no tempo do DOS mas agora o acesso direto às interrupções do Hardware precisam usar algumas coisas de baixo nível das APIs do Windows. No momento não estou lembrado se a API javax.comm faz assim.

Mas usando os eventos do Java se pode fazer mais ou menos assim como mostra o capítulo 11 da primeira edição do livro Java Cookbook que você pode baixar em http://java.sun.com/developer/Books/javaprogramming/cookbook/11.pdf

Não deixe de ler este capítulo.

Você pode baixar os códigos fonte da 1a edição do livro e encontrará os mesmos exemplos porém o código abaixo foi tirado do site do livro Java Cookbook 2a Edição (capítulo 12) em http://javacook.darwinsys.com/download.html:

import java.io.IOException;
import java.util.TooManyListenersException;

import javax.comm.NoSuchPortException;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
import javax.swing.JFrame;

/**
 * Read from a Serial port, notifying when data arrives.
 * Simulation of part of an event-logging service.
 * @version $Id: SerialReadByEvents.java,v 1.4 2004/04/11 23:50:40 ian Exp $
 * @author	Ian F. Darwin, http://www.darwinsys.com/
 */
public class SerialReadByEvents extends CommPortOpen 
	implements SerialPortEventListener {

	public static void main(String[] argv)
		throws IOException, NoSuchPortException, PortInUseException,
			UnsupportedCommOperationException {

		new SerialReadByEvents(null).converse();
	}

	/* Constructor */
	public SerialReadByEvents(JFrame f)
		throws IOException, NoSuchPortException, PortInUseException,
			UnsupportedCommOperationException {
		
		super(f);
	}

	/** 
	 * Hold the conversation. 
	 */
	protected void converse() throws IOException {

		if (!(thePort instanceof SerialPort)) {
			System.err.println("But I wanted a SERIAL port!");
			System.exit(1);
		}
		// Tell the Comm API that we want serial events.
		((SerialPort)thePort).notifyOnDataAvailable(true);
		try {
			((SerialPort)thePort).addEventListener(this);
		} catch (TooManyListenersException ev) {
			// "CantHappen" error
			System.err.println("Too many listeners(!) " + ev);
			System.exit(0);
		}
	
		
	}
	public void serialEvent(SerialPortEvent ev) {
		String line;
		try {
			line = is.readLine();
			if (line == null) {
				System.out.println("EOF on serial port.");
				System.exit(0);
			}
			os.println(line);
		} catch (IOException ex) {
			System.err.println("IO Error " + ex);
		}
	}
}

Abaixo um programa que lê de uma das portas seriais sempre que um dado chega. Poderia ser um exemplo de um sistema de alarme monitorando várias dispositivos remotos e escrevendo um log central. Mais explicações no PDF citado.

import java.io.*;
import javax.comm.*;
import java.util.*;

/**
 * Read from multiple Serial ports, notifying when data arrives on any.
 * @version $Id: SerialLogger.java,v 1.4 2004/03/11 04:09:14 ian Exp $
 * @author	Ian F. Darwin, http://www.darwinsys.com/
 */
public class SerialLogger {

	public static void main(String[] argv)
		throws IOException, NoSuchPortException, PortInUseException,
			UnsupportedCommOperationException {

		new SerialLogger();
	}

	/* Constructor */
	public SerialLogger()
		throws IOException, NoSuchPortException, PortInUseException,
			UnsupportedCommOperationException {
		
		// get list of ports available on this particular computer,
		// by calling static method in CommPortIdentifier.
		Enumeration pList = CommPortIdentifier.getPortIdentifiers();

		// Process the list, processing only serial ports.
		while (pList.hasMoreElements()) {
			CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement();
			String name = cpi.getName();
			System.out.print("Port " + name + " ");
			if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				System.out.println("is a Serial Port: " + cpi);

				SerialPort thePort;
				try {
					thePort = (SerialPort)cpi.open("Logger", 1000);
				} catch (PortInUseException ev) {
					System.err.println("Port in use: " + name);
					continue;
				}

				// Tell the Comm API that we want serial events.
				thePort.notifyOnDataAvailable(true);
				try {
					thePort.addEventListener(new Logger(cpi.getName(), thePort));
				} catch (TooManyListenersException ev) {
					// "CantHappen" error
					System.err.println("Too many listeners(!) " + ev);
					System.exit(0);
				}
			}
		}
	}

	/** Handle one port. */
	public class Logger implements SerialPortEventListener { 
		String portName;
		SerialPort thePort;
		BufferedReader ifile;
		public Logger(String name, SerialPort port) throws IOException {
			portName = name;
			thePort = port;
			// Make a reader for the input file.
			ifile = new BufferedReader(
				new InputStreamReader(thePort.getInputStream()));
		}
		public void serialEvent(SerialPortEvent ev) {
			String line;
			try {
				line = ifile.readLine();
				if (line == null) {
					System.out.println("EOF on serial port.");
					System.exit(0);
				}
				System.out.println(portName + ": " + line);
			} catch (IOException ex) {
				System.err.println("IO Error " + ex);
			}
		}
	}
}

Se você baixar os exemplos do link que citei, pode ver um outro exempo que usa Threads de nome CommPortThreaded.java

Não deixe de estudar também os exemplos JModem.java e TModem.java que são programas simples de troca de dados pela porta serial mas muito instrutivos.

[]s
Luca (que há muitos e muitos anos não mexe com isto)

[quote]
Na comunicação serial, fazer pooling não costuma ser legal porque se pode perder bytes.[/quote]

exemplo, preciso conversar com 500 placas?
a unica solução eficiente que encontrei com o java foi essa, interrogar as placas de tempo em tempo.

Utilizo checksum para validar a comunicação!
a uma distancia de quase 1 km usando rs485 raramente discarto um mensagem.

nosso protocolo é utilizado em catracas do Beto Carreiro, Parque do gugu, e outro varios lugares, e é eficiente!
agora me interessei em descobrir o porque das perdas de bytes que o Luca citou utilizando pooling?!

Olá

[quote=securitynews]exemplo, preciso conversar com 500 placas?
a unica solução eficiente que encontrei com o java foi essa, interrogar as placas de tempo em tempo.

Utilizo checksum para validar a comunicação!
a uma distancia de quase 1 km usando rs485 raramente discarto um mensagem.

nosso protocolo é utilizado em catracas do Beto Carreiro, Parque do gugu, e outro varios lugares, e é eficiente!
agora me interessei em descobrir o porque das perdas de bytes que o Luca citou utilizando pooling?![/quote]

Há muitos anos atrás, ainda no tempo do DOS, a gente usava Laplink que era um programa muito rápido para fazer transferência serial entre PCs. Naquele tempo ainda não havia redes TCP/IP e nem mesmo o Windows for Workgroups havia sido lançado com aquele protocolo de rede proprietário da Microsoft. A gente fazia transferências entre PCs usando cabo serial e quando disponível, cabo paralelo.

Neste tempo, fiz um programa de transferência serial de arquivos que funcionava como o Laplink mas que tinha a opção de comprimir os dados de arquivos grandes antes de transmitir. Precisava do máximo de velocidade possível.

A gente programava direto mexendo mais próximo do hardware possível. Na época a gente entendia que quando se fazia polling para verificar se estavam chegando novos bytes, o programa precisava parar enquanto esperava e a gente precisava otimizar o uso dos clocks da CPU para fazer coisa tais como por exemplo calcular ou verificar o CRC (não acreditava em cheksum para transferir arquivos) ou mover os bytes que chegavam para algum buffer.

Na verdade o Joe Campbell, um dos mais conhecidos autores de livros sobre comunicação serial, autor do clássico C Programmer’s Guide to Serial Communications, ensinava como fazer mas desaconselhava o uso das interrupções devido a excessiva proximidade com o hardware. Mas na época o bom era ser escovador de bits e meu programinha (quase todo em Assembler) se metia nas profundezas do inferno como outros autores como por exemplo o Mark Nelson recomendava no Serial Communications: A C++ Developer’s Guide. Um dos livros que tenho, de autoria do Peter Gofton, compara o uso de pooling e interrupções com um telefone sem campainha com o qual você precisaria a toda hora tirar do gancho para ver se tem novas ligações e outro com campainha alertando para novas ligações. Palavras dele: “I strongly recommend that you use interrupts whenever possible.”

Sobre a questão da possibilidade de perder bytes quando se faz pooling a explicação é muito simples mas para entender é preciso lembrar que antigamente os computadores eram mais lerdos e o sistema operacional DOS não era multi tarefa. Pooling significa de vez em quando perguntar a porta se chegou um byte e se chegou, fazer alguma coisa com ele. Este fazer alguma coisa com ele é que podia demorar mais do que a chegada do próximo byte e a nova consulta a porta.

No meu problema era usado o RS232 programando diretamente na UART e usando DOS em que isto era possível facilmente. A solução era do tipo de http://www.beyondlogic.org/serial/serial1.htm#30 que também fala da questão de pooling x interrupts.

Pensando melhor no problema e no hardware atual com os atuais sistemas operacionais multi tarefa, talvez não seja necessário ir tão fundo, principalmente para se comunicar com dispositivos relativamente lentos como leitoras de cartões, etc. Na época a gente queria transmitir com o máximo baud possível (115200 bps).

Vi agora em http://www.cic.unb.br/~bordim/TD/Arquivos/G10_Monografia.pdf uma comparação do RS232 com o RS485 e percebi enormes diferenças. Não conheço a RS485 e não sei dizer se seria possível obter vantagens usando interrupções. Se fosse o caso, provavelmente precisaria no Windows de um device driver do tipo do PortTalk de http://www.beyondlogic.org/porttalk/porttalk.htm ou algum outro se fosse no Linux. Mas se funciona bem tal como está então não se mexe.

Espero ter explicado apesar de que pode ter ficado meio confuso por ter editado várias vezes.

[]s
Luca

Olá

[quote=securitynews]o link abaixo vai lhe ajudar com a API rxtx

http://www.devmedia.com.br/articles/viewcomp.asp?comp=6722
[/quote]

Muito bom este link. Pelo que me lembro, a RXTX resolve algumas limitações da javax.comm como a questão de acessar a porta paralela que no javax.comm é um problema.

[]s
Luca

Boa noite pessoal.

Eu ia postar um assunto novo, mas acho que aqui podem me ajudar.
Meu problema é o seguinte:
Estava usando a API JavaComm pra implementar uma aplicação que comunicasse via porta serial; desisti pelo fato de não consegui configurar a porta com baud rate não padrão (10400, 8900 por exemplo); testo agora a RXTX que não gera erro de compilação quando tento configurar com baud não padrão, no entanto quando rodo a aplicação, ela assume a velocidade de 9600 bauds (só com baud não padrão). Tive lendo um monte de assuntos referentes a isso e muitos citam o uso de JNI, pelo fato de se poder acessar funções do SO que não são suportadas pela VM do java.
Mas parece que pelo que entendi, o uso de JNI fica preso a um determinado SO. Alguém tem alguma dica pra me dar? Será que existe uma maneira mais fácil pra comunicar serial com java?

Um forte abraço a todos, e muito obrigado.

Olá

Seria importante para quem vai googlar e tentar ajudá-lo, saber mais detalhes como por exemplo o que e onde vai usar. Se for via RS232 o baud rate é definido por um divisor do clock (1.8432 MHz) e você teria que colocar nos registros DLM e DLL algo que redundasse em um divisor que correspondesse ao baud que necessita. Provavelmente isto precisaria ser feito em baixo nível usando C e acessando do Java via JNI. Precisaria fazer uma solução para Linux e outra para Windows.

[]s
Luca

Bom dia Luca.

Esta será uma aplicação automotiva, pra comunicar com o módulo controlador do motor via RS232, pelo menos é o que eu vou tentar. Pelos artigos que andei lendo, parece não ser uma coisa muito fácil, mas eu to tentando.
A todos : sintam-se à vontade pra dar dicas e conselhos.

Obrigado.

Olá

Então é como eu escrevi: você precisará colocar em 2 bytes especiais, o divisor do clock que dará o baud que você quer. E para fazer isto, não vejo outro meio a não ser usar algo que consiga acessar o hardware diretamente. Precisará de C ou Assembler e ainda de um device driver que para sua sorte existe por aí. O site BeyondLogic que indiquei é um bom começo e talvez o porttalk sirva.

A sua sorte é que há muita documentação sobre RS232 e até chances de encontrar algo pronto. Outra sorte é que JNI é muito fácil de usar desde que você conheçe um tiquinho de C (bem menos que o necessário para usar ou fazer o tal device driver).

Se sua aplicação roda em vários sistemas operacionais, será necessário acessar o hardware de forma diferente para cada um deles.

[]s
Luca

De fato, o Windows só permite o uso de baud rates padrão; é preciso programar diretamente o INS16550 (ou chip equivalente) pondo os valores nos registradores apontados.

Não se esquecer que o INS16550 tem uma fila de entrada de bytes de 8 ou 16 bytes (não lembro quanto), e por default, o Windows usa essa fila e só dispara interrupções quando essa fila está cheia ou quando transcorreu algum tempo (não sei exatamente quanto). Isso é bem adequado se você vai usar um terminal serial, mas pode não ser adequado para outras aplicações.

Bom pessoal,

To seguindo passa a passo um tutorial da Sun sobre JNI, tambem baixei uma apostila do site que o Luca indicou.
Seguindo as instruções do tutorial da sun, me enrosquei aqui (anexo), parece que o classpath, mas eu não consegui.

Grato

[quote=Edifran]Bom pessoal,

To seguindo passa a passo um tutorial da Sun sobre JNI, tambem baixei uma apostila do site que o Luca indicou.
Seguindo as instruções do tutorial da sun, me enrosquei aqui (anexo), parece que o classpath, mas eu não consegui.

Grato[/quote]

em vez de utilizar o JNI diretamente, você pode facilitar sua vida ( e a nossa :D) utilizando bibliotecas como NLink.

Pessoal…
de boa… :frowning:

Parece que o problema que estou tendo com o javah é o classpath mesmo, mas eu não to conseguindo entender muito bem isso.

1- É uma variável de ambiente que tenho que criar?
2- É o caminho do jdk que tenho que por como valor desta varivel?

Eu olhei um tanto de exemplo, mas to meio confuso :oops: , se alguem puder me ajudar…

Valeu galera…

Boa tarde pessoal.

Alguma outra sugestão pra solução do meu problema?
To dando meus pulos aki, mas ainda sem sucesso.

Obrigado

Olá

[quote=Edifran]Boa tarde pessoal.

Alguma outra sugestão pra solução do meu problema?
To dando meus pulos aki, mas ainda sem sucesso.

Obrigado
[/quote]

Não adianta fazer up na mensagem. Busque nos tutoriais do GUJ, nas apostilas básicas da Caelum, no Google e encontrará farto material resolvendo suas dúvidas.

[]s
Luca