Porta serial virtual para Linux

128

Preciso testar um aplicativo de porta serial no Linux, no entanto, minha máquina de teste possui apenas uma porta serial.

Existe uma maneira de adicionar uma porta serial virtual ao Linux e testar meu aplicativo emulando um dispositivo por meio de um shell ou script?

Nota: Não consigo remapear a porta, ela está codificada em ttys2 e preciso testar o aplicativo como está escrito.

JeffV
fonte

Respostas:

75

Você pode usar um pty ("pseudo-teletype", em que uma porta serial é um "teletype real") para isso. De um lado, abra /dev/ptyp5e, em seguida, conecte seu programa a /dev/ttyp5; ttyp5agirá como uma porta serial, mas enviará / receberá tudo o que fizer via / dev / ptyp5.

Se você realmente precisa conversar com um arquivo chamado /dev/ttys2, basta mover seu antigo /dev/ttys2para fora do caminho e fazer um link simbólico de ptyp5para ttys2.

Claro que você pode usar outro número que não ptyp5. Talvez escolha um com um número alto para evitar duplicatas, pois todos os seus terminais de login também usarão ptys.

A Wikipedia tem mais sobre ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

apenwarr
fonte
8
No linux, você pode usar as chamadas de sistema openpty / forkpty. Veja a página de manual
Matthew Smith
8
como criar um par de portas seriais virtuais usando a ferramenta de linha de comando?
precisa saber é o seguinte
8
observe que muitos parâmetros da porta serial, por exemplo, baudrate, paridade, controle de fluxo hw, tamanho do caractere (?) não são implementados no pty, portanto, é impossível testar seu aplicativo na presença de erros de transmissão serial.
Dima Tisnek
10
Isso é útil, mas descreve os pseudo-terminais BSD "estilo antigo". Os pseudo-terminais UNIX 98 de "novo estilo" funcionam um pouco diferente - consulte a ptspágina de manual para obter detalhes.
Craig McQueen
3
@LaszloPapp Peço desculpas, eu estava mentindo o tempo todo
Matthew Smith
160

Complementando a resposta do @ slonik.

Você pode testar o socat para criar a porta serial virtual, executando o seguinte procedimento (testado no Ubuntu 12.04):

Abra um terminal (vamos chamá-lo de Terminal 0) e execute:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

O código acima retorna:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Abra outro terminal e escreva (Terminal 1):

cat < /dev/pts/2

o nome da porta deste comando pode ser alterado de acordo com o pc. depende da saída anterior.

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

você deve usar o número disponível na área destacada.

Abra outro terminal e escreva (Terminal 2):

echo "Test" > /dev/pts/3

Agora, de volta ao Terminal 1, você verá a sequência "Teste".

cantoni
fonte
Isso funcionou melhor para mim do que a resposta do slonik, porque atribui automaticamente a arquivos de porta virtual COM e não ecoa.
Gbmhunter
7
Se você quiser um nome de arquivo reproduzível, use link=/path/to/linkapós cada declaração de dispositivo (após eco = 0). Assim, pode ser usado em testes automatizados. (como Slonik faz em sua resposta)
Patrick B.
Isso funcionou exatamente como mencionado. Isso me ajudou muito.
Nim118 11/0418
1
Para criar um pty que links para uma porta serial real: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng 31/08/18
posso criar uma porta serial com nomes como em /dev/ttyS0vez de /dev/pts/1?
mrid 29/04
48

Use socat para isso:

Por exemplo:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
slonik
fonte
Isso funcionou bem para mim, testado com minicom! Parece que a entrada de um terminal é ecoada para ambos (portanto, também reaparecerá no terminal de entrada).
Gbmhunter
1
Eu não tenho o mesmo comportamento de eco ... o minicom tem um recurso de "eco local" ... mas, quando desativado, funciona exatamente como uma porta serial real. Obrigado pela dica.
precisa
16

Também existe o tty0tty http://sourceforge.net/projects/tty0tty/, que é um emulador de modem nulo real para linux.

É um módulo simples do kernel - um pequeno arquivo de origem. Eu não sei por que isso só deu certo no sourceforge, mas funciona bem para mim. A melhor coisa é que também emula os pinos de hardware (RTC / CTS DSR / DTR). Ele ainda implementa os comandos TIOCMGET / TIOCMSET e TIOCMIWAIT iotcl!

Em um kernel recente, você pode receber erros de compilação. Isso é fácil de consertar. Basta inserir algumas linhas na parte superior da fonte module / tty0tty.c (após incluir):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

Quando o módulo é carregado, ele cria 4 pares de portas seriais. Os dispositivos são / dev / tnt0 a / dev / tnt7, onde tnt0 está conectado a tnt1, tnt2 está conectado a tnt3 etc. Você pode precisar corrigir as permissões de arquivo para poder usar os dispositivos.

editar:

Acho que fui um pouco rápido com meu entusiasmo. Enquanto o motorista parece promissor, parece instável. Não sei ao certo, mas acho que caiu uma máquina no escritório em que trabalhava em casa. Não posso verificar até voltar ao escritório na segunda-feira.

A segunda coisa é que o TIOCMIWAIT não funciona. O código parece ter sido copiado de algum código de exemplo "tiny tty". A manipulação do TIOCMIWAIT parece estar ativa, mas nunca é ativada porque está faltando a chamada correspondente para wake_up_interruptible ().

editar:

O acidente no escritório foi realmente culpa do motorista. Faltava uma inicialização e o código TIOCMIWAIT completamente não testado causou uma falha na máquina.

Passei ontem e hoje reescrevendo o motorista. Havia muitos problemas, mas agora funciona bem para mim. Ainda falta um código para o controle de fluxo de hardware gerenciado pelo driver, mas não preciso disso, porque eu mesmo gerenciarei os pinos usando TIOCMGET / TIOCMSET / TIOCMIWAIT no código do modo de usuário.

