# Servidor Modbus

> O servidor Modbus TCP da própria estação: a linha dele na coluna Comunicação, como ligá-lo e desligá-lo, a porta e os clientes conectados, o mapa de registradores que serve tags, variáveis da Logic e estados de alarme, o que um cliente lê e escreve, um exemplo completo e o que ele não faz.

O **Servidor Modbus** deixa um CLP, uma IHM ou um sistema predial que só fala Modbus TCP ler as tags, as variáveis da Logic e os estados de alarme da estação, e escrever nas tags e variáveis que você liberar. É o segundo caminho pelo qual os dados saem da estação, ao lado do [servidor OPC UA embutido](connector-opcua-server), e não é um driver: um driver lê equipamentos, enquanto o servidor Modbus é lido por equipamentos, esperando que um CLP se conecte e sem nunca se conectar a nada. O painel diz isso logo abaixo do título: "Atende os CLPs, IHMs e sistemas prediais que leem e escrevem por Modbus TCP. Recebe conexões e nunca abre uma."

O Modbus não tem nome de usuário nem senha: quem alcança a porta lê todo registrador que o mapa serve. Por isso o servidor nasce desligado, toda linha do mapa nasce somente leitura, e a escrita é liberada linha a linha, por alguém que escolheu liberá-la. Ver Connector lê a página; Configurar Connector a altera.

## A linha na coluna {#the-row-in-the-column}

A linha **Servidor Modbus** fica sob a pasta Servidores da árvore da coluna Comunicação, abaixo da linha do servidor OPC UA, com um ícone de servidor onde os drivers mostram um plugue. Ela está sempre lá: a estação tem exatamente uma, e ela nunca é criada nem excluída. A caixa de busca a acha pelo nome, e os chips de estado a separam pelo estado dela: **Desligados** enquanto o servidor está desligado, **Problemas** enquanto a porta dele está ocupada ou ele não conseguiu escutar, **OK** nos outros casos. Ao lado do nome ela diz o que o servidor está fazendo, e um ponto resume:

| A linha diz | Ponto | Quando |
| --- | --- | --- |
| "Desligado" | cinza | O servidor está desligado, que é como toda estação começa. |
| "Escutando na porta 502", depois quantos clientes estão conectados: "Nenhum cliente conectado", "1 cliente conectado", "3 clientes conectados" | verde | O servidor está ligado e o runtime está rodando: a porta está aberta. |
| "A porta 502 está em uso" | vermelho | O servidor está ligado, mas outro programa segura a porta. |
| "Não foi possível escutar na porta 502" | vermelho | O servidor está ligado, mas o Windows recusou abrir a porta por outro motivo. |
| "Runtime parado" | cinza | O servidor está ligado e o runtime está parado: a porta fica fechada até o runtime voltar a rodar. |

O ponto é só do servidor: ele não entra na consolidação da pasta Drivers nem na barra de status, que tratam dos equipamentos que a estação lê. Selecionar a linha abre o painel do servidor; o cabeçalho repete o estado ao lado do mesmo ponto. Os comandos ficam na barra de comandos; a linha não tem menu próprio.

## Ligar e desligar {#turning-it-on-and-off}

| Comando | O que faz | Esmaecido quando (situação) | Não desenhado quando (papel) |
| --- | --- | --- | --- |
| **Habilitar** | Liga o servidor, como diz a dica: "Ligar o servidor: ele escuta na porta 502 enquanto o runtime roda." A porta abre na hora se o runtime está rodando, e o feed diz "Servidor Modbus ligado." | O servidor já está ligado ("O servidor já está ligado."), uma execução segura a estação ou o runtime está parado; a dica traz o motivo. | Sem Configurar Connector. |
| **Desabilitar** | Desliga o servidor: "Desligar o servidor: ele fecha a porta e desconecta todos os clientes." O feed diz "Servidor Modbus desligado." | O servidor já está desligado ("O servidor já está desligado."), uma execução segura a estação ou o runtime está parado. | Sem Configurar Connector. |

Estar ligado é uma configuração que a estação guarda, e a escuta acompanha o runtime:

