Integração com sistemas de automação

Especificação do MTerminal para empresas que desenvolvem sistemas de automação comercial (PDV, restaurantes, padarias, bares) com suporte a microterminais VT100 via TCP/IP.

1.Visão geral

O MTerminal é um aplicativo Android que emula um microterminal de pedidos (visor LCD de caracteres + teclado numérico) conectado por TCP/IP ao servidor de microterminais do seu sistema. Ele se comporta como um terminal "burro": toda a lógica fica no servidor.

DireçãoConteúdo
Servidor → appTexto e sequências de controle VT100/ANSI (e, opcionalmente, quadros STX/ETX) que desenham o visor.
App → servidorUm byte (ou poucos bytes) por tecla pressionada e o conteúdo lido pelo leitor de código de barras.

Se o seu servidor já atende microterminais VT100 em rede (Ethernet/TCP), normalmente o MTerminal funciona sem nenhuma alteração: basta cadastrar o aparelho como mais um terminal.

2.Requisitos de rede

3.Conexão TCP e sessão

ItemComportamento do MTerminal
PapelCliente TCP. O app conecta em IP:porta configurados; o servidor escuta.
Conexões por aparelhoUma. Antes de abrir uma nova conexão, a anterior é sempre encerrada.
Tempo limite de conexão5 segundos.
Reconexão automáticaApós falha ou queda: 2 s, 4 s, 8 s, 16 s e depois a cada 30 s, até conectar. Volta a 2 s depois de uma conexão bem-sucedida.
Retorno ao appAo voltar do segundo plano sem conexão, reconecta imediatamente (o Android pode derrubar o socket de apps em segundo plano).
Alteração de configuraçõesAo salvar, encerra a conexão e abre uma nova.
Opções do socketTCP_NODELAY ativado (cada tecla sai na hora). Sem keep-alive de aplicação.
CodificaçãoLatin-1 (ISO-8859-1), 1 byte por caractere, nos dois sentidos. Caracteres fora da faixa são enviados como ?.
Envio de teclasSomente com a conexão estabelecida; teclas pressionadas sem conexão são descartadas.
Estado ao reconectarO interpretador de sequências é reiniciado, mas o conteúdo do visor permanece até o servidor redesenhá-lo.

4.Identificação do terminal

O MTerminal suporta as duas formas usuais:

4.1 Pelo IP de origem (padrão, recomendado)

O app não envia nada ao conectar. O servidor identifica o terminal pelo endereço IP remoto da conexão, como faz com microterminais físicos. O IP do aparelho aparece para o usuário em Configurações → IP deste aparelho, para ser cadastrado no seu sistema.

4.2 Por identificador enviado ao conectar (opcional)

Com a opção “Enviar identificador ao conectar” ligada, logo após o connect o app envia o campo Identificador do Terminal seguido de CR:

<identificador> 0x0D        ex.: "01\r" → 30 31 0D
Atenção

Se o seu servidor identifica por IP, deixe essa opção desligada: caso contrário o identificador chega ao servidor como se tivesse sido digitado (ex.: “01” + Enter no prompt de operador).

5.Modelo do visor

6.Sequências VT100/ANSI suportadas