Se alguém estiver interessado na minha versão do código, envie-me uma mensagem e eu a enviarei.

Peter Remmers
fonte
2
Eu ficaria interessado em ver seu código. Você pode contribuir de volta para o projeto tty0tty? No entanto, eu preferiria ver as pessoas melhorarem o código pseudo-terminal no kernel do Linux. Por exemplo, adicione suporte a handshaking de hardware e TIOCMIWAIT.
Craig McQueen
3
"Se alguém estiver interessado na minha versão do código, envie-me uma mensagem e eu enviarei para você." Sim, eu estou interessado! Você pode apontar para algum lugar, por exemplo, no GitHub?
Craig McQueen
7
Carreguei o driver em: github.com/pitti98/nullmodem Desculpe, demorou muito para responder. Não sou muito ativo no stackoverflow e esqueci o seu comentário!
precisa
Não, eu escrevi porque precisava e parei quando era bom o suficiente para fazer o que eu queria. Agora que é público, espero que seja útil para outra pessoa, e talvez alguém atenda onde eu a deixei.
Peter Remmers
8

Você pode querer dar uma olhada no Tibbo VSPDL para criar uma porta serial virtual linux usando um driver Kernel - parece bastante novo e está disponível para download agora (versão beta). Não tenho certeza sobre a licença neste momento ou se eles querem disponibilizá-la comercialmente somente no futuro.

Existem outras alternativas comerciais, como http://www.ttyredirector.com/ .

Em código aberto, o Remserial (GPL) também pode fazer o que você deseja, usando PTYs do Unix. Ele transmite os dados seriais em "formato bruto" para um soquete de rede; A configuração de parâmetros do terminal do tipo STTY deve ser feita ao criar a porta, alterando-os posteriormente, como descrito na RFC 2217, não parece ser suportado. Você poderá executar duas instâncias remseriais para criar um modem nulo virtual como com0com, exceto que você precisará configurar a velocidade da porta, etc.

O Socat (também GPL) é como uma variante estendida do Remserial com muitas outras opções, incluindo um método "PTY" para redirecionar o PTY para outra coisa, que pode ser outra instância do Socat. Para notas de unidade, o socat é provavelmente melhor do que remserial, porque você pode direcionar arquivos diretamente para o PTY. Veja o exemplo PTY na página de manual. Existe um patch em "contrib" para fornecer suporte ao RFC2217 para negociar configurações de linha serial.


fonte
6

Usando os links publicados nas respostas anteriores, codifiquei um pequeno exemplo em C ++ usando uma porta serial virtual. Enviei o código para o GitHub: https://github.com/cymait/virtual-serial-port-example .

O código é bastante auto-explicativo. Primeiro, você cria o processo mestre executando ./main master e ele será impresso para stderr que o dispositivo está usando. Depois disso, você invoca ./main slave device, em que device é o dispositivo impresso no primeiro comando.

E é isso. Você tem um link bidirecional entre os dois processos.

Usando este exemplo, você pode testar o aplicativo enviando todos os tipos de dados e ver se funciona corretamente.

Além disso, você sempre pode vincular o dispositivo a um link simbólico, para não precisar recompilar o aplicativo que está testando.

Mauro Ciancio
fonte
1
while (read (fd, & inputbyte, 1) == 1) {...} ler é indefinido no seu código. a gravação é indefinida. close é indefinido.
Mattis Asp
4

Você seria capaz de usar um adaptador USB-> RS232? Eu tenho alguns, e eles apenas usam o driver FTDI. Então, você poderá renomear / dev / ttyUSB0 (ou o que for criado) como / dev / ttyS2.

Furo
fonte
4

Eu posso pensar em três opções:

Implementar RFC 2217

O RFC 2217 cobre uma porta de comunicação com o padrão TCP / IP que permite que um cliente em um sistema emule uma porta serial para os programas locais, enquanto envia e recebe de forma transparente dados e sinais de controle para um servidor em outro sistema que realmente possui a porta serial. Aqui está uma visão geral de alto nível .

O que você faria é encontrar ou implementar um driver de porta de cliente que implementasse o lado do cliente do sistema no seu PC - parecendo ser uma porta serial real, mas na realidade transferindo tudo para um servidor. Você pode obter esse driver gratuitamente no Digi, Lantronix, etc, suportando seus servidores de porta serial reais e independentes.

Você implementaria o lado da conexão do servidor localmente em outro programa - permitindo que o cliente se conectasse e emitisse os dados e comandos de controle conforme necessário.

Provavelmente não é trivial, mas o RFC está disponível, e você pode encontrar um projeto de código aberto que implemente um ou ambos os lados da conexão.

Modifique o driver da porta serial linux

Como alternativa, a fonte do driver da porta serial para Linux está prontamente disponível. Pegue isso, limpe as peças de controle de hardware e faça com que um driver execute duas portas / dev / ttySx, como um loopback simples. Em seguida, conecte seu programa real ao ttyS2 e seu simulador ao outro ttySx.

Use dois cabos seriais USB <--> em um loopback

Mas a coisa mais fácil de fazer agora? Gaste US $ 40 em dois dispositivos USB de porta serial, conecte-os (modem nulo) e, na verdade, tenha duas portas seriais reais - uma para o programa que você está testando e outra para o seu simulador.

-Adão

Adam Davis
fonte
1
Na verdade, os cabos USB UART do modem nulo parecem uma solução bastante elegante para mim, pois oferecem suporte a testes locais (obtenha um hub USB se você não tiver portas) e depuração remota.
Maxthon Chan
Eu não revi sua qualidade, mas o ttynvt implementa o RFC 2217 via Linux FUSE
Daniel Santos