| Momento | O que o servidor faz |
| --- | --- |
| A estação inicia | Um servidor deixado ligado abre a porta assim que o runtime sobe e as execuções que ele retoma estão de volta; um servidor deixado desligado continua desligado. |
| A porta não pode ser aberta | A linha diz "A porta 502 está em uso" ou "Não foi possível escutar na porta 502", e o cartão Porta e clientes repete isso sob o campo da porta: "A porta 502 está em uso nesta máquina. Feche o que a está segurando, ou escolha outra porta.", ou a mesma falha seguida do motivo que o Windows deu. A estação continua rodando sem ele. O servidor não tenta de novo sozinho: quando a porta estiver livre, desligue e ligue de novo, ou mova-o para outra porta. |
| O runtime é parado | A porta fecha e todos os clientes são desconectados; uma escrita que ainda esperava resposta para de esperar. A linha diz "Runtime parado", e reiniciar o runtime abre a porta de novo. |
| A aplicação fecha | A porta fecha junto com todo o resto. |

## O cartão Porta e clientes {#the-port-and-clients-card}

O primeiro cartão do painel é **Porta e clientes**.

| Campo | O que faz | Valores e padrão |
| --- | --- | --- |
| **Porta TCP** | A porta em que o servidor escuta, em todos os endereços deste computador, IPv4 e IPv6. Mudá-la enquanto o servidor escuta fecha a porta antiga e abre a nova, o que desconecta todos os clientes; o feed diz "Servidor Modbus movido para a porta 5020." | 1 a 65535. Padrão 502, o padrão do Modbus. |
| **Clientes conectados** | Quantos clientes estão conectados agora: "Nenhum cliente conectado", "1 cliente conectado", "3 clientes conectados". Enquanto houver alguém conectado, uma tabela lista cada um com **Endereço do cliente** (o endereço IP e a porta dele, como `192.168.0.20:51234`) e **Conectado desde** (a data e a hora, no formato da estação). | Somente leitura. |

Uma porta para a qual o servidor não pode ir é recusada antes de qualquer coisa ser gravada: o motivo aparece sob o campo, o campo volta para a porta em vigor e o servidor fica onde estava. Seis entradas são recusadas: um número fora da faixa ("A porta precisa estar entre 1 e 65535."); a porta do servidor web, definida em [Acesso remoto](remote-access) ("A porta N já é a do servidor web. Escolha outra porta, ou mova o servidor web antes."); a porta definida para o acesso de agente na página [Agente](agent), esteja o acesso de agente ligado ou desligado ("A porta N já é a do acesso de agente. Escolha outra porta, ou mova o acesso de agente antes."); a porta do servidor OPC UA em [Configuração](connector-opcua-configuration), rodando ou parado ("A porta N já é a do servidor OPC UA. Escolha outra porta, ou mova o servidor antes."); a porta do [broker MQTT](connector-mqtt-broker) na página Connector, ligado ou desligado ("A porta N já é a do broker MQTT. Escolha outra porta, ou mova o broker MQTT antes."); e uma porta que outra coisa nesta máquina segura agora ("A porta N está em uso nesta máquina. Feche o que a está segurando, ou escolha outra porta."). Os outros quatro campos de porta recusam, por sua vez, a porta deste servidor. O motivo fica sob o campo até a próxima porta que o campo aceitar, ou até a linha ser selecionada de novo.

Sob o cartão, uma nota diz: "Responde a qualquer unit id. Outras máquinas só chegam a este servidor se o Firewall do Windows deixar entrar a porta TCP 502: liberar é decisão sua, e esta estação nunca faz isso sozinha."

O servidor aceita no máximo 16 clientes ao mesmo tempo: uma décima sétima conexão é fechada assim que abre, e o diário registra isso. Um cliente que some sem fechar a conexão (um CLP desligado, um cabo puxado) é detectado pelo keep-alive do TCP, e o lugar dele é liberado em cerca de um minuto e meio.

### Firewall do Windows {#windows-firewall}

