# Modbus TCP

> Registradores e coils Modbus sobre TCP/IP, com endereçamento tipado, controle de ordem de bytes e uma varredura de rede limitada.

O driver Modbus TCP lê e escreve registradores e coils Modbus sobre TCP/IP:
CLPs, medidores, gateways e qualquer servidor que fale Modbus/TCP. O endereçamento é
totalmente tipado: você escolhe uma classe de registrador e um número de registrador em
base 0, e a aplicação monta a requisição do barramento; não há endereço em texto livre
para errar.

## Dispositivo {#device}

| Campo | Significado | Padrão |
| --- | --- | --- |
| **Host ou IP** | Nome DNS, endereço IPv4 ou IPv6 do servidor ou gateway Modbus. | vazio: o dispositivo não é conectado até um ser informado |
| **Porta** | Porta TCP, de 1 a 65535. Um campo vazio mostra 502 em cinza e o dispositivo é chamado nela, que é também como se lê um dispositivo salvo com 0. | 502 |
| **Unit ID** | O unit id (escravo) Modbus levado em toda requisição, o que um gateway usa para rotear até o dispositivo atrás dele. De 0 a 255. | 1 |
| **Enquadramento** | Como cada requisição trafega pela conexão: **MBAP**, o cabeçalho do Modbus TCP na frente de cada requisição, ou **RTU**, o quadro RTU com o CRC enviado como está, para um conversor serial-Ethernet em modo transparente (veja [RTU sobre TCP](#rtu-over-tcp)). Host, porta, Unit ID e tags são os mesmos nos dois casos. | MBAP |
| **Intervalo mínimo entre transações (ms)** | Ritmo de compatibilidade: o silêncio mínimo depois que uma transação termina, antes de a próxima começar, de 0 a 1000. Zero não acrescenta atraso artificial. | 0 |
| **Intervalo de leitura (ms)** | Taxa de leitura padrão para as tags que não a sobrepõem. | 1000 |

O Base URI mostrado no cabeçalho do painel é
`modbus+tcp://host:port/unitID`, mais `?minimumTransactionIntervalMs=n` quando o
intervalo está definido.

Dispositivos que compartilham host e porta também compartilham uma única porteira de
transações: requisições ao mesmo endpoint nunca se sobrepõem, e o **maior** intervalo
mínimo entre transações configurado entre os dispositivos habilitados naquele endpoint
ritma todos eles. O painel avisa quando outro dispositivo eleva o intervalo efetivo acima
do que está configurado aqui. O intervalo governa apenas o tráfego que esta aplicação
emite: ele é um recurso de compatibilidade para um servidor ou gateway lento, não um
conserto para falhas de rede.

Conectar espera no máximo 5 segundos; uma resposta é esperada por no máximo 10
segundos; não há novas tentativas no nível do protocolo. O laço de tentativas em segundo
plano é dono da reconexão, então um dispositivo desligado não custa nada além de uma
leitura de qualidade ruim.

## RTU sobre TCP {#rtu-over-tcp}

Um conversor serial-Ethernet em modo transparente não fala Modbus TCP por conta própria: o que chega ao seu socket sai como está pelo barramento serial, e o que o barramento responde volta. Um dispositivo atrás de um conversor é um dispositivo Modbus TCP com o **Enquadramento** em **RTU**: a estação envia o quadro RTU (o Unit ID, a requisição e o CRC) sem cabeçalho MBAP, e só aceita uma resposta cujo CRC confere. O Base URI passa a levar `framing=rtu` na consulta, por exemplo `modbus+tcp://192.168.0.20:502/1?framing=rtu`; um dispositivo em **MBAP** mantém o endereço que sempre teve. Todo o resto desta página continua valendo: as classes de registrador, os códigos de função, a fila de escritas, os timeouts e o intervalo entre transações.

- O **Unit ID** é o endereço do dispositivo no barramento serial atrás do conversor, de 1 a 247.
- Os dispositivos atrás de um conversor compartilham o host e a porta dele e, com eles, a porteira de transações: uma requisição por vez, que é também tudo o que um barramento serial leva. Se o conversor precisar de uma pausa entre quadros, aumente o **Intervalo mínimo entre transações (ms)**.
- As configurações seriais do próprio conversor (velocidade em baud, formato) são feitas no conversor; a estação nunca as vê.
- Um quadro RTU não leva número de transação, então antes de cada requisição a estação descarta o que o conversor já tiver enviado: uma resposta que chega depois do timeout da sua requisição nunca é tomada pela da seguinte.

## Endereçamento da tag {#tag-addressing}

| Campo | Significado | Padrão |
| --- | --- | --- |
| **Classe do registrador** | Qual entidade Modbus a tag endereça: Bobina (0xxxx), Entrada discreta (1xxxx), Registrador de entrada (3xxxx) ou Registrador de retenção (4xxxx). Cada uma leva o primeiro dígito que o endereço do manual tem para ela, então um manual que imprime só 30001 aponta para os registradores de entrada. | Derivada do tipo e do acesso: tags booleanas recebem uma entrada discreta (somente leitura) ou uma bobina (gravável); todo outro tipo recebe um registrador de entrada (somente leitura) ou um registrador de retenção (gravável). |
| **Número do registrador (começando em 0)** | O endereço bruto do protocolo. Este é o endereço em base 0 no barramento, não a notação do manual: o holding register 40001 é o registrador número 0. Digitar 30001 aqui não escolhe a classe, porque há equipamentos com registradores acima de 30000 de verdade: a classe é escolhida acima. O registrador viaja no barramento como um número de 16 bits, então o campo aceita de 0 a 65535 e recusa qualquer coisa mais larga onde é digitado. | 0 |
| **Quantidade (registradores, vazio = automático)** | Quantos registradores de 16 bits o valor ocupa. A caixa é desenhada só em tags String: todo outro tipo tem largura fixa, então não há o que sobrepor. | Por tipo: Boolean, Int16 e UInt16 1, Int32 e Float 2, String 4 |
| **Byte mais significativo primeiro (MSB first, big-endian)** | Qual byte de cada registrador de 16 bits vem primeiro no barramento; as palavras entre parênteses são as que os manuais imprimem. Em tags numéricas e numa tag booleana guardada num registrador de retenção ou de entrada; uma booleana numa bobina ou numa entrada discreta é um bit só, sem byte para ordenar, então ali a caixa não é desenhada. | ligado (o que a especificação Modbus pede) |
| **Palavra mais significativa primeiro (palavra alta primeiro)** | Qual registrador de um valor de dois registradores leva a metade alta. Só em tags Int32 e Float: um valor de um registrador só (Boolean, Int16, UInt16) não tem segundo registrador, então a caixa não é desenhada ali. Sob as duas caixas, **Ordem dos bytes do valor** nomeia o arranjo que elas formam nas letras de um manual ([Ordem de bytes e de palavras](#byte-and-word-order)). | ligado |

O cartão Origem termina com **Endereço no manual**, onde a tag fica na notação que o
manual do equipamento imprime: o primeiro dígito da classe e depois o registrador contado
a partir de 1. O registrador de entrada 0 lê 30001, um Float no registrador de retenção 100
lê de 40101 a 40102, e um registrador acima de 9998 ganha seis dígitos (o registrador de
retenção 9999 lê 410000), então o painel se lê contra o manual linha por linha.

### Tipos de valor e quantidades {#value-types-and-quantities}

Seis tipos de valor são oferecidos, e a largura de protocolo de cada um é fixa:

| Tipo de dado | Registradores | Forma no barramento |
| --- | --- | --- |
| Boolean | 1 | Numa classe de registrador: qualquer registrador diferente de zero lê verdadeiro, e uma escrita envia 1 ou 0. Em `Coil`/`DiscreteInput`: o próprio bit. |
| Int16 | 1 | Inteiro de 16 bits com sinal, num único registrador, de -32768 a 32767. |
| UInt16 | 1 | Inteiro de 16 bits sem sinal, num único registrador, de 0 a 65535. O mesmo registrador lê 65535 como UInt16 e -1 como Int16: o sinal vem do tipo de dado escolhido, não do registrador. |
| Int32 | 2 | Inteiro de 32 bits com sinal, num par de registradores. |
| Float | 2 | Precisão simples IEEE 754, num par de registradores. |
| String | 1 ou mais (padrão 4) | Bytes UTF-8 empacotados dois por registrador. Uma leitura para no primeiro byte NUL; uma escrita precisa caber na quantidade declarada (2 bytes por registrador) e é preenchida com zeros. |

Uma tag String é lida e escrita na ordem em que o dispositivo guarda os bytes, e uma
escrita sempre envia UTF-8. Bytes que não são UTF-8 válido, que é a cara de uma faixa que
o dispositivo nunca inicializou ou de um texto escrito em outra codificação,
leem como o caractere de substituição do Unicode em vez de falhar: a tag mostra
algo visivelmente errado, e toda outra tag daquele dispositivo segue lendo.

A **Quantidade (registradores, vazio = automático)** é pedida só em tags String. As
larguras de Boolean, Int16, UInt16, Int32 e Float são fixas, então a caixa não é desenhada nesses pontos,
nem no painel da tag nem na grade de tags; a sobreposição existe para dimensionar tags
String.

### Ordem de bytes e de palavras {#byte-and-word-order}

A caixa da ordem de bytes é desenhada em tags numéricas e numa booleana guardada em registrador; a da ordem de palavras, só nas de dois registradores (Int32, Float). Elas são perguntas
independentes: qual byte vem na frente dentro de cada registrador, e qual registrador vem
na frente num par. O Modbus não define nenhuma das duas para texto, então uma tag String
não as recebe: os bytes dela viajam na ordem em que o dispositivo os guarda. Para o valor
`0x01020304`, com `A` sendo o byte mais significativo, os quatro arranjos são:

| Byte mais significativo primeiro | Palavra mais significativa primeiro | Bytes no barramento |
| --- | --- | --- |
| ligado | ligado | `AB CD` (o padrão da especificação) |
| ligado | desligado | `CD AB` (a troca clássica de palavras) |
| desligado | ligado | `BA DC` |
| desligado | desligado | `DC BA` |

Leituras e escritas aplicam as mesmas duas respostas na mesma ordem, então uma escrita
deposita exatamente os bytes que uma leitura teria trazido de volta. **Ordem dos bytes do valor**,
sob as caixas, diz o arranjo numa palavra (ABCD, CDAB, BADC ou DCBA), como um manual o nomeia.

Um valor Int16 ou UInt16 é um registrador só, então só a ordem de bytes se aplica a ele:
para `0x1234`, byte mais significativo primeiro envia `12 34` e desligado envia `34 12`.
Não há segundo registrador para posicionar, então a caixa da ordem de palavras não é
desenhada para ele.

### Códigos de função {#function-codes}

| Classe de registrador | Leitura | Escrita |
| --- | --- | --- |
| Registrador de retenção (4xxxx) | 3 (Read Holding Registers) | 6 (registrador único) ou 16 (vários registradores) |
| Registrador de entrada (3xxxx) | 4 (Read Input Registers) | somente leitura; uma escrita é recusada |
| Bobina (0xxxx) | 1 (Read Coils) | 5 (Force Single Coil), um bit por vez |
| Entrada discreta (1xxxx) | 2 (Read Discrete Inputs) | somente leitura; uma escrita é recusada |

Uma escrita só retorna sucesso quando a resposta de protocolo do servidor confirma a
aceitação; o valor cacheado só avança então.

## Descoberta {#discovery}

A varredura é explícita e limitada: a aplicação nunca deduz nem varre a sua sub-rede
local. O formulário de escopo recebe:

| Campo | Significado | Padrão |
| --- | --- | --- |
| **Host IPv4 ou CIDR** | Um endereço (`192.168.1.10`) ou uma sub-rede não mais ampla que /24 (`192.168.1.0/24`). Os endereços de rede e de difusão são pulados. | obrigatório |
| **Porta** | A porta a sondar. | 502 |
| **Unit ids** | Valores, listas separadas por vírgula ou faixas crescentes: `1`, `1,5,9`, `1, 3, 8-16` (de 0 a 255). | 1 |
| **Enquadramento** | O quadro em que cada sondagem é enviada. Um conversor em modo transparente só responde a quadros RTU, então varra-o em RTU. | MBAP |
| **Intervalo mínimo entre transações (ms)** | Ritmo entre sondagens concluídas no mesmo host, de 0 a 1000. | 0 |

A varredura envia cada sondagem no **Enquadramento** escolhido. Em **RTU** cada sondagem é o quadro RTU puro, e uma resposta só conta quando o Unit ID confere e o CRC é válido, então as unidades atrás de um conversor em modo transparente são encontradas como qualquer outra. Uma unidade encontrada mantém o enquadramento da varredura ao ser acrescentada.

Uma varredura pode enviar no máximo **256 sondagens** (hosts × unit ids); um plano maior é
recusado antes de qualquer soquete abrir. A única requisição enviada é a **Read Basic Device
Identification** (função 43/14): a descoberta nunca lê registradores nem adivinha um mapa
de registradores. Uma resposta de exceção Modbus totalmente válida prova que uma unidade
está presente sem afirmar a identidade dela; alcançabilidade TCP, timeouts e quadros
malformados não provam. Até quatro hosts são varridos em paralelo, sequencialmente dentro
de cada host, com timeouts de 750 ms para conectar e para sondar.

Os resultados carregam o endpoint completo e um nome sugerido, montado a partir do
fabricante e do código de produto quando o dispositivo os relata. Os candidatos têm zero
tags: os registradores são configurados depois do **Adicionar**. Uma unidade já
configurada é marcada como tal e oferece **Abrir** em vez de criar uma duplicata.

## Limites que vale conhecer {#limits-worth-knowing}

- Outras larguras de inteiro (SByte, Byte, UInt32, Int64, UInt64) e Double não são
  oferecidos: o codec do barramento vai e volta exatamente com os seis tipos acima.
- Uma requisição fica pendente por endpoint de cada vez; muitos dispositivos atrás de um
  gateway compartilham essa serialização por projeto.
- As escritas endereçam um coil ou uma sequência de registradores por vez; não há
  escrita de vários coils.
