Due programmi che condividono uModbusRTU e uGauge: - Console/PlanciaConsole: plancia nautica descritta da file XML, con modalita' plancia e modalita' configurazione. Comandi, spie, selettori, strumenti e allarmi sonori; il bus gira in un thread suo perche' la finestra non si fermi mai. - ProjectPlancia: il programma di prova piu' vecchio, usato per collaudare i canali. Le plance sono in Console/*.xml, la documentazione in Console/LEGGIMI.md. Esclusi dal versionamento i compilati (.exe, .dcu), i file dell'IDE e un audio da 17 MB. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
741 lines
38 KiB
Markdown
741 lines
38 KiB
Markdown
# PlanciaConsole
|
||
|
||
Plancia configurabile su Modbus RTU / RS485. Due modalità, decise dalla riga di
|
||
comando; la configurazione vive in un file XML letto all'avvio.
|
||
|
||
Riusa `..\uModbusRTU.pas` e `..\uGauge.pas` del programma di test
|
||
(`ProjectPlancia`): i due progetti condividono quei due file, non ne esistono
|
||
copie. Il bus gira in un thread a parte (`uModbusWorker.pas`), così la finestra
|
||
non si ferma mai; vedi "Il bus in un thread a parte".
|
||
|
||
## Avvio
|
||
|
||
PlanciaConsole.exe aboard, legge plancia.xml
|
||
PlanciaConsole.exe aboard
|
||
PlanciaConsole.exe config configurazione
|
||
PlanciaConsole.exe config -f rotta.xml configurazione su un altro file
|
||
PlanciaConsole.exe rotta.xml aboard su un altro file
|
||
|
||
Senza indicazioni viene riaperta l'ultima plancia usata, e in mancanza di
|
||
quella `plancia.xml` accanto all'eseguibile. `-f <percorso>`,
|
||
`-file=<percorso>` o un parametro libero indicano un file diverso.
|
||
|
||
### Modalità aboard
|
||
|
||
Legge l'XML, apre la porta seriale indicata nel file, si connette da sola e
|
||
opera. A vista c'è solo la plancia più una barra di stato con porta, baud, LED
|
||
verde/rosso e ultimo messaggio. Nessun comando di configurazione.
|
||
|
||
La finestra si dimensiona sulla plancia. Se il pannello è più grande dello
|
||
schermo lo zoom si riduce automaticamente per farcelo stare: a bordo è meglio
|
||
una plancia rimpicciolita che una da raggiungere scorrendo.
|
||
|
||
### Cambiare plancia a bordo
|
||
|
||
In fondo a destra, nella barra di stato, una casella elenca le plance della
|
||
stessa cartella del file caricato: tutti gli XML che sono configurazioni di
|
||
plancia, mostrati con il loro titolo. Scegliendone una:
|
||
|
||
- la porta seriale viene chiusa e riaperta con porta e baud del nuovo file;
|
||
- la finestra si ridimensiona sul nuovo pannello;
|
||
- **le bobine non vengono toccate**: i relè restano come sono e la nuova plancia
|
||
ne rilegge lo stato al primo ciclo di polling.
|
||
|
||
Il file viene letto per prova prima di lasciare quello in servizio: se è rotto
|
||
resta la plancia di prima e l'errore compare nella barra di stato.
|
||
|
||
La casella compare solo in aboard e solo se nella cartella ci sono almeno due
|
||
plance. In configurazione si usa "Apri", che chiede anche delle modifiche non
|
||
salvate. Dopo la scelta il fuoco viene tolto alla casella, così le frecce della
|
||
tastiera non cambiano plancia per sbaglio.
|
||
|
||
### Modalità configuration
|
||
|
||
Palette a sinistra, pannello a destra con le proprietà dell'elemento
|
||
selezionato, barra in alto con Nuovo / Apri / Salva / Salva con nome, griglia e
|
||
zoom.
|
||
|
||
- **Inserire**: trascina una voce della palette sul pannello. L'elemento nasce
|
||
centrato sul punto di rilascio; se lì c'è già qualcosa scala in diagonale
|
||
finché trova posto libero, così non si impilano tutti nello stesso punto.
|
||
- **Spostare**: trascina l'elemento. Un click senza trascinare non lo sposta:
|
||
il movimento parte solo oltre la soglia di trascinamento di Windows (pochi
|
||
pixel), e un asse su cui il mouse non si è mosso non viene riagganciato alla
|
||
griglia.
|
||
- **Ridimensionare**: trascina una delle otto maniglie dell'elemento
|
||
selezionato, oppure scrivi larghezza e altezza nel pannello proprietà.
|
||
- **Ritocchi da tastiera**, sull'elemento selezionato: **Ctrl+freccia** lo
|
||
sposta di un pixel, **Maiusc+freccia** cambia le misure di un pixel (destra
|
||
e giù ingrandiscono, sinistra e su rimpiccioliscono). Un pixel esatto anche
|
||
con la griglia attiva. Non funzionano mentre si scrive in una casella, dove
|
||
le frecce restano del testo: cliccare l'elemento riporta i tasti sul pannello.
|
||
- **Annulla / Ripeti**: pulsanti nella barra, oppure **Ctrl+Z** e **Ctrl+Y**
|
||
(o Ctrl+Maiusc+Z). Coprono spostamenti, misure, proprietà, tipo, elementi
|
||
aggiunti e cancellati e le impostazioni generali, fino a 100 passi. Le
|
||
modifiche in fila sulla stessa cosa, entro un secondo e mezzo l'una
|
||
dall'altra, contano come un passo solo: le cifre di una larghezza digitata,
|
||
o Ctrl+freccia tenuto premuto. Lo storico si azzera con Nuovo e Apri.
|
||
Un'immagine rimossa dalla libreria non torna con Annulla: tornano i
|
||
riferimenti degli elementi, ma il file va riaggiunto.
|
||
- **Griglia**: con "Griglia 10 px" attiva posizioni e bordi si agganciano a
|
||
multipli di 10.
|
||
- **Zoom**: da 50% a 200%. È solo una lente di lavoro: le coordinate salvate
|
||
nell'XML restano sempre quelle reali al 100%.
|
||
- **Configurare**: seleziona l'elemento e compila i campi. Le modifiche si
|
||
vedono subito.
|
||
- **Eliminare**: pulsante "Elimina elemento" o tasto Canc.
|
||
- **Chiusura**: chiudendo la finestra la plancia viene **salvata da sola** nel
|
||
file su cui si stava lavorando, senza chiedere niente. Solo se il
|
||
salvataggio non riesce (disco pieno, file di sola lettura) viene chiesto se
|
||
chiudere comunque. Nuovo, Apri e il passaggio in plancia invece continuano a
|
||
chiedere cosa fare delle modifiche: lì si può volerle buttare.
|
||
|
||
**Come viene scritto il file.** Il salvataggio non scrive mai sopra il file
|
||
buono: scrive un `.tmp` accanto e poi scambia i nomi, tenendo la versione
|
||
precedente come `.bak`. Così un programma chiuso male, un disco pieno o due
|
||
copie del programma che salvano insieme non possono lasciare un XML troncato,
|
||
che alla riapertura non si leggerebbe più. Se un file non si apre, accanto c'è
|
||
il `.bak` della volta prima: si rinomina e si riparte da lì.
|
||
|
||
**Se il file non si è aperto**, chiudendo non ci si salva sopra: il programma
|
||
avverte e propone "Salva con nome", perché salvare il pannello vuoto
|
||
cancellerebbe quello che il file contiene.
|
||
|
||
All'avvio senza indicazioni viene riaperta **l'ultima plancia usata**: il
|
||
percorso è ricordato in `plancia-ultima.txt` accanto all'eseguibile, e si
|
||
aggiorna a ogni apertura, salvataggio e cambio di plancia a bordo. Se quel file
|
||
non c'è, o la plancia è stata spostata, si riparte da `plancia.xml`. Un file
|
||
indicato sulla riga di comando ha comunque la precedenza.
|
||
|
||
In configurazione la porta seriale **non** viene aperta: si disegna la plancia
|
||
senza rischiare di comandare relè per sbaglio. Per provare i canali si usa il
|
||
programma di test `ProjectPlancia`.
|
||
|
||
### Passare da una modalità all'altra
|
||
|
||
Chi è partito con `config` trova in fondo a destra, nella barra di stato, un
|
||
pulsante **"Vai in plancia"**: la palette e le proprietà spariscono, la finestra
|
||
si veste sulla plancia e la porta seriale si apre. Da lì il pulsante diventa
|
||
**"Torna a configurare"** e riporta indietro, chiudendo la porta.
|
||
|
||
Serve a provare quello che si è appena disegnato senza chiudere e riaprire il
|
||
programma con un'altra riga di comando.
|
||
|
||
Tre cose da sapere:
|
||
|
||
- Se ci sono modifiche non salvate viene chiesto cosa farne **prima** di passare
|
||
in plancia, altrimenti si perderebbero in silenzio.
|
||
- Tornando a configurare la porta seriale viene **chiusa**, e le spie tornano a
|
||
"dato non disponibile": una plancia che non sta leggendo non deve sembrare in
|
||
servizio.
|
||
- Posizione della finestra e zoom di lavoro vengono ritrovati come li si era
|
||
lasciati, perché in plancia la finestra si ridimensiona sul pannello.
|
||
|
||
**Chi è partito in `aboard` non vede il pulsante.** Una plancia avviata in
|
||
servizio non deve offrire la strada per essere modificata per sbaglio; per
|
||
configurarla si riavvia con `config`.
|
||
|
||
### Modalità notturna
|
||
|
||
Accanto c'è il pulsante **"Notte"**, questo disponibile in entrambe le modalità.
|
||
Scurisce l'intera plancia: fondo quasi nero, immagine di sfondo ricalcolata
|
||
scura, e ogni colore abbassato alla stessa frazione, così i rapporti fra i
|
||
colori restano quelli del giorno e il quadro resta leggibile. Serve in
|
||
navigazione notturna, dove un pannello chiaro a tutto schermo brucia
|
||
l'adattamento al buio e per qualche minuto non si vede più fuori.
|
||
|
||
Le scritte non vengono abbassate ma **sostituite con un ambra**: una serigrafia
|
||
nera abbassata resterebbe nera, cioè invisibile sul fondo scuro. L'ambra è anche
|
||
il colore che disturba meno la visione notturna. Vale per etichette, legende dei
|
||
selettori, marchi e scale dei gauge.
|
||
|
||
Si torna al giorno con lo stesso pulsante, che nel frattempo dice "Giorno". La
|
||
scelta **non** viene salvata nell'XML: è una condizione del momento, non una
|
||
proprietà della plancia.
|
||
|
||
## Tipi di elemento
|
||
|
||
| Tipo | Funzione Modbus | Comportamento |
|
||
|---|---|---|
|
||
| Pulsante | `WriteSingleCoil` (05) | Chiude alla pressione, riapre al rilascio (es. horn) |
|
||
| Interruttore | `WriteSingleCoil` (05) + `ReadCoils` (01) | Commuta alla pressione del mouse e resta premuto |
|
||
| Selettore | `WriteSingleCoil` (05) + `ReadCoils` (01) | Manopola rotativa a 2 o 3 posizioni, anche a ritorno di molla |
|
||
| Spia | `ReadDiscreteInputs` (02) | Sola lettura, LED di colore configurabile |
|
||
| Gauge | `ReadHoldingRegisters` (03) | Colonna con scala, soglie e valore |
|
||
| Display | `ReadHoldingRegisters` (03) | Numero a sette segmenti rossi su fondo nero |
|
||
| Immagine | nessuna | Grafica decorativa: loghi, sagome, cornici |
|
||
| Testo | nessuna | Scritta serigrafata sul pannello |
|
||
|
||
Il campo `channel` è l'indirizzo Modbus della bobina o del registro, `slave`
|
||
l'indirizzo del nodo sul bus. Immagine e Testo non hanno né slave né canale.
|
||
|
||
Gli interruttori e i selettori rileggono le bobine ad ogni ciclo: se un relè
|
||
cambia stato per altra via, o una scrittura non va a segno, il comando a video
|
||
si riallinea. I pulsanti momentanei non vengono riallineati, perché il loro
|
||
stato dipende dal mouse.
|
||
|
||
### All'ingresso in plancia la plancia si allinea al campo
|
||
|
||
Entrando in modalità plancia (all'avvio, tornando dalla configurazione o
|
||
cambiando plancia) la prima lettura serve a mettere tutto nella posizione in
|
||
cui è il campo, non solo a controllare:
|
||
|
||
- **interruttori e selettori** dalle bobine (funzione 01);
|
||
- **pulsanti** dalle bobine, ma **solo in questa prima lettura**: se un canale
|
||
momentaneo è rimasto eccitato va mostrato chiuso, mentre dopo lo stato del
|
||
pulsante lo decide il mouse e rileggerlo lo farebbe lampeggiare;
|
||
- **spie** dagli ingressi digitali (funzione 02), come sempre.
|
||
|
||
**In questa prima lettura le bobine si chiedono una per una**, non a blocco. Un
|
||
blocco che arriva oltre l'ultimo canale del modulo fallisce tutto, e con lui
|
||
fallirebbe l'allineamento anche dei comandi su canali che esistono: chiedendo un
|
||
canale per volta fallisce solo la richiesta del canale che non c'è. Costa un
|
||
giro più lento, una volta sola. Finito l'allineamento si torna alle richieste
|
||
raggruppate, che sono quelle che tengono leggero il polling.
|
||
|
||
Chiudendo il programma non viene scritto niente sul bus: i relè restano come
|
||
sono, ed è la plancia che alla ripartenza si adatta a loro. Quando l'allineamento
|
||
è fatto la barra di stato dice quanti canali sono stati letti, quanti comandi
|
||
risultano chiusi e quanti canali non hanno risposto; se non risponde nessuna
|
||
bobina si riprova al ciclo dopo, invece di dare per aperto quello che non si sa.
|
||
Una spia già in allarme all'avvio fa suonare il suo cicalino.
|
||
|
||
### Più comandi sulla stessa bobina
|
||
|
||
Lo stesso `slave` e `channel` si possono mettere su più elementi: lo stesso relè
|
||
comandato da due punti della plancia, o un pulsante e un interruttore sullo
|
||
stesso circuito. Premendone uno **gli altri si muovono subito**, senza aspettare
|
||
la rilettura: mezzo secondo di disaccordo fra due comandi che sono la stessa cosa
|
||
si nota. Vale in tutte le combinazioni, compresi i selettori (per quelli a 3
|
||
posizioni conta la bobina del lato).
|
||
|
||
Le spie no: leggono gli ingressi digitali, che sono un altro spazio di
|
||
indirizzi, quindi una spia sullo stesso numero di canale di una bobina non è la
|
||
stessa cosa e non viene toccata.
|
||
|
||
Una risposta **più vecchia del comando appena dato** viene scartata. Le letture
|
||
partono a giri regolari e la risposta può arrivare dopo un click: crederle
|
||
farebbe tornare indietro il comando per un giro, e si vedrebbe il comando
|
||
spegnersi, riaccendersi e rispegnersi. Ogni comando segna l'istante in cui ha
|
||
scritto la sua bobina, e le risposte partite prima di quel momento non vengono
|
||
applicate a quella bobina.
|
||
|
||
**Attenzione**: questo riallineamento è anche il motivo per cui un interruttore
|
||
può *sembrare* un pulsante. Se la rilettura della bobina risponde 0 — relè
|
||
assente, indirizzo sbagliato, scrittura non andata a segno — l'interruttore
|
||
torna su da solo entro un ciclo di polling, e a occhio sembra che non resti
|
||
premuto. Il tipo dell'elemento non c'entra: si guarda la barra di stato.
|
||
|
||
### Cambiare tipo dopo il disegno
|
||
|
||
Pulsante, interruttore e spia si scambiano fra loro in qualsiasi momento, dalla
|
||
casella **Tipo** in cima al pannello proprietà, come si fa con la forma o il
|
||
canale. Condividono tutti i campi — canale, colori, forma, immagini, etichetta —
|
||
quindi il passaggio non perde niente. Cambia solo il funzionamento: il pulsante
|
||
chiude il contatto finché lo tieni premuto, l'interruttore commuta e resta, la
|
||
spia non si preme e si accende quando l'ingresso è chiuso.
|
||
|
||
Serve soprattutto per le lenti colorate che sulla foto di un quadro sembrano
|
||
pulsanti ma sono allarmi, come FIRE ALARM e OIL STEERING di ZEBRA.
|
||
|
||
**Attenzione al canale** passando da comando a spia o viceversa: il numero
|
||
resta lo stesso ma cambia significato. Per pulsanti e interruttori è una bobina
|
||
da comandare, per la spia un ingresso digitale da leggere (funzione 02), che di
|
||
solito sta su un altro modulo. La barra di stato lo ricorda al momento del
|
||
cambio.
|
||
|
||
Cambiando tipo l'elemento riparte da spento, perché un pulsante non viene più
|
||
riletto dal campo e resterebbe illuminato per sempre. Se l'etichetta era
|
||
ancora quella predefinita segue il nuovo tipo, altrimenti resta la tua.
|
||
|
||
### Selettore rotativo
|
||
|
||
La leva **ruota**: passando da una posizione all'altra si vede girare, sempre
|
||
passando per l'alto, in 130 millisecondi con partenza e arrivo morbidi. È solo
|
||
quello che si vede: il comando sul bus parte subito, all'inizio del movimento.
|
||
In configurazione la leva sta ferma dove dice la definizione.
|
||
|
||
Si "gira" premendo dal lato verso cui lo si vuole portare: pressione a sinistra
|
||
della manopola per scendere di una posizione, a destra per salire. La legenda
|
||
sopra la manopola è testo libero (`OFF ◄ 0 ► ON`, `STOP ◄ 0 ► START`, …).
|
||
|
||
Il cablaggio dipende dal numero di posizioni:
|
||
|
||
- **2 posizioni**: una bobina, quella di `channel`. Chiusa = posizione destra.
|
||
- **3 posizioni**: **due bobine**, `channel` e (salvo indicazione) `channel+1`.
|
||
La prima chiusa = posizione sinistra, la seconda chiusa = destra, entrambe
|
||
aperte = centro (0).
|
||
|
||
Quindi un selettore a 3 posizioni **occupa due canali**: nel numerare i canali
|
||
va lasciato il buco.
|
||
|
||
Per configurarlo: tipo Selettore, **Posizioni = 3**, e in **Canale** la bobina
|
||
del lato sinistro. La bobina di destra si imposta nel riquadro "Selettore", in
|
||
**Canale lato destro**: lasciandolo vuoto è il canale successivo (l'etichetta
|
||
ricorda quale sarebbe), e si compila solo quando sul modulo le due bobine non
|
||
sono contigue. Nell'XML è l'attributo `channel2`, scritto solo se indicato.
|
||
|
||
Il suggerimento a comparsa dell'elemento mostra entrambe le bobine.
|
||
|
||
#### Ritorno a molla
|
||
|
||
Con **Ritorno a molla** spuntato (nell'XML `momentary="true"`) il selettore non
|
||
resta dove lo porti: tiene la posizione finché lo tieni premuto e torna al
|
||
centro appena lasci il mouse, aprendo entrambe le bobine. È il comando di
|
||
avviamento dei quadri veri, `STOP ◄ 0 ► START`: si tiene su START finché il
|
||
motore parte, e si molla.
|
||
|
||
- Si preme direttamente dal lato voluto, senza passare per lo zero.
|
||
- Al rilascio torna al centro **sempre**, anche se il mouse è finito fuori
|
||
dall'elemento e anche se la scrittura di andata era fallita: un comando di
|
||
avviamento non deve mai restare eccitato.
|
||
- Finché è premuto il polling non lo sposta, altrimenti una lettura arrivata in
|
||
quell'istante lo farebbe scattare al centro sotto il dito.
|
||
- Vale anche a 2 posizioni: premuto = chiusa, lasciato = aperta.
|
||
|
||
In `antago.xml` e in `plancia-mfd.xml` è così il selettore **GENERATOR**.
|
||
|
||
Le due bobine **non vengono mai chiuse insieme**: a ogni cambio di posizione si
|
||
apre prima quella del lato opposto e solo dopo si chiude l'altra. Se la seconda
|
||
scrittura fallisce il selettore resta al centro, con tutte e due aperte. Questa
|
||
però è una protezione del programma: se i due lati comandano qualcosa che non
|
||
deve mai partire insieme (due sensi di marcia, due alimentazioni), serve
|
||
comunque l'interblocco elettrico fra i due relè.
|
||
|
||
### Gauge a quadrante
|
||
|
||
Con `style="dial"` il gauge non è una colonna ma uno strumento a lancetta, come
|
||
quelli dei display di plancia: scala su 270 gradi con tacche e numeri, lancetta,
|
||
e sotto il perno la lettura in cifre con le unità (`decimals` ne fissa i
|
||
decimali). Se l'elemento è più alto che largo il titolo va sotto al quadrante,
|
||
altrimenti dentro.
|
||
|
||
La fascia della scala è grigia. Con `warnBelow` / `warnAbove` impostati diventa
|
||
verde nell'intervallo buono e rossa fuori: senza soglie resta grigia, perché un
|
||
quadrante tutto verde direbbe "tutto a posto" senza saperlo. Senza dato valido
|
||
la lancetta non c'è e la lettura mostra `---`.
|
||
|
||
Stile e decimali del quadrante per ora si impostano solo nell'XML; il pannello
|
||
proprietà non li mostra ma il salvataggio li conserva.
|
||
|
||
### Display
|
||
|
||
Mostra il registro scalato in unità reali, allineato a destra sul numero di
|
||
cifre richiesto, con zeri davanti come i display veri. `digits` è il numero di
|
||
cifre, `decimals` quante dopo la virgola. Senza dato valido i segmenti restano
|
||
tutti spenti.
|
||
|
||
### Spia
|
||
|
||
Il colore da accesa si imposta con l'attributo `color` (`#RRGGBB`): rosso per
|
||
gli allarmi, verde per i consensi, giallo e arancio per i livelli. Se
|
||
l'etichetta è vuota il LED — o l'immagine PNG che lo sostituisce — occupa tutto
|
||
l'elemento, così si possono appoggiare spie piccole sopra una grafica. Vale per
|
||
qualunque elemento con l'etichetta fuori dal disegno: senza etichetta non viene
|
||
riservata nessuna fascia.
|
||
|
||
#### Allarme sonoro
|
||
|
||
Ogni spia può far suonare qualcosa quando si accende. Nel pannello proprietà,
|
||
riquadro **Allarme sonoro**:
|
||
|
||
- **Suona quando si accende**: la casella che accende o spegne l'allarme.
|
||
- **File**: si sceglie fra i suoni presenti nella cartella **`suoni\` accanto
|
||
al file XML della plancia** (MP3 e WAV). Come per le immagini, i suoni
|
||
viaggiano con la plancia quando si copia la cartella.
|
||
- **Aggiorna**: rilegge la cartella. Serve quando si aggiunge un file mentre il
|
||
programma è già aperto, senza doverlo riavviare.
|
||
|
||
Nell'XML sono gli attributi `alarm="true"` e `sound="cicalino.mp3"` sulla spia.
|
||
Il nome del file resta salvato anche con l'allarme spento, così si può
|
||
riaccendere senza riscegliere il suono.
|
||
|
||
Come suona:
|
||
|
||
- **Parte sul fronte**, quando la spia passa da spenta ad accesa, e poi **va in
|
||
ciclo**: finito il file ricomincia, e continua finché l'allarme c'è. Un
|
||
cicalino che suona una volta sola lo si perde se in quel momento si sta
|
||
guardando altrove. Si ferma quando l'allarme rientra, quando lo si zittisce
|
||
premendo la spia, o lasciando la plancia.
|
||
- **Se l'allarme è già attivo all'avvio** suona appena arriva la prima lettura:
|
||
una plancia che parte con una sentina piena deve dirlo.
|
||
- **Non blocca niente**: il suono va per conto suo, la plancia resta comandabile.
|
||
- Due allarmi diversi si sovrappongono; lo stesso allarme che si ripete riparte
|
||
da capo.
|
||
- **Quando l'allarme rientra il suono si ferma subito**, senza aspettare la
|
||
fine del file: serve per i suoni lunghi, una sirena che continua a suonare
|
||
su un allarme già passato è peggio del silenzio. Se lo stesso file è
|
||
assegnato a più spie, tace solo quando si è spenta l'ultima ancora accesa.
|
||
- **Se il file manca o non si può suonare**, la barra di stato lo dice: un
|
||
cicalino muto senza avviso è peggio di nessun cicalino.
|
||
- Uscendo dalla plancia (torna a configurare, chiusura) i suoni si fermano.
|
||
|
||
#### Zittire un allarme
|
||
|
||
**Si preme la spia che sta suonando**: è il gesto che viene naturale, si preme
|
||
quello che dà fastidio. Ogni pressione allunga il silenzio:
|
||
|
||
| Pressioni | Silenzio |
|
||
|---|---|
|
||
| 1 | un minuto |
|
||
| 2 | dieci minuti |
|
||
| 3 | un'ora |
|
||
| 4 | allarme di nuovo attivo |
|
||
|
||
Le pressioni contano finché il silenzio dura: dopo che è scaduto si ricomincia
|
||
da un minuto. Il suono in corso si ferma subito alla prima pressione.
|
||
|
||
**Il silenzio non spegne la spia**: il LED resta acceso, con una sbarra sopra,
|
||
perché guardando il quadro si deve capire che quell'allarme c'è ancora e sta
|
||
suonando a vuoto. Premere una spia spenta, o una senza allarme, non fa niente.
|
||
|
||
**Quando il silenzio scade, se la condizione è ancora presente l'allarme torna
|
||
a suonare**: è il senso di zittire "per un minuto" invece che per sempre.
|
||
|
||
In basso a destra, nella barra di stato, compare il tasto **"N allarmi zittiti
|
||
(tempo) — riattiva"**, che dice quanti sono e quanto manca al primo che torna a
|
||
suonare. Premendolo si riattivano tutti subito, e quelli ancora presenti
|
||
suonano di nuovo. Il tasto si vede solo finché c'è almeno un allarme zittito.
|
||
|
||
Se l'allarme rientra da solo, il silenzio si azzera con lui: la volta dopo si
|
||
riparte da un minuto. Tornando a configurare, o cambiando plancia, i silenzi si
|
||
azzerano tutti.
|
||
|
||
In `suoni\` c'è `cicalino.wav`, due bip generati per provare subito; va
|
||
sostituito con il suono vero.
|
||
|
||
La spia accetta anche la forma (`shape`) dei pulsanti, per somigliare alle
|
||
lenti di allarme dei quadri:
|
||
|
||
- **`round`** — ghiera metallica e lente tonda. Spenta la lente resta del suo
|
||
colore ma scura (`colorOff`, o `color` scurito se manca), accesa prende
|
||
`color` pieno con un riflesso. La ghiera non cambia: è una spia, non un
|
||
comando premuto.
|
||
- **`screen`** — tasto a video che si riempie di `color` quando l'ingresso è
|
||
chiuso.
|
||
- le altre forme — il LED tondo di sempre.
|
||
|
||
In ogni forma cliccare una spia non fa nulla e non manda niente sul bus.
|
||
|
||
### Aspetto di pulsanti, interruttori e spie
|
||
|
||
**La lente di un pulsante o di un interruttore non cambia mai colore.** Lo stato
|
||
si legge solo dal bordo, come su un quadro vero, dove il vetro è sempre dello
|
||
stesso colore e quello che cambia è la luce dietro.
|
||
|
||
- Forma **tonda**: la ghiera attorno alla lente è grigia a riposo e diventa
|
||
**azzurra luminosa** quando il comando è acceso, o mentre un pulsante è tenuto
|
||
premuto — più chiara contro la lente e più carica all'orlo, come se la luce
|
||
venisse da dentro.
|
||
- Forma **squadrata o a pillola**: non c'è ghiera, quindi è il bordo stesso che
|
||
si ingrossa e prende lo stesso azzurro.
|
||
|
||
Il colore della lente è **`colorOff`**. Su pulsanti e interruttori `color` non
|
||
tocca più il vetro: resta usato dalle spie, dove il cambio di colore è tutto
|
||
quello che c'è da vedere. Anche l'etichetta scritta *dentro* al comando resta
|
||
uguale: prima diventava bianca e in grassetto da acceso, ed era un secondo modo
|
||
di dire la stessa cosa che ora dice il bordo.
|
||
|
||
Tre attributi permettono di far somigliare i comandi a quelli del quadro vero,
|
||
e si impostano anche dal riquadro "Aspetto" del pannello proprietà:
|
||
|
||
- **`shape`** — `auto` (pillola per i pulsanti, squadrato per gli
|
||
interruttori), `round`, `rect`, `pill`, `screen`. I quadri di bordo hanno
|
||
quasi sempre pulsanti tondi: con `round` l'elemento viene disegnato con
|
||
ghiera metallica e lente, come un pulsante illuminato da incasso.
|
||
`screen` ("a video") è il tasto di un display multifunzione ed è l'eccezione
|
||
alla regola della lente: spento è un riquadro scuro con il filo chiaro
|
||
(`colorOff` per tingerlo), acceso **si riempie** del colore `color`. La
|
||
scritta sopra passa da chiara a nera quando il fondo diventa chiaro.
|
||
- **`captionPos`** — `center` (etichetta scritta sul comando), `below`,
|
||
`above`. Sui quadri veri l'etichetta è serigrafata **sotto** al pulsante:
|
||
con `below` il disegno si restringe per farle posto e il testo resta nero
|
||
sulla lamiera invece di stare sopra la lente. Le etichette lunghe vanno a
|
||
capo e la fascia si allarga da sola.
|
||
- **`color`** e **`colorOff`** — colore della lente accesa e a riposo. Serve
|
||
perché un pulsante STOP è rosso anche da spento e si limita a illuminarsi:
|
||
senza `colorOff` la lente a riposo è grigio-azzurra neutra.
|
||
|
||
### Testo e marchi
|
||
|
||
L'elemento Testo non serve solo alle scritte: con una cornice diventa un
|
||
marchio serigrafato, disegnato **con il font e non con un'immagine**, quindi
|
||
nitido a qualsiasi zoom invece di sgranare come farebbe un PNG ingrandito.
|
||
|
||
- **`fontName`** — nome del font, per esempio `Times New Roman` o
|
||
`Arial Black`. Vuoto = quello del pannello. Funziona su qualsiasi elemento,
|
||
non solo sul Testo.
|
||
- **`spacing`** — pixel in più fra una lettera e l'altra. I marchi hanno quasi
|
||
sempre le lettere larghe e senza questo non somigliano.
|
||
- **`frame`** — `none`, `oval`, `rect`, `round` (rettangolo stondato, cioè a
|
||
pastiglia). Disegnata con GDI+ in antialiasing, altrimenti un ovale grande
|
||
verrebbe scalettato.
|
||
- **`frameWidth`** — spessore del tratto della cornice.
|
||
- **`color`** — colore di inchiostro e cornice.
|
||
|
||
Un marchio su più righe si compone sovrapponendo più elementi: uno con la sola
|
||
cornice (etichetta vuota), uno con il nome in grande, uno con il sottotitolo
|
||
piccolo. È così che sono fatti i loghi ZEBRA e ANTAGO negli esempi.
|
||
|
||
Per andare a capo dentro un'etichetta si usa ` `, per esempio
|
||
`caption="PORT ENGINE"`.
|
||
|
||
## Immagini
|
||
|
||
La libreria immagini è nel pannello di sinistra: "Aggiungi..." accetta PNG, JPG
|
||
e BMP (selezione multipla), "Rimuovi" toglie l'immagine e la sgancia dagli
|
||
elementi che la usavano, chiedendo conferma.
|
||
|
||
Non è una `TImageList`: quella imporrebbe a tutte le immagini la stessa
|
||
dimensione, mentre qui un LED da 32 px e un logo da 600 px devono convivere.
|
||
|
||
**Nell'XML si salvano nome e percorso, non i pixel.** I file restano sul disco e
|
||
si possono sostituire senza toccare la configurazione. I percorsi sono relativi
|
||
alla cartella del file XML quando possibile, così l'intera plancia si trasporta
|
||
copiando una cartella; "Salva con nome" in un'altra cartella ricalcola i
|
||
percorsi da solo.
|
||
|
||
Dove si usano:
|
||
|
||
- **Pulsante, interruttore, spia**: due immagini, a riposo e attiva. Se il campo
|
||
"immagine a riposo" è vuoto si torna al disegno vettoriale predefinito. Se è
|
||
valorizzata solo quella a riposo, l'elemento non cambia aspetto quando si
|
||
attiva.
|
||
- **Immagine**: una sola, decorativa.
|
||
- **Sfondo del pannello**: si sceglie in "Generale → Immagine di sfondo", ed è
|
||
stirata su tutto il pannello.
|
||
|
||
Le PNG con trasparenza funzionano: gli elementi non riempiono il proprio sfondo,
|
||
quindi un logo con alpha si fonde con lo sfondo della plancia.
|
||
|
||
L'etichetta continua a essere scritta sopra l'immagine, in bianco con contorno
|
||
nero perché resti leggibile su fondo chiaro e scuro; sulle spie va in basso per
|
||
non coprire il LED. Se l'immagine contiene già la scritta, basta svuotare il
|
||
campo Etichetta.
|
||
|
||
Se un file manca o non si apre, nella libreria il nome compare seguito da `[!]`
|
||
e l'elemento mostra un riquadro tratteggiato in configurazione.
|
||
|
||
## Il file XML
|
||
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<plancia version="1">
|
||
<connection port="COM1" baud="9600" timeoutMs="500" pollMs="500"/>
|
||
<panel title="Plancia ZEBRA" width="980" height="560" background="sfondo"/>
|
||
<images>
|
||
<image name="sfondo" file="immagini\sfondo.png"/>
|
||
<image name="btn-off" file="immagini\btn-off.png"/>
|
||
<image name="btn-on" file="immagini\btn-on.png"/>
|
||
</images>
|
||
<elements>
|
||
<element kind="button" caption="HORN" slave="1" channel="5"
|
||
left="40" top="60" width="180" height="70"
|
||
imageOff="btn-off" imageOn="btn-on"/>
|
||
<element kind="image" caption="" image="logo-zebra"
|
||
left="620" top="440" width="320" height="90"/>
|
||
<element kind="gauge" caption="Serbatoio" slave="5" channel="1"
|
||
left="640" top="200" width="130" height="200"
|
||
rawMin="0" rawMax="4095" engMin="0" engMax="100"
|
||
units="%" warnBelow="15" warnAbove="1E30"/>
|
||
</elements>
|
||
</plancia>
|
||
|
||
`kind` vale `button`, `switch`, `rotary`, `lamp`, `gauge`, `display`, `image`
|
||
o `label`.
|
||
|
||
- `fontSize`: altezza del testo in pixel logici; assente = font del pannello.
|
||
- `imageOff` / `imageOn`: nomi presi da `<images>`; solo per pulsanti,
|
||
interruttori e spie.
|
||
- `image`: l'immagine dell'elemento decorativo.
|
||
- `background` su `<panel>`: immagine di sfondo.
|
||
- `ink` su `<panel>`: colore della serigrafia, `#RRGGBB`, nero se assente.
|
||
Vale per etichette sotto/sopra i comandi, legende e titoli di selettori,
|
||
display e quadranti, e per i `label` senza `color`. Le plance a fondo scuro
|
||
lo mettono chiaro. Si imposta solo nell'XML.
|
||
- `style` (`bar` o `dial`) e `decimals`: aspetto del `gauge`, vedi sopra.
|
||
- `color` / `colorOff`: colore acceso e a riposo di spie, pulsanti e
|
||
interruttori, `#RRGGBB`. Su `label` è il colore di inchiostro e cornice.
|
||
- `shape` e `captionPos`: forma del comando e posizione dell'etichetta.
|
||
- `fontName` e `spacing`: font e spaziatura fra le lettere.
|
||
- `frame` e `frameWidth`: cornice attorno a un `label`.
|
||
- `alarm` e `sound`: solo per `lamp`, allarme sonoro all'accensione; il file
|
||
sta nella cartella `suoni\` accanto all'XML.
|
||
- `positions` (2 o 3), `legend`, `channel2` e `momentary`: solo per `rotary`.
|
||
`channel2` è la bobina del lato destro di un selettore a 3 posizioni;
|
||
assente = `channel+1`. `momentary="true"` è il ritorno a molla.
|
||
- `digits` e `decimals`: solo per `display`.
|
||
- `raw*`, `eng*` e `units` valgono per `gauge` e `display`:
|
||
`rawMin`/`rawMax` sono il fondo scala del modulo (4095 = ADC a 12 bit),
|
||
`engMin`/`engMax` i valori reali corrispondenti.
|
||
- `warnBelow` / `warnAbove`: solo per `gauge`, sono le soglie oltre le quali la
|
||
colonna diventa rossa (`-1E30` e `1E30` significano "soglia non impostata").
|
||
|
||
I numeri decimali si scrivono con il punto. Il file si può modificare a mano:
|
||
un attributo mancante prende il valore di default. Per i caratteri speciali
|
||
nelle legende si usano le entità XML, per esempio `◀` e `▶` per le
|
||
frecce ◄ ►.
|
||
|
||
## File di esempio
|
||
|
||
- `esempio-plancia.xml` — solo elementi vettoriali, nessuna immagine.
|
||
- `esempio-immagini.xml` — usa la cartella `immagini\`: sfondo, logo con
|
||
trasparenza, pulsante e LED con grafica. Le immagini sono segnaposto generate
|
||
per la prova, da sostituire con quelle vere.
|
||
- `antago.xml` — riproduzione del quadro elettrico ANTAGO, ricavata dalla foto
|
||
del quadro reale. Il pannello è 1270×950 come la foto, così ogni elemento sta
|
||
dove sta sul quadro vero.
|
||
- `zebra.xml` — riproduzione della pulsantiera ZEBRA: 7 colonne × 6 righe di
|
||
pulsanti tondi illuminati, i due selettori delle ventole, i comandi motore
|
||
con gli ovali PORT/STBD ENGINE e il selettore PARALLEL a tre posizioni.
|
||
La foto è in prospettiva, quindi la griglia è stata ridisegnata dritta
|
||
(passo 120 in orizzontale, 145 in verticale); etichette, forme e colori delle
|
||
lenti vengono dalla foto.
|
||
|
||
- `plancia-mfd.xml` — tutti i comandi, le spie e le misure di ZEBRA e ANTAGO
|
||
su una sola plancia, nello stile della foto `immagini\Esempio plancia.jpg`:
|
||
cornice scura con tasti a video ai lati, schermo nero con quattro quadranti,
|
||
i due display dei caricabatterie, il sinottico della barca con le spie e i
|
||
tasti illuminati di motori e servizi; sotto, due file di selettori. Pannello
|
||
1900×1080. Gli indirizzi di ZEBRA sono quelli di `zebra.xml`; **le bobine
|
||
di ANTAGO sono spostate da slave 1 a slave 4**, perché sullo slave 1 si
|
||
sovrapponevano a quelle di ZEBRA, e i due comandi di prova "Luce" e "Horn"
|
||
di `antago.xml` (che stavano sul canale 0, lo stesso del selettore
|
||
VOLTMETER) sono sui canali 26 e 27 dello slave 4.
|
||
|
||
In tutti **slave e canali sono inventati** e vanno rimappati sui moduli
|
||
reali prima di collegare il bus.
|
||
|
||
## Strumenti
|
||
|
||
`strumenti\` contiene gli script PowerShell usati per preparare la grafica dei
|
||
due quadri:
|
||
|
||
| Script | Cosa fa |
|
||
|---|---|
|
||
| `ruota.ps1` | Raddrizza una foto scattata in verticale |
|
||
| `ritaglia-grafica.ps1` | Ritaglia un pezzo di serigrafia dalla foto e rende trasparente il fondo chiaro, lasciando solo il tratto |
|
||
| `genera-sfondo.ps1` | Disegna la lamiera del pannello con cornice e viti, di qualsiasi misura |
|
||
| `genera-mfd.ps1` | Disegna cornice e schermo di `plancia-mfd.xml` e la sagoma della barca ANTAGO in chiaro per il fondo nero |
|
||
|
||
Il ritaglio dalla foto conviene solo per i disegni che non si possono
|
||
ricostruire, come la sagoma della barca del quadro ANTAGO. **Le scritte no**:
|
||
i marchi ZEBRA e ANTAGO e gli ovali PORT/STBD ENGINE sono elementi Testo con
|
||
font e cornice, non immagini, così restano nitidi a ogni ingrandimento.
|
||
|
||
### Diagnostica del bus
|
||
|
||
Due programmi a riga di comando servono quando un modulo non si legge. Vanno
|
||
lanciati **con PlanciaConsole chiusa**, perché la porta si apre una volta sola.
|
||
Si ricompilano con i `build-*.bat` accanto ai sorgenti.
|
||
|
||
| Programma | Cosa fa |
|
||
|---|---|
|
||
| `scanbus.exe [porta] [baud] [ultimoIndirizzo]` | Interroga gli indirizzi uno per uno e dice chi risponde, con quali funzioni e che dati |
|
||
| `dumpframe.exe [porta] [baud] [slave] [funzione] [start] [quantità]` | Manda una sola richiesta e stampa i byte grezzi della risposta con la verifica della CRC |
|
||
| `monitorio.exe [porta] [baud] [slave] [canali] [cicli]` | Mostra gli ingressi digitali in tempo reale, una riga ad ogni cambiamento |
|
||
| `ringtest.exe [file.bmp]` | Disegna i comandi tondi spenti e accesi a tre misure e salva l'immagine: serve a giudicare una modifica ai colori guardandola |
|
||
|
||
`scanbus` serve a trovare l'indirizzo di un modulo appena montato. `dumpframe`
|
||
serve quando `scanbus` dà risultati incoerenti: mostrando il frame byte per byte
|
||
distingue un modulo che non risponde da due moduli che rispondono insieme.
|
||
|
||
**Due nodi con lo stesso indirizzo** è il guasto più frequente quando si
|
||
aggiunge un modulo: i moduli escono quasi tutti con indirizzo 1, e sul bus le
|
||
due risposte si sovrappongono. Il sintomo è una risposta di lunghezza variabile,
|
||
spesso con byte a zero in testa, e la CRC che non torna.
|
||
|
||
## Il bus in un thread a parte
|
||
|
||
Il thread principale non parla mai con la porta seriale. Tutto il Modbus vive
|
||
in un thread suo (`uModbusWorker.pas`), che apre la COM, fa le letture e le
|
||
scritture, e lascia i risultati in una cassetta condivisa. La finestra li
|
||
ritira con il suo timer. Così un timeout — mezzo secondo per richiesta — costa
|
||
tempo al thread del bus e non alla plancia, che resta trascinabile, ridisegnabile
|
||
e cliccabile anche con tutti i moduli staccati.
|
||
|
||
**Un thread solo, non uno per le letture e uno per le scritture.** Su RS485 il
|
||
filo è uno: due richieste insieme si sovrappongono e le risposte arrivano
|
||
mescolate. Chi comanda deve comunque aspettare la fine della richiesta in
|
||
corso, quindi un secondo thread aggiungerebbe solo un lucchetto attorno alla
|
||
porta. La reattività dei comandi si ottiene con la **precedenza**: la coda
|
||
delle scritture viene svuotata prima di ogni lettura, non solo a ogni giro,
|
||
quindi un pulsante premuto parte al massimo dopo la richiesta in corso.
|
||
|
||
Come si comporta:
|
||
|
||
- **Cliccare un comando torna subito.** La scrittura va in coda; l'elemento si
|
||
accende fidandosi. Se la scrittura non va a segno lo dice la barra di stato,
|
||
e la rilettura delle bobine rimette l'elemento a posto entro un ciclo.
|
||
- **L'ordine è garantito**: le due bobine di un selettore a 3 posizioni, o la
|
||
pressione e il rilascio di un pulsante, partono nella sequenza in cui sono
|
||
state messe in coda.
|
||
- **La porta si riapre da sola.** Se non c'è, o se cade (adattatore USB
|
||
staccato), il thread riprova ogni due secondi: non serve più riavviare il
|
||
programma.
|
||
- **Chiudendo**, l'attesa del thread dura al massimo quanto la richiesta in
|
||
corso.
|
||
|
||
## Aggiungere slave e canali
|
||
|
||
Niente nel programma è legato ai moduli montati adesso: una plancia si può
|
||
disegnare prima, e i moduli si aggiungono quando arrivano.
|
||
|
||
- **Slave**: qualsiasi indirizzo da 1 a 247, quanti se ne vuole sullo stesso
|
||
bus. Ogni slave nuovo aggiunge solo le sue richieste al giro di polling.
|
||
- **Canali**: qualsiasi numero da 0 a 65535, senza doverli tenere contigui.
|
||
Canali molto distanti sullo stesso slave allargano però l'intervallo letto
|
||
(vedi Polling), quindi conviene raggrupparli.
|
||
- **Limiti di una singola richiesta**, imposti dal protocollo: 2000 bit per
|
||
bobine e ingressi, 125 registri. Oltre, la richiesta viene saltata e la barra
|
||
di stato lo dice: si spezza l'intervallo o si sposta l'elemento su un altro
|
||
slave.
|
||
- **Nuove porte**: la porta è una per plancia (`<connection port=...>`). Due
|
||
bus separati si fanno con due plance, e si passa dall'una all'altra con la
|
||
casella in basso a destra.
|
||
|
||
**Una richiesta che non riesce si divide da sola.** Se la lettura di un blocco
|
||
di bobine fallisce, il programma la spezza a metà e riprova con le due metà, e
|
||
così via: un modulo da 32 canali interrogato fino al 38 finisce per farsi
|
||
leggere i suoi 32 in poche richieste, invece di non dare più niente. Ogni
|
||
divisione compare nella barra di stato. Le divisioni imparate valgono finché
|
||
non si cambia plancia o non si riapre la porta.
|
||
|
||
**Le richieste che non rispondono non danno fastidio.** Dopo tre errori di
|
||
fila una richiesta muta viene messa in pausa e riprovata ogni cinque secondi,
|
||
invece di costarne il timeout a ogni giro: così una plancia disegnata in
|
||
anticipo resta scorrevole e i moduli che rispondono vengono letti alla velocità
|
||
giusta. Appena il modulo viene collegato riparte da solo, entro quei cinque
|
||
secondi. La barra di stato distingue i due casi: `Timeout: nessuna risposta` è
|
||
una richiesta che si sta ancora provando, `non risponde, riprovo fra 4 s` è una
|
||
messa in pausa. La pausa si azzera da sola quando si cambia plancia, quando si
|
||
modificano i canali in configurazione e quando la porta viene riaperta.
|
||
|
||
La pausa vale **per singola richiesta**, non per modulo: sullo stesso nodo le
|
||
bobine possono rispondere benissimo mentre gli ingressi, che quel modulo non ha,
|
||
danno errore. Mettere in pausa tutto il nodo per colpa degli ingressi
|
||
lascerebbe la plancia cieca proprio su quello che si legge.
|
||
|
||
## Polling
|
||
|
||
Ad ogni ciclo (`pollMs`) gli elementi vengono raggruppati per slave e tipo, e
|
||
per ogni gruppo parte **una sola** richiesta che copre i canali da quello più
|
||
basso a quello più alto. Aggiungere elementi contigui non aumenta il traffico
|
||
sul bus; canali molto distanti sullo stesso slave sì, perché allargano
|
||
l'intervallo letto.
|
||
|
||
Ogni richiesta va per conto suo: se un modulo non risponde, gli altri gruppi
|
||
vengono letti comunque. Solo le spie e i gauge di **quella** richiesta passano a
|
||
"dato non disponibile"; il resto della plancia continua a leggere. Interruttori
|
||
e selettori invece non si azzerano, perché la loro posizione è un comando dato,
|
||
non una misura.
|
||
|
||
L'errore finisce nella barra di stato dicendo **cosa** non si è potuto leggere:
|
||
slave, funzione e intervallo di canali, per esempio
|
||
|
||
Lettura fallita su 4 richieste, la prima: slave 3, ingressi 0-14 (FC02): timeout
|
||
|
||
Così si capisce subito se manca un modulo, se l'indirizzo è sbagliato o se si
|
||
sta leggendo oltre i canali che il modulo ha (tipico: un modulo da 8 bobine
|
||
interrogato per 37, perché un elemento ha un canale alto). Il polling continua
|
||
e si riallinea da solo appena il bus risponde.
|