Sob a nota, um ponto e uma frase declaram se a regra de entrada da própria estação deixa entrar esta porta, como o cartão [Acesso de clientes](connector-opcua-client-access#windows-firewall) declara para a porta OPC UA, com uma ação quando ela não deixa.

| Estado | Texto |
| --- | --- |
| Permitido (verde) | "As conexões Modbus de entrada estão liberadas na porta N para redes privadas e de domínio." |
| Não configurado (âmbar) | "Os clientes da rede podem estar bloqueados porque nenhuma regra deste aplicativo libera a porta N." O botão **Liberar a rede local** é desenhado. |
| Sem suporte (cinza) | "Esta execução não consegue administrar o Firewall do Windows. Configure o acesso de entrada no sistema operacional se for preciso." Uma abertura de desenvolvimento, portátil ou de demonstração, ou qualquer execução que não seja o aplicativo instalado. |
| Desconhecido (cinza) | "Não foi possível determinar a situação do Firewall do Windows." |

| Comando | O que faz | Esmaecido quando (situação) | Não desenhado quando (papel) |
| --- | --- | --- | --- |
| **Liberar a rede local** | Inicia o ajudante do próprio aplicativo com elevação, então o Windows pede aprovação de administrador, e acrescenta a regra para esta porta, com escopo nos perfis Particular e de Domínio, na sub-rede local e neste programa. Diz "Aplicando…" enquanto isso; o feed diz "Pedindo ao Firewall do Windows o acesso à porta Modbus N…", e depois "O Firewall do Windows agora libera as conexões Modbus na porta N." ou o texto de estado como erro. Um pedido de aprovação cancelado deixa o estado em Não configurado. | Num navegador em outro dispositivo ("A regra de firewall só pode ser aplicada pelo aplicativo instalado na estação."), enquanto uma execução segura a estação ou o runtime está parado, e enquanto a regra é aplicada ("A regra de firewall está sendo aplicada."). | Sem Configurar Connector. |

O estado é lido quando o cartão abre e de novo quando a porta muda, então uma porta nova mostra Não configurado até você liberá-la. A estação nunca cria a regra sozinha.

## O mapa de registradores {#the-register-map}

O segundo cartão, **Mapa de registradores**, é o que o servidor serve: cada linha coloca uma tag, uma variável da Logic ou um estado de alarme em um registrador, ou em uma coil, que um cliente endereça. Um registrador que nenhuma linha cobre não existe para um cliente. O cartão diz: "Cada linha serve uma tag, uma variável da Logic ou um estado de alarme em um registrador. Uma linha fica somente leitura até você liberar a escrita, e uma linha que serve um alarme fica sempre. A escrita de um cliente segue então o mesmo caminho de qualquer outra e fica no diário com o endereço do cliente."

### A tabela {#the-table}

| Coluna | O que mostra |
| --- | --- |
| **Classe do registrador** | Registrador de retenção (4xxxx), Registrador de entrada (3xxxx), Bobina (0xxxx) ou Entrada discreta (1xxxx), cada uma com o primeiro dígito que o endereço do manual leva para ela. |
| **Registradores** | O registrador em que a linha começa, contado a partir de 0, e o último que ela ocupa: `0` para uma linha de um registrador, `0-1` para um Float. |
| **No manual** | O mesmo lugar na notação que o manual ou a ferramenta do CLP do cliente escreve: o primeiro dígito da classe e depois o registrador contado a partir de 1. `40001` para o registrador de retenção 0, `de 40001 a 40002` para um Float ali, seis dígitos acima de 9999 (`410000` para o registrador de retenção 9999). |
| **Tipo de dado** | Boolean, Int16, UInt16, Int32, Float ou String. |
| **Acesso** | Somente leitura, ou Leitura e escrita. |
| **Origem** | A origem, como o seletor a nomeia. |
| **Valor atual** | O que um cliente lê ali agora, ou um traço quando um cliente que lê a linha recebe a exceção 04. |

As linhas são listadas por classe (holding registers, registradores de entrada, coils, entradas discretas) e depois por registrador. Sem nenhuma: "Nenhum registrador é servido ainda. Adicione um com Nova linha." Clicar numa linha a seleciona e abre os campos dela sob a tabela; qual linha está selecionada pertence à janela em que você está.

O que faz a tabela crescer e o que encerra uma linha ficam à direita do título do cartão:

| Comando | O que faz | Esmaecido quando (situação) | Não desenhado quando (papel) |
| --- | --- | --- | --- |
| **Nova linha** | Adiciona uma linha no primeiro holding register que nenhuma linha ocupa: Float, as duas caixas de ordem marcadas, somente leitura, ainda sem origem. A linha fica selecionada e o feed diz "Linha adicionada em Registrador de retenção (4xxxx) de 40001 a 40002." Quando não sobra holding register nenhum: "Não sobra nenhum holding register livre para uma nova linha." | Uma execução segura a estação, ou o runtime está parado. | Sem Configurar Connector. |
| **Excluir linha** (tinta de perigo) | Exclui a linha que a tabela tem selecionada, na hora e sem pergunta; a dica a nomeia ("Excluir a linha em Registrador de retenção (4xxxx) de 40001 a 40002") e o feed diz "Linha em Registrador de retenção (4xxxx) de 40001 a 40002 excluída." A tag ou a variável que ela servia não é tocada. Um cliente que lê esses registradores recebe a exceção 02 a partir daí. | Nenhuma linha selecionada ("Selecione uma linha do mapa de registradores para excluí-la."), uma execução segura a estação, ou o runtime está parado. | Sem Configurar Connector. |

### Os campos de uma linha {#a-rows-fields}

Uma linha tem exatamente os campos e as regras de uma [tag Modbus](driver-modbus-tcp#tag-addressing): um ponto aceito numa ponta do fio é aceito na outra. Cada campo é gravado no momento em que muda (um número quando você sai do campo ou tecla Enter, uma escolha quando você escolhe, uma caixa quando você a marca), e um cliente recebe a linha nova a partir da próxima requisição, sem ser desconectado.

| Campo | O que faz | Valores e padrão |
| --- | --- | --- |
| **Classe do registrador** | Em qual tabela do Modbus a linha responde. Escolher uma bobina ou uma entrada discreta faz o tipo virar Boolean; escolher um registrador de entrada ou uma entrada discreta faz a linha virar somente leitura. | Registrador de retenção (4xxxx), Registrador de entrada (3xxxx), Bobina (0xxxx), Entrada discreta (1xxxx). Registrador de retenção numa linha nova. |
| **Número do registrador (começando em 0)** | Onde a linha começa, o número como ele viaja na requisição: o holding register 0 é o que a notação clássica chama de 40001. Ao lado, **Endereço no manual** lê a linha nessa notação, como a coluna **No manual**. | 0 a 65535. O primeiro holding register livre numa linha nova. |
| **Tipo de dado** | Como o valor é disposto, do mesmo jeito que uma tag Modbus o dispõe ([Tipos de valor e quantidades](driver-modbus-tcp#value-types-and-quantities)): Boolean num registrador (1 ou 0) ou como um bit, Int16 e UInt16 num registrador, Int32 e Float em dois, String como UTF-8 com dois bytes por registrador. Uma coil e uma entrada discreta carregam só um Boolean. Escolher Boolean numa linha de registrador a move para uma entrada discreta (somente leitura) ou uma bobina (leitura e escrita); escolher um número numa bobina ou numa entrada discreta a move para um registrador de entrada ou um registrador de retenção, como faz o painel de uma tag Modbus. | Boolean, Int16, UInt16, Int32, Float, String. Float numa linha nova. |
| **Comprimento (registradores)** | Desenhado só para um String: quantos registradores o texto ocupa. | Vazio significa 4. 1 a 65535. |
| **Byte mais significativo primeiro (MSB first, big-endian)** | Qual byte de cada registrador viaja primeiro; as palavras entre parênteses são as que os manuais imprimem. Não desenhado para um String, nem para uma coil ou uma entrada discreta. | Marcado. |
| **Palavra mais significativa primeiro (palavra alta primeiro)** | Qual registrador do par carrega a metade alta. Desenhado só para Int32 e Float. Com as duas caixas marcadas, um Float viaja como `AB CD`, a ordem da especificação ([Ordem de bytes e de palavras](driver-modbus-tcp#byte-and-word-order)); **Ordem dos bytes do valor**, sob as caixas, nomeia o arranjo que elas formam (ABCD, CDAB, BADC ou DCBA). | Marcado. |
| **Acesso** | Se um cliente pode escrever na linha. Num registrador de entrada ou numa entrada discreta, **Leitura e escrita** continua listado e esmaecido, com a dica "Só um holding register ou uma coil aceita escrita." Numa linha que serve um alarme ele também fica esmaecido: "Uma linha que serve um alarme é somente leitura." | **Somente leitura** ou **Leitura e escrita**. Somente leitura numa linha nova. |
| **Origem** | O que a linha serve. A lista abre com "(nenhum)", depois toda tag habilitada de um dispositivo habilitado, nomeada pelo driver, pelo dispositivo e por ela mesma ("Tag do Connector · Simulated · Oven · Temperature"), depois toda variável da Logic que guarda um valor (Booleano, Inteiro, Número decimal, Texto ou Data e hora) pelo nome ("Variável da Logic · Setpoint"), ou, arquivada numa pasta, pelas pastas e pelo nome ("Variável da Logic · Oven / Setpoint"), então duas variáveis de mesmo nome se distinguem. Depois, todo alarme, nomeado do mesmo jeito ("Alarme da Logic · Oven / High temperature"); uma linha que serve um alarme é sempre somente leitura, e serve o estado que **Estado do alarme servido** indica. A linha guarda a origem pela identidade, então renomear a tag ou a variável, ou arquivar o dispositivo numa pasta, deixa a linha no mesmo ponto. Uma origem que a lista não oferece mais continua selecionada e nomeada: uma tag desabilitada como "Tag do Connector · Simulated · Oven · Temperature (desabilitado)", uma tag de um dispositivo desabilitado como "Tag do Connector · Simulated · Oven · Temperature (dispositivo desabilitado)", e só uma origem que não existe mais com o nome Tag ausente ou Variável ausente e a identidade dela. O cartão [Usada por](connector-tags#the-used-by-card) de uma tag lista as linhas que a servem, e o Substituir tudo dele as move para a tag escolhida. | "(nenhum)" numa linha nova. |
| **Estado do alarme servido** | Aparece numa linha que serve um alarme: qual estado dele um cliente lê. **Ativo (Boolean)** vale 1 enquanto a condição vale, **Reconhecido (Boolean)** vale 1 enquanto nada espera reconhecimento, e **Estado (número)** é o estado como número. | Ativo (Boolean) numa nova linha de alarme. |

Sob os campos, três linhas leem a linha de volta: onde ela fica ("Ocupa o registrador 0." ou "Ocupa os registradores 0 a 1."), o que um cliente pode fazer com ela ("Um cliente pode ler esta linha, mas não escrevê-la." ou "Um cliente pode ler e escrever esta linha: cada escrita fica no diário com o endereço dele.", ou "Um cliente lê este estado do alarme e nunca o escreve. Como número, 0 é sem alarme, 1 ativo e não reconhecido, 2 ativo e reconhecido, 3 normalizado e não reconhecido." numa linha que serve um alarme), e o que um cliente lê ali agora ("Valor atual: 21.5"). Quando um cliente que lê a linha não receberia valor nenhum, o motivo vem em seguida:

| O painel diz | Quando |
| --- | --- |
| "Esta linha ainda não serve nada: escolha a origem." | Nenhuma origem foi escolhida. |
| "A origem desta linha não existe mais. Um cliente que a lê recebe a exceção 04." | A tag ou a variável foi excluída. |
| "A origem não tem valor bom agora. Um cliente que lê esta linha recebe a exceção 04 até que ela tenha um." | A tag não tem valor bom (o dispositivo não responde e a tag não apresenta substituto, a tag ou o dispositivo está desabilitado, uma falha de limite deixou a qualidade ruim), ou a variável é uma lacuna. |
| "O valor da origem não cabe no tipo desta linha. Um cliente que a lê recebe a exceção 04." | Um valor que nenhuma linha deste tipo comporta: um NaN numa linha inteira, ou um texto maior do que os registradores da linha. |

### O que uma linha recusa {#what-a-row-refuses}

Uma mudança que as regras do servidor recusam não é gravada: o motivo aparece em vermelho acima dos campos da linha, a mudança fica na tela para você corrigir, e a linha continua servindo o que servia até uma mudança ser aceita. As outras linhas não são afetadas.

| O painel diz | Quando |
| --- | --- |
| "O número do registrador precisa estar entre 0 e 65535." | Um registrador fora da faixa do protocolo. |
| "Um ponto Modbus carrega Boolean, Int16, UInt16, Int32, Float, String." | Um tipo fora desses seis, que só um agente consegue pedir. |
| "Uma coil ou uma entrada discreta carrega um Boolean." | Um número numa coil ou numa entrada discreta, que só um agente consegue pedir. |
| "Um texto ocupa de 1 a 65535 registradores." | Um comprimento de String fora da faixa. |
| "Os registradores 65535 a 65536 passam do registrador 65535." | Uma linha que terminaria depois do último registrador: aqui, um Float em 65535. |
| "Os registradores 40001 a 40002 se sobrepõem à linha em Registrador de retenção (4xxxx) 40002." | Duas linhas da mesma classe dividindo um registrador. |
| "Um registrador de entrada ou uma entrada discreta é somente leitura para um cliente: só um holding register ou uma coil aceita escrita." | Escrita liberada numa classe de entrada, que só um agente consegue pedir. |
| "Uma linha que aceita escrita precisa da tag ou da variável que a recebe." | Leitura e escrita escolhida antes de uma origem, ou a origem voltada para "(nenhum)" numa linha que aceita escrita. Escolha a origem primeiro. |
| "A origem não pode ser escrita: escolha uma tag com acesso de escrita ou uma variável de memória, ou deixe a linha somente leitura." | Escrita liberada numa linha cuja origem é uma tag somente leitura, uma tag de um driver que nunca escreve, uma variável de expressão, ou uma origem que não existe mais. |
| "A origem guarda um texto ou uma data, que só uma linha String carrega." | Uma tag de texto ou de data, ou uma variável Texto ou Data e hora, numa linha de qualquer outro tipo. |
| "Uma linha que serve um alarme é somente leitura: um cliente lê o estado do alarme e nunca o escreve." | Leitura e escrita pedida numa linha que serve um alarme, o que só um agente consegue pedir. |
| "Esta linha do mapa de registradores não existe mais. Recarregue e tente de novo." | A linha foi excluída em outro lugar, em outra janela ou por um agente, enquanto você a editava. |

Enquanto uma execução segura a estação ou o runtime está parado, uma mudança é recusada como toda mudança da página, com o motivo no feed de ações ("A configuração está travada enquanto uma Unidade está em execução.", "Runtime parado"), e nada é gravado.

## O que um cliente lê e escreve {#what-a-client-reads-and-writes}

O servidor responde a qualquer unit id, e responde com o mesmo unit id com que foi perguntado: em TCP, uma estação é endereçada pelo endereço IP. Os números de registrador são contados a partir de 0 como viajam. Uma ferramenta de CLP que conta a partir de 1, ou que escreve a notação clássica, soma o deslocamento por conta própria:

| Classe do registrador | Ler com a função | Escrever com a função | Registrador 0 na notação clássica |
| --- | --- | --- | --- |
| Registrador de retenção (4xxxx) | 3 | 6 (um registrador) ou 16 (vários) | 40001 |
| Registrador de entrada (3xxxx) | 4 | nenhuma: somente leitura | 30001 |
| Bobina (0xxxx) | 1 | 5 (uma coil) ou 15 (várias) | 00001 |
| Entrada discreta (1xxxx) | 2 | nenhuma: somente leitura | 10001 |

Qualquer outro código de função recebe a exceção 01. Uma requisição lê no máximo 125 registradores ou 2000 coils ou entradas, e escreve no máximo 123 registradores ou 1968 coils.

Uma leitura é respondida inteira ou não é respondida. Cada valor é lido do estado atual da estação, nunca avaliado para o cliente: uma tag serve o valor de engenharia, o que a estação mostra depois da [cadeia de valor](connector-value-pipeline), uma variável serve o valor dela, e um alarme o estado que a linha indica. O valor é convertido para o tipo da linha pela conversão única da estação: um real é arredondado para o inteiro mais próximo numa linha inteira (as metades para longe do zero) e segurado nos limites do tipo, então uma linha Int16 serve 32767 para 40000. Uma leitura pode pedir parte de uma linha de dois registradores: recebe os registradores que pediu, como o valor codificado os guarda. Uma linha cuja origem não tem valor bom nunca recebe um último valor guardado pelo servidor: um registrador não carrega qualidade, e um CLP que lesse um número velho agiria sobre um valor que a estação sabe que não é atual. O cliente recebe a exceção 04 no lugar, e o tratamento de falha de comunicação dele decide; o preço é que uma linha sem valor faz falhar uma leitura em bloco que a atravessa, e a coluna Valor atual do mapa aponta qual. Uma tag que apresenta um substituto próprio (o último valor bom mantido, ou um número declarado, definido no estágio [Leitura inválida](connector-value-pipeline)) mantém um valor bom, e o substituto é servido como qualquer valor.

A escrita de um cliente passa pelo mesmo funil único de escrita de todas as outras (veja [Logic](logic#writing-values)): uma tag pela fila de entrega do dispositivo, com o valor de engenharia revertido pela conversão da tag, e uma variável de memória pela fila da Logic. As travas de origem valem: uma origem que uma receita ou um intertravamento do Process em execução segura é recusada. O funil registra no diário cada valor como antigo para novo sob a origem `Modbus client 192.168.0.20:51234`, e a resposta espera o recibo de cada valor, que para uma tag é a resposta do próprio equipamento.

- Uma escrita cobre linhas inteiras: escrever um registrador só de uma linha Float é recusado, então um Float é escrito com a função 16 e uma contagem de 2.
- Toda linha que a escrita alcança é conferida contra o mapa antes de qualquer valor sair: um registrador fora de qualquer linha, ou uma linha somente leitura, recusa a requisição inteira, e nada é escrito.
- Os valores então vão para as origens na ordem dos registradores. Uma recusa que o funil dá a um deles é a resposta que o cliente recebe, embora as outras linhas da mesma requisição também tenham sido entregues.

| Exceção | Quando |
| --- | --- |
| 01 (função ilegal) | Um código de função diferente de 1, 2, 3, 4, 5, 6, 15 e 16. |
| 02 (endereço de dado ilegal) | Um registrador fora de qualquer linha; uma escrita numa linha somente leitura ou em parte de uma linha; uma faixa que passa de 65535; uma origem que o funil de escrita diz que não pode ser escrita. |
| 03 (valor de dado ilegal) | Uma contagem fora da faixa ou uma requisição malformada; uma coil escrita com algo que não seja ligado ou desligado; um valor que a origem não aceita. |
| 04 (falha do dispositivo servidor) | Uma origem sem valor bom, uma origem que não existe mais, ou um valor que a linha não comporta; uma escrita que o equipamento recusou ou não respondeu, ou um dispositivo que não está conectado. |
| 06 (dispositivo servidor ocupado) | Uma origem que um Process em execução segura, ou o runtime parando. |

## Um exemplo completo {#a-worked-example}

Um CLP lê a temperatura de um forno e a chave da porta dele na estação, e escreve o setpoint do forno, uma variável de memória `Variables.Oven.Setpoint`. No painel:

1. Selecione a linha **Servidor Modbus** e pressione **Nova linha**. Defina **Classe do registrador** como Registrador de entrada (3xxxx) (o registrador continua 0) e **Origem** como "Tag do Connector · Simulated · Oven · Temperature". A linha diz "Ocupa os registradores 0 a 1.", **Endereço no manual** mostra de 30001 a 30002, e a coluna Valor atual mostra a temperatura.
2. Pressione **Nova linha** de novo, defina **Classe do registrador** como Entrada discreta (1xxxx) (o tipo vira Boolean e o registrador continua 0) e escolha a chave da porta, "Tag do Connector · Simulated · Oven · DoorOpen".
3. Pressione **Nova linha** uma terceira vez. Ela cai no holding register 0, Float. Escolha primeiro "Variável da Logic · Oven / Setpoint", depois defina **Acesso** como **Leitura e escrita**: a linha diz "Um cliente pode ler e escrever esta linha: cada escrita fica no diário com o endereço dele."
4. Pressione **Habilitar** na barra de comandos: a linha diz "Escutando na porta 502". Para um CLP em outra máquina, pressione depois **Liberar a rede local** no cartão Porta e clientes.

O que o CLP pede, com as duas caixas de ordem marcadas (um Float viaja em big-endian, palavra mais significativa primeiro, `ABCD`):

| Valor | Função | Endereço | Contagem | Notação clássica |
| --- | --- | --- | --- | --- |
| Temperatura (leitura) | 4 | 0 | 2 | 30001-30002 |
| Chave da porta (leitura) | 2 | 0 | 1 | 10001 |
| Setpoint (escrita) | 16 | 0 | 2 | 40001-40002 |
| Setpoint (leitura de volta) | 3 | 0 | 2 | 40001-40002 |

O mesmo com um agente, pelas quatro ferramentas das áreas do Connector:

```text
modbus_map_upsert(source: "Connector.Simulated.Oven.Temperature", registerClass: "InputRegister", register: 0, type: "Float")
modbus_map_upsert(source: "Connector.Simulated.Oven.DoorOpen", registerClass: "DiscreteInput", register: 0)
modbus_map_upsert(source: "Variables.Oven.Setpoint", registerClass: "HoldingRegister", register: 0, type: "Float", access: "ReadAndWrite")
modbus_server_configure(enabled: true)
```

Uma linha criada por um agente é somente leitura a menos que `access` diga outra coisa, e uma coil ou uma entrada discreta é Boolean quando nenhum tipo é dado. `modbus_server_status` lê o servidor inteiro de volta: o estado, os clientes e cada linha com o que um cliente lê ali agora. As ferramentas estão descritas em [As ferramentas, área por área](agent-tools#connector--configure).

## Permissões e travas {#permissions-and-locks}

| Permissão | O que libera aqui |
| --- | --- |
| Ver Connector | A linha, o painel e o mapa de registradores, somente leitura. Os cartões ficam inertes sob a nota "Mudar o Connector exige a permissão “Configurar Connector”.", e nenhum verbo é desenhado: nem Habilitar, nem Desabilitar, nem Nova linha, nem Excluir linha. |
| Configurar Connector | Tudo na página: ligar e desligar o servidor, a porta dele e cada linha do mapa. |

Enquanto uma execução segura a estação ou o runtime está parado, os verbos continuam desenhados e esmaecidos com o motivo, e toda mudança é recusada, como em toda a página [Connector](connector#engineering-boundaries). Ler o painel, e os clientes lendo o servidor, continuam. Um agente altera o servidor só pela área de configuração do Connector no [acesso de agente](agent-areas), e cada mudança que ele faz fica no diário como do agente.

## O diário {#the-journal}

O servidor escreve no console de [Eventos](events-console) sob a área Server, componente Modbus server: quando começa e para de escutar, uma porta que não conseguiu abrir, uma conexão que fechou porque já servia 16 clientes, e toda requisição que recusou, com o código da exceção. Uma recusa que se repete, como a de um CLP que lê a cada ciclo um registrador fora do mapa, é escrita na primeira vez, resumida a cada poucos minutos enquanto dura, e encerrada com uma linha quando o cliente volta a ser atendido. Conexões e desconexões são detalhe, guardado para a [captura detalhada](events-console#detailed-capture). Cada mudança das configurações do servidor ou do mapa também fica no diário, venha da página ou de um agente. O que a escrita de um cliente fez é a linha do próprio funil de escrita, sob a origem `Modbus client <address>:<port>`.

## O que o servidor não faz {#what-the-server-does-not-do}

- Ele serve só Modbus TCP, com o cabeçalho MBAP. Não há servidor Modbus RTU ou ASCII numa linha serial, nem enquadramento RTU sobre TCP.
- Ele nunca abre o Firewall do Windows sozinho (só **Liberar a rede local** faz isso, quando você pressiona), e não consegue escutar numa placa de rede só: escuta em todos os endereços do computador, numa porta.
- Ele responde a qualquer unit id com o mesmo mapa único: não consegue hospedar várias unidades com mapas diferentes.
- Ele não tem usuário, nem senha, nem criptografia, porque o Modbus não tem: quem alcança a porta lê toda linha e escreve em toda linha que aceita escrita. Deixe as linhas somente leitura a menos que um cliente precise escrevê-las, e mantenha a porta fechada para redes que não têm nada a ver com ela.
- Ele nunca se conecta a nada. Para ler um equipamento Modbus, adicione-o sob o driver [Modbus TCP](driver-modbus-tcp) ou [Modbus RTU](driver-modbus-rtu).
- Ele não guarda registradores próprios: um registrador que nenhuma linha cobre não existe, e tudo o que um cliente escreve cai numa tag ou numa variável.
- Ele nunca guarda um valor próprio para servir no lugar de um que falta, e não executa nenhum dos outros códigos de função (Read/Write Multiple Registers, Mask Write Register, identificação do dispositivo): eles recebem a exceção 01.
- O mapa não tem importação nem exportação próprias: ele viaja com a configuração da estação nos [backups](settings-backups).