O interpretador é contínuo: sequências divididas entre pacotes TCP são tratadas corretamente. Notação: ESC = 0x1B; CSI = ESC [; n omitido assume o padrão indicado.

SequênciaNomeEfeito no MTerminal
CSI 2 JLimpar telaLimpa o visor inteiro, cursor na linha 1, coluna 1.
CSI J / CSI 0 JLimpar até o fimLimpa do cursor até o fim do visor (cursor não se move).
CSI 1 JLimpar até o inícioLimpa do início do visor até o cursor.
CSI K / CSI 0 KLimpar linha → fimLimpa do cursor até o fim da linha.
CSI 1 KLimpar linha ← inícioLimpa do início da linha até o cursor.
CSI 2 KLimpar linhaLimpa a linha inteira.
CSI l ; c H / fPosicionar cursorLinha l, coluna c (padrão 1;1). Aceita zeros à esquerda (ESC[01;05H) e um só parâmetro (ESC[2H = linha 2, coluna 1).
CSI HCursor no inícioLinha 1, coluna 1.
CSI n A/B/C/DMover cursorCima/baixo/direita/esquerda n posições (padrão 1), sem sair do visor.
CSI s / CSI uSalvar/restaurar cursorGuarda e recupera a posição do cursor.
ESC 7 / ESC 8Salvar/restaurar cursorIdem (forma DEC).
ESC cResetLimpa o visor e posiciona o cursor em 1;1.
ESC D / ESC MIndex / Reverse indexCursor uma linha abaixo/acima (limitado ao visor).
ESC EPróxima linhaInício da linha seguinte.
CSI 0 m, CSI 7 m, CSI 27 m, CSI 0;7 mAtributosAceitos (vários parâmetros permitidos), sem efeito visual: o visor não exibe vídeo reverso.
CSI 5 i … CSI 4 iMedia copy (impressora/porta auxiliar)Tudo entre as duas sequências é descartado (não aparece no visor).
CSI ? … h/l e outros modos privadosModos DECIgnorados sem imprimir nada (ex.: ESC[?25l, ESC[?24h).
ESC O x, ESC ( x, ESC ) x, ESC # xSS3 / charset / DECIgnorados (consomem o próximo byte).
Qualquer outro CSI … final—Ignorado sem imprimir nada.

7.Caracteres de controle e texto

ByteNomeEfeito
0x07BELEmite o som de clique do sistema (se o bip estiver ativado no app).
0x08BSCursor uma posição à esquerda e apaga o caractere (padrão dos microterminais). O usuário pode desligar o apagamento (VT100 estrito). BS espaço BS também funciona.
0x09TABAvança até a próxima coluna múltipla de 8.
0x0A, 0x0B, 0x0CLF / VT / FFInício da linha seguinte (sem rolagem: da última linha volta para a primeira).
0x0DCRCursor na coluna 1 da linha atual.
0x02 / 0x03STX / ETXVer seção 8.
0x20–0x7EASCII imprimívelEscrito na posição do cursor.
0xA0–0xFFLatin-1Escrito (acentos: Ã=0xC3, Ç=0xC7, É=0xC9…).
Demais (0x00–0x1F, 0x7F–0x9F)—Ignorados.

8.Enquadramento STX/ETX

Definido pelo usuário em Configurações → Protocolo:

8.1 “VT100 / ANSI” (padrão)

STX (0x02) e ETX (0x03) são apenas delimitadores e são descartados; o conteúdo segue como VT100. Um eventual byte de verificação (LRC) após o ETX seria tratado como texto, então não o envie nesse modo.

8.2 “STX/ETX com comandos”

Para sistemas que usam quadros STX <comando> <dados> ETX:

QuadroEfeitoExemplo
STX D <texto> ETXEscreve o texto (pode conter sequências VT100).02 44 "MESA:" 03
STX L ETXLimpa o visor e posiciona em 1;1.02 4C 03
STX C <l><cc> ETXPosiciona o cursor com linha (1 dígito) e coluna (2 dígitos) a partir de 0.STX C105 ETX = linha 2, coluna 6
STX P … ETX / STX S … ETXDados para impressora/serial do terminal: descartados.—
Outro comandoO conteúdo do quadro é tratado como VT100.—

Sequências VT100 fora de quadros continuam funcionando nesse modo. Quadros com mais de 512 bytes sem ETX são exibidos como texto.

9.Teclado: bytes enviados

Cada toque envia imediatamente (sem buffer de linha) os bytes abaixo. Enter, Del e Bck são configuráveis pelo usuário; os valores padrão estão em destaque.

TeclaEnviaOpções
0–90x30–0x39—
.0x2E—
,0x2C—
EnterCR 0x0DCR+LF 0D 0A · LF 0A
DelESC 0x1BBS 08 · DEL 7F
BckBS 0x08DEL 7F
Dica

Trate a entrada como um fluxo de bytes: vários toques (e a leitura do leitor de código de barras) podem chegar no mesmo segmento TCP.

10.Leitor de código de barras

A leitura pela câmera envia o conteúdo do código seguido da sequência configurada para Enter, como um leitor de teclado:

7891000012345 + CR  →  37 38 39 31 30 30 30 30 31 32 33 34 35 0D

11.Exemplo de sessão

Login do operador “125” num visor 2×20, com eco feito pelo servidor:

# servidor → app: limpa e pede o operador
ESC[2J ESC[1;1H "OPERADOR:"            1B 5B 32 4A 1B 5B 31 3B 31 48 4F 50 45 ...

# usuário digita 1, 2, 5 (um byte por toque); o servidor ecoa cada um
app → servidor: 31          servidor → app: 31
app → servidor: 32          servidor → app: 32
app → servidor: 35          servidor → app: 35

# usuário corrige com Bck: o servidor ecoa BS (o app apaga o "5")
app → servidor: 08          servidor → app: 08

# Enter confirma; servidor responde na linha 2
app → servidor: 0D
servidor → app: ESC[2;1H ESC[K "BEM-VINDO JOAO"

12.Servidor de teste

Para testar sem o sistema completo, rode este servidor mínimo (Python 3) no computador e aponte o app para o IP dele, porta 1001. Ele desenha uma tela, ecoa os dígitos, trata Bck e responde ao Enter:

import socket, threading

ESC = "\x1b"

def atender(conn, addr):
    print("terminal conectado:", addr[0])
    def envia(texto):
        conn.sendall(texto.encode("latin-1"))
    envia(f"{ESC}[2J{ESC}[1;1HMTERMINAL TESTE{ESC}[2;1HDIGITE: ")
    digitado = ""
    while True:
        dados = conn.recv(64)
        if not dados:
            break
        for b in dados:
            ch = chr(b)
            if ch.isdigit():
                digitado += ch
                envia(ch)                      # eco
            elif b == 0x08 and digitado:       # Bck
                digitado = digitado[:-1]
                envia("\x08")
            elif b == 0x0D:                    # Enter
                envia(f"{ESC}[1;1H{ESC}[KRECEBIDO: {digitado}"
                      f"{ESC}[2;1H{ESC}[KDIGITE: ")
                digitado = ""
            elif b == 0x1B:                    # Del
                digitado = ""
                envia(f"{ESC}[2;1H{ESC}[KDIGITE: ")
    conn.close()

srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 1001))
srv.listen()
while True:
    threading.Thread(target=atender, args=srv.accept(), daemon=True).start()

Alternativa rápida para ver apenas a exibição: ncat -l 1001 (ou nc -l -p 1001 no Linux) e digite o texto a enviar.

13.Boas práticas do servidor

  1. Aceite várias conexões simultâneas, uma por aparelho.
  2. Reconexão do mesmo IP: ao receber uma nova conexão de um IP que já tem sessão, encerre a sessão antiga e continue na nova. O app nunca mantém duas conexões, então a antiga está morta.
  3. Redesenhe a tela inteira no início de cada conexão (ESC[2J + conteúdo), porque o visor mantém o conteúdo anterior.
  4. Posicione o cursor explicitamente (ESC[l;cH) e limpe com ESC[K, em vez de depender de LF e rolagem.
  5. Faça o eco dos caracteres digitados que devem aparecer no visor, e ecoe BS ao apagar.
  6. Trate a entrada como fluxo: não assuma um toque por pacote.
  7. Não derrube conexões ociosas muito cedo: o operador pode passar vários minutos sem digitar. Detecte conexões mortas por falha de envio ou pela chegada de uma nova conexão do mesmo IP.
  8. Mantenha o texto dentro do formato configurado (ex.: 20 colunas no 2×20) e use Latin-1 para acentos.

14.Checklist de homologação

#TesteResultado esperado
1Cadastrar o IP do aparelho e abrir o appStatus “CONECTADO” e tela inicial do sistema no visor.
2Digitar númerosEco correto na posição esperada.
3Bck, Del e EnterApagar, cancelar e confirmar funcionam no fluxo do sistema.
4Ler um código de barras de produtoProduto lançado como se tivesse sido digitado + Enter.
5Textos com acentosAcentos exibidos corretamente (Latin-1).
6Desligar o Wi-Fi do aparelho por 30 s e religarO app reconecta sozinho; o servidor aceita a nova conexão e redesenha a tela.
7Reiniciar o servidor de microterminaisO app reconecta em até 30 s.
8Vários aparelhos ao mesmo tempoCada um com sua sessão, sem interferência.
9Alterar e salvar as Configurações do appUma única nova conexão; nenhuma sessão duplicada no servidor.
10Fluxo completo de venda (mesa/comanda, itens, fechamento)Igual ao microterminal físico equivalente.

15.Configurações do app (referência)

Para orientar o cliente final, estes são os campos em Configurações e os valores padrão:

CampoPadrãoObservação
IP do Servidor—IP ou nome do host do servidor de microterminais.
Porta TCP10011 a 65535.
Identificador do Terminal—Exibido no app; enviado apenas se a opção abaixo estiver ligada.
Enviar identificador ao conectarDesligadoSeção 4.2.
ProtocoloVT100 / ANSIOu “STX/ETX com comandos” (seção 8).
Backspace do servidor apaga o caractereLigadoDesligue para VT100 estrito (BS só move o cursor).
Formato do visor2×202×16, 2×20, 2×40, 4×20.
Enter / Del / BckCR / ESC / BSSeção 9.
Tema, bip, manter tela ligadaVerde, ligado, ligadoApenas visuais/conforto.

16.Limitações conhecidas

17.Contato técnico

Dúvidas de integração, relatos de incompatibilidade ou pedidos de novas sequências: suporte.dns.apps@gmail.com. Ajuda informar o sistema, a versão, o formato do visor e, se possível, uma captura dos bytes enviados pelo servidor.

Para orientar seus clientes no uso diário, indique o Manual do Usuário.