# Server Modbus

> Il server Modbus TCP della stazione stessa: la sua riga nella colonna Comunicazione, l'accensione e lo spegnimento, la porta e i client connessi, la mappa dei registri che serve tag, variabili di Logic e stati di allarme, che cosa un client legge e scrive, un esempio completo e che cosa non fa.

Il **Server Modbus** permette a un PLC, a un HMI o a un sistema di building automation che parla solo Modbus TCP di leggere i tag, le variabili di Logic e gli stati di allarme della stazione, e di scrivere i tag e le variabili che si consentono. È la seconda strada per cui i dati lasciano la stazione, accanto al [server OPC UA incorporato](connector-opcua-server), e non è un driver: un driver legge le apparecchiature, mentre il server Modbus viene letto dalle apparecchiature; aspetta che un PLC si colleghi e non si collega mai a nulla. Il suo pannello lo dice sotto il titolo: « Risponde ai PLC, agli HMI e ai sistemi di building automation che leggono e scrivono in Modbus TCP. Riceve le connessioni e non ne apre mai. »

Modbus non porta né nome utente né password: chi raggiunge la porta legge ogni registro che la mappa serve. Per questo il server nasce spento, ogni riga della sua mappa nasce di sola lettura, e la scrittura si consente riga per riga, da parte di qualcuno che l'ha scelto. Visualizzare Connector legge la pagina; Configurare Connector la modifica.

## La riga nella colonna {#the-row-in-the-column}

La riga **Server Modbus** sta sotto la cartella Server dell'albero della colonna Comunicazione, sotto la riga del server OPC UA, con un'icona di server dove i driver mostrano una spina. È sempre presente: una stazione ne ha esattamente una, e non viene mai creata né eliminata. La casella di ricerca la trova per nome, e i chip di stato la classificano secondo il suo stato: **Spenti** finché il server è spento, **Problemi** finché la sua porta è occupata o non è riuscito a mettersi in ascolto, **In ordine** altrimenti. Accanto al nome dice che cosa sta facendo il server, e un punto lo riassume:

| La riga dice | Punto | Quando |
| --- | --- | --- |
| « Spento » | grigio | Il server è spento, ed è così che parte ogni stazione. |
| « In ascolto sulla porta 502 », poi quanti client sono connessi: « Nessun client connesso », « 1 client connesso », « 3 client connessi » | verde | Il server è acceso e il runtime è in esecuzione: la porta è aperta. |
| « La porta 502 è occupata » | rosso | Il server è acceso, ma un altro programma tiene la porta. |
| « Impossibile restare in ascolto sulla porta 502 » | rosso | Il server è acceso, ma Windows ha rifiutato di aprire la porta per un altro motivo. |
| « Runtime fermo » | grigio | Il server è acceso e il runtime è fermo: la porta resta chiusa finché il runtime non torna in esecuzione. |

Il punto è solo del server: non entra nel riepilogo della cartella Driver né nella barra di stato, che parlano delle apparecchiature che la stazione legge. Selezionare la riga apre il pannello del server; la sua intestazione ripete lo stato accanto allo stesso punto. I comandi stanno nella barra dei comandi; la riga non ha un menu proprio.

## Accenderlo e spegnerlo {#turning-it-on-and-off}

| Comando | Che cosa fa | Grigio quando (situazione) | Non disegnato quando (ruolo) |
| --- | --- | --- | --- |
| **Abilita** | Accende il server, come dice il suo suggerimento: « Accendere il server: resta in ascolto sulla porta 502 finché il runtime è in esecuzione. » La porta si apre subito se il runtime è in esecuzione, e il registro delle azioni dice « Server Modbus acceso. » | Il server è già acceso (« Il server è già acceso. »), una prova tiene la stazione, oppure il runtime è fermo; il suggerimento riporta il motivo. | Senza Configurare Connector. |
| **Disabilita** | Spegne il server: « Spegnere il server: chiude la sua porta e scollega tutti i client. » Il registro delle azioni dice « Server Modbus spento. » | Il server è già spento (« Il server è già spento. »), una prova tiene la stazione, oppure il runtime è fermo. | Senza Configurare Connector. |

Essere acceso è un'impostazione che la stazione conserva, e l'ascolto segue il runtime:

| Momento | Che cosa fa il server |
| --- | --- |
| La stazione si avvia | Un server lasciato acceso apre la sua porta appena il runtime è pronto e le prove che riprende sono tornate; un server lasciato spento resta spento. |
| La porta non si può aprire | La riga dice « La porta 502 è occupata » o « Impossibile restare in ascolto sulla porta 502 », e la scheda Porta e client lo dice sotto il campo della porta: « La porta 502 è occupata su questa macchina. Chiudere ciò che la tiene occupata oppure scegliere un'altra porta. », oppure lo stesso errore seguito dal motivo che Windows ha dato. La stazione continua a funzionare senza di lui. Il server non riprova da solo: quando la porta è libera, spegnerlo e riaccenderlo, oppure spostarlo su un'altra porta. |
| Il runtime viene fermato | La porta si chiude e tutti i client vengono scollegati; una scrittura che ancora aspettava la sua risposta smette di aspettare. La riga dice « Runtime fermo », e il riavvio del runtime riapre la porta. |
| L'applicazione si chiude | La porta si chiude insieme a tutto il resto. |

## La scheda Porta e client {#the-port-and-clients-card}

La prima scheda del pannello è **Porta e client**.

| Campo | Che cosa fa | Valori e predefinito |
| --- | --- | --- |
| **Porta TCP** | La porta su cui il server ascolta, su ogni indirizzo di questo computer, IPv4 e IPv6. Cambiarla mentre il server ascolta chiude la vecchia porta e apre la nuova, il che scollega tutti i client; il registro delle azioni dice « Server Modbus spostato sulla porta 5020. » | Da 1 a 65535. Predefinito 502, lo standard di Modbus. |
| **Client connessi** | Quanti client sono connessi adesso: « Nessun client connesso », « 1 client connesso », « 3 client connessi ». Finché qualcuno è connesso, una tabella elenca ciascuno con **Indirizzo del client** (il suo indirizzo IP e la sua porta, per esempio `192.168.0.20:51234`) e **Connesso da** (la data e l'ora, nel formato della stazione). | Sola lettura. |

Una porta su cui il server non può spostarsi viene rifiutata prima che si salvi qualcosa: il motivo compare sotto il campo, il campo torna alla porta in uso e il server resta dov'era. Sei valori vengono rifiutati: un numero fuori intervallo (« La porta deve essere compresa tra 1 e 65535. »); la porta del server web, impostata in [Accesso remoto](remote-access) (« La porta N è già del server web. Scegliere un'altra porta oppure spostare prima il server web. »); la porta dell'accesso agente impostata nella pagina [Agente](agent), che l'accesso agente sia attivo o no (« La porta N è già dell'accesso agente. Scegliere un'altra porta oppure spostare prima l'accesso agente. »); la porta del server OPC UA in [Configurazione](connector-opcua-configuration), in esecuzione o fermo (« La porta N è già del server OPC UA. Scegliere un'altra porta oppure spostare prima il server. »); la porta del [broker MQTT](connector-mqtt-broker) nella pagina Connector, acceso o spento (« La porta N è già del broker MQTT. Scegliere un'altra porta oppure spostare prima il broker MQTT. »); e una porta che qualcos'altro su questa macchina tiene in questo momento (« La porta N è occupata su questa macchina. Chiudere ciò che la tiene occupata oppure scegliere un'altra porta. »). Gli altri quattro campi di porta rifiutano a loro volta la porta di questo server. Il motivo resta sotto il campo fino alla prossima porta che il campo accetta, o finché la riga non viene selezionata di nuovo.

Sotto la scheda, una nota dice: « Risponde a qualsiasi ID unità. Le altre macchine raggiungono questo server solo se Windows Firewall lascia entrare la porta TCP 502: consentirlo è una decisione dell'operatore, e questa stazione non lo fa mai da sola. »

Il server accetta al massimo 16 client alla volta: una diciassettesima connessione viene chiusa appena si apre, e il diario tecnico lo registra. Un client che sparisce senza chiudere la sua connessione (un PLC spento, un cavo staccato) viene rilevato dal keep-alive TCP, e il suo posto si libera in circa un minuto e mezzo.

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

Sotto la nota, un punto e una frase dichiarano se la regola in entrata propria della stazione lascia entrare questa porta, come la scheda [Accesso dei client](connector-opcua-client-access#windows-firewall) lo dichiara per la porta OPC UA, con un'unica azione quando non la lascia entrare.

| Stato | Testo |
| --- | --- |
| Consentito (verde) | « Le connessioni Modbus in entrata sono consentite sulla porta N per le reti private e di dominio. » |
| Non configurato (ambra) | « I client di rete potrebbero essere bloccati perché nessuna regola di proprietà dell'applicazione consente la porta N. » Viene disegnato il pulsante **Consenti la rete locale**. |
| Non supportato (grigio) | « Questo avvio non può gestire il Firewall di Windows. Configurare l'accesso in entrata nel sistema operativo se necessario. » Un avvio di sviluppo, portatile o dimostrativo, oppure qualsiasi esecuzione che non sia l'applicazione installata. |
| Sconosciuto (grigio) | « Non è stato possibile determinare lo stato del Firewall di Windows. » |

| Comando | Che cosa fa | Grigio quando (situazione) | Non disegnato quando (ruolo) |
| --- | --- | --- | --- |
| **Consenti la rete locale** | Avvia con privilegi elevati l'ausiliario proprio dell'applicazione, così Windows chiede l'approvazione dell'amministratore, e aggiunge la regola per questa porta, limitata ai profili Privato e Dominio, alla sottorete locale e a questo programma. Nel frattempo legge « Applicazione… »; il registro delle azioni dice « Richiesta di accesso al Firewall di Windows per la porta Modbus N… », poi « Il Firewall di Windows ora consente le connessioni Modbus sulla porta N. » oppure il testo di stato come errore. Una richiesta di approvazione annullata lascia lo stato Non configurato. | In un browser su un altro dispositivo (« La regola del firewall può essere applicata solo dall'applicazione desktop della stazione. »), mentre una prova tiene la stazione o il runtime è fermo, e mentre la regola viene applicata (« La regola del firewall è in corso di applicazione. »). | Senza Configurare Connector. |

Lo stato viene letto quando la scheda si apre e di nuovo quando la porta cambia, quindi una porta nuova mostra Non configurato finché non la si consente. La stazione non aggiunge mai la regola da sola.

## La mappa dei registri {#the-register-map}

La seconda scheda, **Mappa dei registri**, è ciò che il server serve: ogni riga mette un tag, una variabile di Logic o uno stato di allarme in un registro, o in una coil, che un client indirizza. Un registro che nessuna riga copre non esiste per un client. La scheda dice: « Ogni riga serve un tag, una variabile di Logic o uno stato di allarme a un registro. Una riga resta di sola lettura finché non si consente la scrittura, e una riga che serve un allarme lo resta sempre. La scrittura di un client segue allora lo stesso percorso di ogni altra ed è registrata nel diario tecnico con l'indirizzo del client. »

### La tabella {#the-table}

| Colonna | Che cosa mostra |
| --- | --- |
| **Classe di registro** | Registro di mantenimento (4xxxx), Registro di ingresso (3xxxx), Bobina (0xxxx) o Ingresso discreto (1xxxx), ognuna con la prima cifra che l'indirizzo del manuale porta per lei. |
| **Registri** | Il registro da cui parte la riga, contato da 0, e l'ultimo che occupa: `0` per una riga di un registro, `0-1` per un Float. |
| **Nel manuale** | Lo stesso punto nella notazione che scrive il manuale o lo strumento del PLC del client: la prima cifra della classe e poi il registro contato da 1. `40001` per il registro di mantenimento 0, `da 40001 a 40002` per un Float lì, sei cifre oltre 9999 (`410000` per il registro di mantenimento 9999). |
| **Tipo di dato** | Boolean, Int16, UInt16, Int32, Float o String. |
| **Accesso** | Sola lettura, oppure Lettura e scrittura. |
| **Sorgente** | La sorgente, come la nomina il selettore. |
| **Valore attuale** | Ciò che un client vi legge adesso, oppure un trattino quando un client che legge la riga riceve l'eccezione 04. |

Le righe sono elencate per classe (holding register, registri di ingresso, coil, ingressi discreti), poi per registro. Senza nessuna: « Nessun registro è ancora servito. Aggiungerne uno con Nuova riga. » Fare clic su una riga la seleziona e apre i suoi campi sotto la tabella; quale riga è selezionata appartiene alla finestra in cui ci si trova.

Ciò che fa crescere la tabella e ciò che elimina una riga stanno a destra del titolo della scheda:

| Comando | Che cosa fa | Grigio quando (situazione) | Non disegnato quando (ruolo) |
| --- | --- | --- | --- |
| **Nuova riga** | Aggiunge una riga al primo holding register che nessuna riga occupa: Float, le due caselle d'ordine spuntate, sola lettura, ancora senza sorgente. La riga viene selezionata e il registro delle azioni dice « Riga aggiunta in Registro di mantenimento (4xxxx) da 40001 a 40002. » Quando non resta alcun holding register: « Non resta alcun holding register libero per una nuova riga. » | Una prova tiene la stazione, oppure il runtime è fermo. | Senza Configurare Connector. |
| **Elimina riga** (inchiostro di pericolo) | Elimina la riga che la tabella ha selezionato, subito e senza domande; il suo suggerimento la nomina (« Elimina la riga in Registro di mantenimento (4xxxx) da 40001 a 40002 ») e il registro delle azioni dice « Riga in Registro di mantenimento (4xxxx) da 40001 a 40002 eliminata. » Il tag o la variabile che serviva non viene toccato. Un client che legge quei registri riceve l'eccezione 02 da quel momento. | Nessuna riga selezionata (« Selezionare una riga della mappa dei registri per eliminarla. »), una prova tiene la stazione, oppure il runtime è fermo. | Senza Configurare Connector. |

### I campi di una riga {#a-rows-fields}

Una riga ha esattamente i campi e le regole di un [tag Modbus](driver-modbus-tcp#tag-addressing): un punto accettato a un capo del filo è accettato all'altro. Ogni campo viene salvato nel momento in cui cambia (un numero quando si esce dal campo o si preme Invio, una scelta quando si sceglie, una casella quando la si spunta), e un client riceve la nuova riga dalla sua richiesta successiva, senza essere scollegato.

| Campo | Che cosa fa | Valori e predefinito |
| --- | --- | --- |
| **Classe di registro** | In quale tabella Modbus risponde la riga. Scegliere una bobina o un ingresso discreto porta il tipo a Boolean; scegliere un registro di ingresso o un ingresso discreto rende la riga di sola lettura. | Registro di mantenimento (4xxxx), Registro di ingresso (3xxxx), Bobina (0xxxx), Ingresso discreto (1xxxx). Registro di mantenimento per una nuova riga. |
| **Numero di registro (base 0)** | Dove parte la riga, il numero come viaggia nella richiesta: l'holding register 0 è quello che la notazione classica chiama 40001. Accanto, **Indirizzo nel manuale** legge la riga in quella notazione, come la colonna **Nel manuale**. | Da 0 a 65535. Il primo holding register libero per una nuova riga. |
| **Tipo di dato** | Come il valore è disposto, come lo dispone un tag Modbus ([Tipi di valore e quantità](driver-modbus-tcp#value-types-and-quantities)): Boolean in un registro (1 o 0) o come un bit, Int16 e UInt16 in un registro, Int32 e Float in due, String in UTF-8 con due byte per registro. Una coil e un ingresso discreto portano solo un Boolean. Scegliere Boolean su una riga di registro la sposta in un ingresso discreto (sola lettura) o in una bobina (lettura e scrittura); scegliere un numero su una coil o un ingresso discreto la sposta in un registro di ingresso o in un registro di mantenimento, come fa il pannello di un tag Modbus. | Boolean, Int16, UInt16, Int32, Float, String. Float per una nuova riga. |
| **Lunghezza (registri)** | Disegnato solo per un String: quanti registri occupa il testo. | Vuoto significa 4. Da 1 a 65535. |
| **Byte più significativo per primo (MSB first, big-endian)** | Quale byte di ogni registro viaggia per primo; le parole tra parentesi sono quelle che stampano i manuali. Non disegnato per un String, né per una coil o un ingresso discreto. | Spuntata. |
| **Parola più significativa per prima (parola alta per prima)** | Quale registro della coppia porta la metà alta. Disegnato solo per Int32 e Float. Con le due caselle spuntate, un Float viaggia come `AB CD`, l'ordine della specifica ([Ordine dei byte e delle parole](driver-modbus-tcp#byte-and-word-order)); **Ordine dei byte del valore**, sotto le caselle, nomina la disposizione che formano (ABCD, CDAB, BADC o DCBA). | Spuntata. |
| **Accesso** | Se un client può scrivere la riga. Su un registro di ingresso o un ingresso discreto, **Lettura e scrittura** resta in elenco e in grigio, con il suggerimento « Solo un holding register o una coil accettano scritture. » Su una riga che serve un allarme resta in grigio anche lì: « Una riga che serve un allarme è di sola lettura. » | **Sola lettura** o **Lettura e scrittura**. Sola lettura per una nuova riga. |
| **Sorgente** | Ciò che la riga serve. L'elenco si apre con « (nessuno) », poi ogni tag abilitato di un dispositivo abilitato, chiamato col suo driver, il suo dispositivo e il suo nome (« Tag di Connector · Simulated · Oven · Temperature »), poi ogni variabile di Logic che tiene un valore (Booleano, Intero, Decimale, Testo o Data e ora) col suo nome (« Variabile · Setpoint ») oppure, se archiviata in una cartella, con le sue cartelle e il suo nome (« Variabile · Oven / Setpoint »), così due variabili con lo stesso nome si distinguono. Poi ogni allarme, nominato allo stesso modo (« Allarme · Oven / High temperature »); una riga che serve un allarme è sempre di sola lettura, e serve lo stato indicato da **Stato dell'allarme servito**. La riga tiene la sua sorgente per identità, quindi rinominare il tag o la variabile, o archiviare il suo dispositivo in una cartella, lascia la riga sullo stesso punto. Una sorgente che l'elenco non offre più resta selezionata e nominata: un tag disabilitato come « Tag di Connector · Simulated · Oven · Temperature (disabilitato) », un tag di un dispositivo disabilitato come « Tag di Connector · Simulated · Oven · Temperature (dispositivo disabilitato) », e solo una sorgente che non esiste più come Tag mancante o Variabile mancante con la sua identità. La scheda [Usato da](connector-tags#the-used-by-card) di un tag elenca le righe che lo servono, e il suo Sostituisci tutto le sposta sul tag scelto. | « (nessuno) » per una nuova riga. |
| **Stato dell'allarme servito** | Mostrato per una riga che serve un allarme: quale dei suoi stati legge un client. **Attivo (Boolean)** vale 1 finché la condizione è vera, **Tacitato (Boolean)** vale 1 finché nulla attende la tacitazione, e **Stato (numero)** è lo stato come numero. | Attivo (Boolean) per una nuova riga di allarme. |

Sotto i campi, tre righe rileggono la riga: dove si trova (« Occupa il registro 0. » o « Occupa i registri da 0 a 1. »), che cosa un client può farne (« Un client può leggere questa riga ma non scriverla. » o « Un client può leggere e scrivere questa riga: ogni scrittura è registrata nel diario tecnico con il suo indirizzo. », o « Un client legge questo stato dell'allarme e non lo scrive mai. Come numero, 0 è normale, 1 attivo non tacitato, 2 attivo tacitato, 3 rientrato non tacitato. » per una riga che serve un allarme), e che cosa un client vi legge adesso (« Valore attuale: 21.5 »). Quando un client che legge la riga non riceverebbe alcun valore, segue il motivo:

| Il pannello dice | Quando |
| --- | --- |
| « Questa riga non serve ancora nulla: scegliere la sua sorgente. » | Non è stata scelta alcuna sorgente. |
| « La sorgente di questa riga non esiste più. Un client che la legge riceve l'eccezione 04. » | Il tag o la variabile è stato eliminato. |
| « La sorgente non ha ora un valore valido. Un client che legge questa riga riceve l'eccezione 04 finché non ne ha uno. » | Il tag non ha un valore valido (il suo dispositivo non risponde e il tag non presenta un sostituto, il tag o il suo dispositivo è disabilitato, un superamento dei limiti ne ha resa cattiva la qualità), oppure la variabile è un vuoto. |
| « Il valore della sorgente non rientra nel tipo di questa riga. Un client che la legge riceve l'eccezione 04. » | Un valore che nessuna riga di questo tipo può tenere: un NaN in una riga intera, o un testo più lungo dei registri della riga. |

### Che cosa rifiuta una riga {#what-a-row-refuses}

Una modifica che le regole del server rifiutano non viene salvata: il motivo compare in rosso sopra i campi della riga, la modifica resta sullo schermo perché la si possa correggere, e la riga continua a servire ciò che serviva finché una modifica non viene accettata. Le altre righe non ne risentono.

| Il pannello dice | Quando |
| --- | --- |
| « Il numero di registro deve essere compreso tra 0 e 65535. » | Un registro fuori dall'intervallo del protocollo. |
| « Un punto Modbus porta Boolean, Int16, UInt16, Int32, Float, String. » | Un tipo fuori da questi sei, che solo un agente può chiedere. |
| « Una coil o un ingresso discreto porta un Boolean. » | Un numero in una coil o in un ingresso discreto, che solo un agente può chiedere. |
| « Un testo occupa da 1 a 65535 registri. » | Una lunghezza di String fuori intervallo. |
| « I registri da 65535 a 65536 vanno oltre il registro 65535. » | Una riga che finirebbe oltre l'ultimo registro: qui un Float a 65535. |
| « I registri da 40001 a 40002 si sovrappongono alla riga in Registro di mantenimento (4xxxx) 40002. » | Due righe della stessa classe che condividono un registro. |
| « Un registro di ingresso o un ingresso discreto è di sola lettura per un client: solo un holding register o una coil accettano scritture. » | Scrittura consentita su una classe di ingresso, che solo un agente può chiedere. |
| « Una riga che accetta scritture ha bisogno del tag o della variabile a cui vanno. » | Lettura e scrittura scelta prima di una sorgente, oppure la sorgente riportata a « (nessuno) » su una riga che consente la scrittura. Scegliere prima la sorgente. |
| « La sorgente non si può scrivere: scegliere un tag con accesso in scrittura o una variabile di memoria, oppure lasciare la riga di sola lettura. » | Scrittura consentita su una riga la cui sorgente è un tag di sola lettura, un tag di un driver che non scrive mai, una variabile di espressione o una sorgente che non esiste più. |
| « La sorgente contiene un testo o una data, che solo una riga String porta. » | Un tag di testo o di data, o una variabile Testo o Data e ora, in una riga di qualunque altro tipo. |
| « Una riga che serve un allarme è di sola lettura: un client legge lo stato dell'allarme e non lo scrive mai. » | Lettura e scrittura richiesta su una riga che serve un allarme, cosa che solo un agente può chiedere. |
| « Questa riga della mappa dei registri non esiste più. Ricaricare e riprovare. » | La riga è stata eliminata altrove, in un'altra finestra o da un agente, mentre la si modificava. |

Finché una prova tiene la stazione o il runtime è fermo, una modifica viene rifiutata come ogni modifica della pagina, con il motivo nel registro delle azioni (« La configurazione è bloccata mentre un'unità è in esecuzione. », « Runtime fermo »), e non viene salvato nulla.

## Che cosa un client legge e scrive {#what-a-client-reads-and-writes}

Il server risponde a qualsiasi ID unità, e risponde con l'ID unità con cui è stato interrogato: in TCP una stazione si indirizza col suo indirizzo IP. I numeri di registro viaggiano contati da 0. Uno strumento per PLC che conta da 1, o che scrive la notazione classica, aggiunge da sé lo scostamento:

| Classe di registro | Leggere con la funzione | Scrivere con la funzione | Registro 0 nella notazione classica |
| --- | --- | --- | --- |
| Registro di mantenimento (4xxxx) | 3 | 6 (un registro) o 16 (più registri) | 40001 |
| Registro di ingresso (3xxxx) | 4 | nessuna: sola lettura | 30001 |
| Bobina (0xxxx) | 1 | 5 (una coil) o 15 (più coil) | 00001 |
| Ingresso discreto (1xxxx) | 2 | nessuna: sola lettura | 10001 |

Qualsiasi altro codice di funzione riceve l'eccezione 01. Una richiesta legge al massimo 125 registri o 2000 coil o ingressi, e scrive al massimo 123 registri o 1968 coil.

Una lettura riceve una risposta intera o nessuna. Ogni valore viene letto dallo stato attuale della stazione, mai valutato per il client: un tag serve il suo valore ingegneristico, quello che la stazione mostra dopo la [catena di conversione](connector-value-pipeline), una variabile serve il suo valore, e un allarme lo stato indicato dalla sua riga. Il valore viene convertito nel tipo della riga con la conversione unica della stazione: un reale viene arrotondato all'intero più vicino per una riga intera (le metà lontano da zero) e tenuto entro i limiti del tipo, quindi una riga Int16 serve 32767 per 40000. Una lettura può chiedere una parte di una riga di due registri: riceve i registri chiesti, come li tiene il valore codificato. Una riga la cui sorgente non ha un valore valido non riceve mai un ultimo valore conservato dal server: un registro non porta qualità, e un PLC che leggesse un numero vecchio agirebbe su un valore che la stazione sa non attuale. Il client riceve invece l'eccezione 04, e la sua gestione dei guasti di comunicazione decide; il prezzo è che una riga senza valore fa fallire una lettura a blocco che la attraversa, e la colonna Valore attuale della mappa indica quale. Un tag che presenta un sostituto proprio (l'ultimo valore valido mantenuto, o un numero dichiarato, impostato nella sua fase [Lettura non valida](connector-value-pipeline)) mantiene un valore valido, e il sostituto viene servito come qualunque valore.

La scrittura di un client passa dallo stesso punto unico di scrittura di ogni altra (vedi [Logic](logic#writing-values)): un tag dalla coda di consegna del suo dispositivo, con il suo valore ingegneristico riportato indietro dalla conversione del tag, e una variabile di memoria dalla coda di Logic. I blocchi delle sorgenti valgono: una sorgente che una ricetta o un interblocco di Process in corso tiene bloccata viene rifiutata. Il punto unico di scrittura registra nel diario tecnico ogni valore dal vecchio al nuovo sotto la sorgente `Modbus client 192.168.0.20:51234`, e la risposta aspetta la ricevuta di ogni valore, che per un tag è la risposta dell'apparecchiatura stessa.

- Una scrittura copre righe intere: scrivere un solo registro di una riga Float viene rifiutato, quindi un Float si scrive con la funzione 16 e un conteggio di 2.
- Ogni riga che la scrittura raggiunge viene controllata sulla mappa prima che parta qualunque valore: un registro fuori da ogni riga, o una riga di sola lettura, rifiuta l'intera richiesta, e non viene scritto nulla.
- I valori vanno poi alle loro sorgenti nell'ordine dei registri. Un rifiuto che il punto unico di scrittura dà a uno di essi è la risposta che riceve il client, anche se le altre righe della stessa richiesta sono state consegnate anch'esse.

| Eccezione | Quando |
| --- | --- |
| 01 (funzione non valida) | Un codice di funzione diverso da 1, 2, 3, 4, 5, 6, 15 e 16. |
| 02 (indirizzo dati non valido) | Un registro fuori da ogni riga; una scrittura su una riga di sola lettura o su una parte di riga; un intervallo oltre 65535; una sorgente che il punto unico di scrittura dichiara non scrivibile. |
| 03 (valore dati non valido) | Un conteggio fuori intervallo o una richiesta malformata; una coil scritta con qualcosa che non sia acceso o spento; un valore che la sorgente non può accettare. |
| 04 (guasto del dispositivo server) | Una sorgente senza valore valido, una sorgente che non esiste più, o un valore che la riga non può portare; una scrittura che l'apparecchiatura ha rifiutato o a cui non ha risposto, o un dispositivo non connesso. |
| 06 (dispositivo server occupato) | Una sorgente che un Process in corso tiene bloccata, oppure il runtime che si sta fermando. |

## Un esempio completo {#a-worked-example}

Un PLC legge dalla stazione la temperatura di un forno e il contatto della sua porta, e scrive il setpoint del forno, una variabile di memoria `Variables.Oven.Setpoint`. Nel pannello:

1. Selezionare la riga **Server Modbus** e premere **Nuova riga**. Impostare **Classe di registro** su Registro di ingresso (3xxxx) (il registro resta 0) e **Sorgente** su « Tag di Connector · Simulated · Oven · Temperature ». La riga dice « Occupa i registri da 0 a 1. », **Indirizzo nel manuale** mostra da 30001 a 30002, e la colonna Valore attuale mostra la temperatura.
2. Premere di nuovo **Nuova riga**, impostare **Classe di registro** su Ingresso discreto (1xxxx) (il tipo diventa Boolean e il registro resta 0) e scegliere il contatto della porta, « Tag di Connector · Simulated · Oven · DoorOpen ».
3. Premere **Nuova riga** una terza volta. Arriva sull'holding register 0, Float. Scegliere prima « Variabile · Oven / Setpoint », poi impostare **Accesso** su **Lettura e scrittura**: la riga dice « Un client può leggere e scrivere questa riga: ogni scrittura è registrata nel diario tecnico con il suo indirizzo. »
4. Premere **Abilita** nella barra dei comandi: la riga dice « In ascolto sulla porta 502 ». Per un PLC su un'altra macchina, premere poi **Consenti la rete locale** nella scheda Porta e client.

Ciò che il PLC chiede, con le due caselle d'ordine spuntate (un Float viaggia in big-endian, parola più significativa per prima, `ABCD`):

| Valore | Funzione | Indirizzo | Conteggio | Notazione classica |
| --- | --- | --- | --- | --- |
| Temperatura (lettura) | 4 | 0 | 2 | 30001-30002 |
| Contatto della porta (lettura) | 2 | 0 | 1 | 10001 |
| Setpoint (scrittura) | 16 | 0 | 2 | 40001-40002 |
| Setpoint (rilettura) | 3 | 0 | 2 | 40001-40002 |

Lo stesso con un agente, con i quattro strumenti delle aree del 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)
```

Una riga creata da un agente è di sola lettura a meno che `access` non dica altro, e una coil o un ingresso discreto è Boolean quando non si dà un tipo. `modbus_server_status` rilegge l'intero server: il suo stato, i suoi client e ogni riga con ciò che un client vi legge adesso. Gli strumenti sono descritti in [Gli strumenti, area per area](agent-tools#connector--configure).

## Permessi e blocchi {#permissions-and-locks}

| Permesso | Che cosa apre qui |
| --- | --- |
| Visualizzare Connector | La riga, il pannello e la mappa dei registri, in sola lettura. Le schede restano inerti sotto la nota « Per modificare il Connector serve il permesso “Configurare Connector”. », e nessun verbo viene disegnato: né Abilita, né Disabilita, né Nuova riga, né Elimina riga. |
| Configurare Connector | Tutto nella pagina: accendere e spegnere il server, la sua porta e ogni riga della mappa. |

Finché una prova tiene la stazione o il runtime è fermo, i verbi restano disegnati e in grigio con il motivo, e ogni modifica viene rifiutata, come ovunque nella pagina [Connector](connector#engineering-boundaries). La lettura del pannello, e quella del server da parte dei client, continuano. Un agente modifica il server solo dall'area di configurazione del Connector dell'[accesso agente](agent-areas), e ogni modifica che fa resta registrata come sua.

## Il diario tecnico {#the-journal}

Il server scrive nella [Console](events-console) degli Eventi sotto l'area Server, componente Modbus server: quando inizia e smette di ascoltare, una porta che non è riuscito ad aprire, una connessione che ha chiuso perché serviva già 16 client, e ogni richiesta che ha rifiutato, con il suo codice di eccezione. Un rifiuto che si ripete, come quello di un PLC che a ogni ciclo interroga un registro assente dalla mappa, viene scritto la prima volta, riassunto ogni pochi minuti finché dura, e chiuso con una riga quando il client torna a essere servito. Connessioni e disconnessioni sono un dettaglio, conservato per la [cattura dettagliata](events-console#detailed-capture). Ogni modifica delle impostazioni del server o della sua mappa viene registrata anch'essa, che venga dalla pagina o da un agente. Ciò che la scrittura di un client ha fatto è la riga del punto unico di scrittura stesso, sotto la sorgente `Modbus client <address>:<port>`.

## Che cosa il server non fa {#what-the-server-does-not-do}

- Serve solo Modbus TCP, con l'intestazione MBAP. Non c'è un server Modbus RTU o ASCII su una linea seriale, né trame RTU su TCP.
- Non apre mai Windows Firewall da solo (lo fa solo **Consenti la rete locale**, quando lo si preme), e non può ascoltare su una sola scheda di rete: ascolta su ogni indirizzo del computer, su una porta.
- Risponde a qualsiasi ID unità con la stessa unica mappa: non può ospitare più unità con mappe diverse.
- Non ha utente, né password, né cifratura, perché Modbus non ne ha: chi raggiunge la porta legge ogni riga e scrive ogni riga che consente la scrittura. Lasciare le righe di sola lettura a meno che un client non debba scriverle, e tenere la porta chiusa alle reti che non hanno nulla a che fare con essa.
- Non si collega mai a nulla. Per leggere un'apparecchiatura Modbus, aggiungerla sotto il driver [Modbus TCP](driver-modbus-tcp) o [Modbus RTU](driver-modbus-rtu).
- Non tiene registri propri: un registro che nessuna riga copre non esiste, e tutto ciò che un client scrive finisce in un tag o in una variabile.
- Non tiene mai un valore proprio da servire al posto di uno mancante, e non esegue nessuno degli altri codici di funzione (Read/Write Multiple Registers, Mask Write Register, identificazione del dispositivo): ricevono l'eccezione 01.
- La mappa non ha un'importazione né un'esportazione proprie: viaggia con la configurazione della stazione nei [backup](settings-backups).
