811 lines
23 KiB
Markdown
811 lines
23 KiB
Markdown
***
|
|
## Panoramica del Sistema
|
|
|
|
Il Function Block **FB2120 MaselliTCP** è stato sviluppato per leggere direttamente i valori inviati dai sensori Maselli UR62 o UR29 utilizzando il protocollo ADAM tramite un gateway 485-Ethernet. Il sistema utilizza TCP per migliorare la resilienza dei dati, sfruttando la gestione automatica delle ritrasmissioni e il mantenimento dell'ordine dei frame.
|
|
|
|
### Vantaggi del Sistema
|
|
|
|
- **Comunicazione digitale diretta**: Evita la doppia conversione DAC-ADC, mantenendo la piena risoluzione
|
|
- **Resilienza TCP**: Gestione automatica delle ritrasmissioni e mantenimento dell'ordine dei dati
|
|
- **Sistema di riconnessione intelligente**: Gestisce diversi timeout per ristabilire la connessione
|
|
- **Monitoraggio avanzato**: Contatori per diversi tipi di errori e metriche di affidabilità
|
|
- **Compatibilità parallela**: Può funzionare in parallelo al sistema ADAM esistente
|
|
|
|
## Architettura del Sistema
|
|
|
|
```plantuml
|
|
@startuml
|
|
!define RECTANGLE class
|
|
!theme plain
|
|
|
|
package "Sensore Maselli" #E8F4F8 {
|
|
[UR62/UR29] as sensor #4A90A4
|
|
}
|
|
|
|
package "Gateway 485-Ethernet" #E8F5E8 {
|
|
[Waveshare RS485-TCP] as gateway #2E7D32
|
|
}
|
|
|
|
package "PLC Siemens S7-300" #E3F2FD {
|
|
[FB2120 MaselliTCP] as fb #1565C0
|
|
[TCON] as tcon #42A5F5
|
|
[TRCV] as trcv #42A5F5
|
|
[TDISCON] as tdiscon #42A5F5
|
|
}
|
|
|
|
package "Rete Ethernet" #FFF3E0 {
|
|
[TCP Connection] as tcp #FF8F00
|
|
}
|
|
|
|
sensor -right-> gateway : RS485\nProtocollo ADAM
|
|
gateway -right-> tcp : TCP Trasparente
|
|
tcp -right-> fb : Frame #XX12.345CKCR
|
|
fb -down-> tcon : Connessione
|
|
fb -down-> trcv : Ricezione
|
|
fb -down-> tdiscon : Disconnessione
|
|
|
|
note right of gateway #E8F5E8
|
|
**Gateway trasparente 485-Ethernet**
|
|
• Converte RS485 in TCP
|
|
• Server TCP sulla porta 8899
|
|
• Comunicazione bidirezionale
|
|
end note
|
|
|
|
note right of fb #E3F2FD
|
|
**FB2120 gestisce:**
|
|
• State machine TCP
|
|
• Buffer circolare ottimizzato
|
|
• Parsing frame ADAM
|
|
• Calcolo Brix digitale
|
|
• Gestione errori avanzata
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
|
|
```plantuml
|
|
@startuml
|
|
|
|
skinparam cloud {
|
|
BackgroundColor Gold
|
|
BorderColor Orange
|
|
}
|
|
|
|
' Definición de los componentes con colores
|
|
component "🔌 UR29" as Meter <<meter>> #LightBlue {
|
|
[RS485] as MeterRS485 #SkyBlue
|
|
}
|
|
|
|
component "🌐 Gateway RS485-Ethernet" as Gateway <<gateway>> #LightGreen {
|
|
[RS485] as GatewayRS485 #SkyBlue
|
|
[Ethernet] as GatewayEth #LightYellow
|
|
}
|
|
|
|
component "🖥️ PLC 315F 2PN/DP" as PLC <<plc>> #LightBlue {
|
|
[PN] as PLCEth #LightYellow
|
|
[FB2120] as FB2120 #LightPink
|
|
[DB2120] as DB2120 #LightPink
|
|
}
|
|
|
|
' Fuente de alimentación con estilo
|
|
cloud "⚡ Alimentatore\n24V DC" as PowerSupply #Gold
|
|
|
|
' Conexiones de datos con colores y etiquetas mejoradas
|
|
MeterRS485 -[#Blue,thickness=3]-> GatewayRS485 : "📡 RS485\nADAM Protocol"
|
|
GatewayEth -[#Green,thickness=3]-> PLCEth : "🌐 Ethernet\nTCP Trasparente"
|
|
|
|
' Conexión interna del PLC
|
|
PLCEth -[#Purple,thickness=2]-> FB2120 : "Comm TCP"
|
|
FB2120 -[#Purple,thickness=2]-> DB2120 : "Dati"
|
|
|
|
' Conexiones de alimentación
|
|
PowerSupply -[#Red,dashed,thickness=2]-> Meter : "24V DC"
|
|
PowerSupply -[#Red,dashed,thickness=2]-> Gateway : "24V DC"
|
|
PowerSupply -[#Red,dashed,thickness=2]-> PLC : "24V DC"
|
|
|
|
' Notas explicativas con colores
|
|
note right of Meter #LightBlue
|
|
**Reflectometer**
|
|
• Protocollo: Transparent TCP
|
|
• Interfaccia: RS485
|
|
• Velocità: 115200 bps
|
|
end note
|
|
|
|
note top of Gateway #LightGreen
|
|
**Gateway di Comunicazione**
|
|
• Conversione RS485 ↔ Ethernet
|
|
• Protocollo: TCP Trasparente
|
|
• IP: 10.1.33.18
|
|
end note
|
|
|
|
note left of PLC #LightBlue
|
|
**PLC Siemens 315**
|
|
• CPU 315-2DP
|
|
• Interfaccia Ethernet
|
|
• FB2120: Function Block comunicazione
|
|
• DB2120: Data Block instanza
|
|
• IP: 10.1.33.11
|
|
end note
|
|
|
|
' Título del diagrama
|
|
title **Sistema di Comunicazione Industriale**\n//Contatore → Gateway → PLC//
|
|
|
|
@enduml
|
|
```
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme toy
|
|
|
|
' Layout horizontal para enfatizar flujo de datos
|
|
left to right direction
|
|
|
|
skinparam cloud {
|
|
BackgroundColor Gold
|
|
BorderColor Orange
|
|
}
|
|
|
|
' Definición de los componentes con colores
|
|
component "🔌 UR29" as Meter <<meter>> #LightBlue {
|
|
[RS485] as MeterRS485 #SkyBlue
|
|
}
|
|
|
|
component "🌐 Gateway RS485-Ethernet" as Gateway <<gateway>> #LightGreen {
|
|
[RS485] as GatewayRS485 #SkyBlue
|
|
[Ethernet] as GatewayEth #LightYellow
|
|
}
|
|
|
|
component "🖥️ PLC 315F 2PN/DP" as PLC <<plc>> #LightBlue {
|
|
[PN] as PLCEth #LightYellow
|
|
[FB2120] as FB2120 #LightPink
|
|
[DB2120] as DB2120 #LightPink
|
|
}
|
|
|
|
' Alimentación minimalista en la parte superior
|
|
note top #Gold : **⚡ Alimentazione 24V DC**\n//Tutti i componenti//
|
|
|
|
' CONEXIONES DE DATOS PRINCIPALES - MUY VISIBLES
|
|
MeterRS485 -[#Blue,thickness=5]-> GatewayRS485 : "📡 **RS485**\n//ADAM Protocol//\n**115200 bps**"
|
|
GatewayEth -[#Green,thickness=5]-> PLCEth : "🌐 **ETHERNET**\n//TCP Trasparente//\n**10.1.33.18 → 10.1.33.11**"
|
|
|
|
' Conexiones internas del PLC con flujo claro
|
|
PLCEth -[#Purple,thickness=4]-> FB2120 : "**TCP Data**"
|
|
FB2120 -[#Purple,thickness=4]-> DB2120 : "**Memory**"
|
|
|
|
' Indicadores de dirección de flujo
|
|
note bottom of Meter #LightCyan : **📤 TX Data**
|
|
note bottom of PLC #LightCyan : **📥 RX Data**
|
|
|
|
' Notas técnicas compactas
|
|
note right of Gateway #LightGreen
|
|
**Gateway Configuration**
|
|
• RS485 ↔ Ethernet Bridge
|
|
• Transparent TCP Protocol
|
|
• IP: 10.1.33.18
|
|
• Port: Configurable
|
|
end note
|
|
|
|
' Título enfocado en comunicación
|
|
title **🔗 Flusso Dati di Comunicazione Industriale**\n//UR29 Reflectometer → TCP Gateway → Siemens PLC//
|
|
|
|
@enduml
|
|
```
|
|
|
|
|
|
## State Machine Principale
|
|
|
|
Il FB2120 utilizza una state machine principale per gestire la connessione TCP:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
[*] --> IDLE : Sistema avviato
|
|
|
|
IDLE : Entry: xConnected = FALSE
|
|
IDLE : Do: Retry delay attivo
|
|
IDLE --> CONNECT : xEnable = TRUE AND tonRetryDelay.Q
|
|
|
|
CONNECT : Entry: Preparazione connessione
|
|
CONNECT : Do: iCyclesToWait + 1
|
|
CONNECT --> WAIT_CONNECT : iCyclesToWait >= 2
|
|
|
|
WAIT_CONNECT : Entry: xTconReq = TRUE
|
|
WAIT_CONNECT : Do: TCON attivo, tonConnTimeout attivo
|
|
WAIT_CONNECT --> READING : TCON.DONE
|
|
WAIT_CONNECT --> DISCONNECT : TCON.ERROR OR tonConnTimeout.Q
|
|
WAIT_CONNECT --> DISCONNECT : NOT xEnable
|
|
|
|
READING : Entry: xConnected = TRUE
|
|
READING : Do: TRCV attivo, lettura frame
|
|
READING : Do: Reading state machine attiva
|
|
READING --> DISCONNECT : TRCV.ERROR OR tonNoDataTimeout.Q
|
|
READING --> DISCONNECT : NOT xEnable
|
|
|
|
DISCONNECT : Entry: xTdisconReq = TRUE
|
|
DISCONNECT : Do: TDISCON attivo
|
|
DISCONNECT --> IDLE : TDISCON.DONE OR TDISCON.ERROR
|
|
|
|
note right of READING
|
|
Stato più complesso con
|
|
sub-state machine per
|
|
la gestione della lettura
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
## Reading State Machine
|
|
|
|
Durante lo stato READING, una sub-state machine gestisce la lettura ottimizzata dei frame:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
[*] --> ACTIVE_READING : Ingresso in READING
|
|
|
|
state "Fase Inizializzazione" as INIT {
|
|
ACTIVE_READING : Entry: xTrcvTimeToCall = TRUE
|
|
ACTIVE_READING : Do: Lettura intensiva ogni ciclo
|
|
ACTIVE_READING : Do: Accumulo diAccumCycleMs
|
|
ACTIVE_READING --> COMPLETED : Frame valido ricevuto
|
|
|
|
COMPLETED : Entry: xTrcvTimeToCall = FALSE
|
|
COMPLETED : Do: Calcolo intervallo frame
|
|
COMPLETED : Do: Reset diAccumCycleMs = 0
|
|
COMPLETED --> ACTIVE_READING : xInitPhaseFinish = FALSE
|
|
}
|
|
|
|
state "Fase Normale" as NORMAL {
|
|
ACTIVE_READING2 : Entry: xTrcvTimeToCall = TRUE
|
|
ACTIVE_READING2 : Do: Lettura intensiva
|
|
ACTIVE_READING2 --> PAUSED : Troppo tempo al prossimo frame
|
|
ACTIVE_READING2 --> COMPLETED2 : Frame valido ricevuto
|
|
|
|
PAUSED : Entry: xTrcvTimeToCall = FALSE
|
|
PAUSED : Do: Attesa finestra frame
|
|
PAUSED --> ACTIVE_READING2 : Vicino al prossimo frame
|
|
|
|
COMPLETED2 : Entry: Elaborazione frame
|
|
COMPLETED2 : Do: Aggiornamento statistiche
|
|
COMPLETED2 --> PAUSED : Completato
|
|
}
|
|
|
|
INIT --> NORMAL : xInitPhaseFinish = TRUE
|
|
|
|
note right of INIT
|
|
Durante l'inizializzazione
|
|
legge continuamente per
|
|
sincronizzarsi con il flusso
|
|
end note
|
|
|
|
note right of NORMAL
|
|
In funzionamento normale
|
|
ottimizza la lettura con
|
|
finestre temporali
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
## Formato Frame ADAM
|
|
|
|
Il protocollo ADAM utilizza frame di 12 byte fissi:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
package "Frame ADAM - 12 Bytes" {
|
|
rectangle "Byte 0\n#" as b0
|
|
rectangle "Byte 1-2\nAdam ID" as b12
|
|
rectangle "Byte 3-4\nXX" as b34
|
|
rectangle "Byte 5\n." as b5
|
|
rectangle "Byte 6-8\nYYY" as b678
|
|
rectangle "Byte 9-10\nChecksum" as b910
|
|
rectangle "Byte 11\nCR" as b11
|
|
}
|
|
|
|
b0 -right-> b12
|
|
b12 -right-> b34
|
|
b34 -right-> b5
|
|
b5 -right-> b678
|
|
b678 -right-> b910
|
|
b910 -right-> b11
|
|
|
|
note bottom of b0
|
|
Start marker '#'
|
|
(0x23)
|
|
end note
|
|
|
|
note bottom of b12
|
|
Device ID
|
|
"01" = Dispositivo 1
|
|
"02" = Dispositivo 2
|
|
end note
|
|
|
|
note bottom of b34
|
|
Parte intera
|
|
corrente mA
|
|
"02" = 2mA
|
|
end note
|
|
|
|
note bottom of b5
|
|
Separatore decimale
|
|
'.' (0x2E)
|
|
end note
|
|
|
|
note bottom of b678
|
|
Parte decimale
|
|
corrente mA
|
|
"145" = 0.145mA
|
|
end note
|
|
|
|
note bottom of b910
|
|
Checksum esadecimale
|
|
Somma bytes 0-8
|
|
modulo 256
|
|
end note
|
|
|
|
note bottom of b11
|
|
Carriage Return
|
|
(0x0D)
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
**Esempio Frame**: `#0102.145CkCr`
|
|
|
|
- `#`: Start marker
|
|
- `01`: Device ID = 1
|
|
- `02.145`: Corrente = 2.145 mA
|
|
- `Ck`: Checksum calcolato
|
|
- `Cr`: Carriage return
|
|
|
|
## Sequenza di Comunicazione TCP
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
participant "FB2120" as fb
|
|
participant "TCON" as tcon
|
|
participant "Gateway" as gw
|
|
participant "TRCV" as trcv
|
|
participant "Sensore" as sensor
|
|
|
|
== Fase Connessione ==
|
|
fb -> tcon : REQ=TRUE, ID=W#16#10
|
|
tcon -> gw : TCP SYN a IP:porta
|
|
gw -> tcon : TCP SYN-ACK
|
|
tcon -> fb : DONE=TRUE
|
|
|
|
== Fase Lettura ==
|
|
loop Lettura Continua
|
|
sensor -> gw : Frame ADAM via RS485
|
|
gw -> fb : Frame TCP trasparente
|
|
fb -> trcv : EN_R=TRUE (se xTrcvTimeToCall)
|
|
trcv -> fb : NDR=TRUE + dati
|
|
fb -> fb : Parsing frame, validazione
|
|
fb -> fb : Calcolo Brix, aggiornamento FIFO
|
|
end
|
|
|
|
== Gestione Errori ==
|
|
alt Errore di comunicazione
|
|
trcv -> fb : ERROR=TRUE
|
|
fb -> fb : Analisi errore, riconnessione
|
|
end
|
|
|
|
== Disconnessione ==
|
|
fb -> tdiscon : REQ=TRUE
|
|
tdiscon -> gw : TCP FIN
|
|
gw -> tdiscon : TCP FIN-ACK
|
|
tdiscon -> fb : DONE=TRUE
|
|
@enduml
|
|
```
|
|
|
|
## Gestione Buffer Circolare
|
|
|
|
Il sistema utilizza un buffer circolare per gestire efficacemente i frame ricevuti:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
package "Buffer Circolare - 256 Bytes" {
|
|
rectangle "Circular Buffer\naCircBuffer[0..255]" as buffer
|
|
rectangle "Write Pointer\niWritePtr" as wptr
|
|
rectangle "Read Pointer\niReadPtr" as rptr
|
|
rectangle "Data Count\niDataInBuffer" as count
|
|
}
|
|
|
|
package "Frame Processing" {
|
|
rectangle "Ricerca '#'" as search
|
|
rectangle "Validazione Formato" as validate
|
|
rectangle "Parsing Dati" as parse
|
|
rectangle "Calcolo Checksum" as checksum
|
|
}
|
|
|
|
buffer -down-> search : Scan per start marker
|
|
search -right-> validate : Frame trovato
|
|
validate -right-> parse : Formato OK
|
|
parse -right-> checksum : Dati estratti
|
|
checksum -up-> buffer : Frame processato, avanzamento puntatori
|
|
|
|
note right of buffer
|
|
Buffer di 256 byte per gestire
|
|
ricezione asincrona e parsing
|
|
efficiente dei frame
|
|
end note
|
|
|
|
note bottom of search
|
|
Ricerca sequenziale del
|
|
carattere '#' per inizio frame
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
## Codici di Errore
|
|
|
|
Il sistema utilizza codici di errore gerarchici (priorità crescente):
|
|
|
|
|Codice|Priorità|Descrizione|
|
|
|---|---|---|
|
|
|0|-|Nessun errore|
|
|
|1|Bassa|Errore checksum|
|
|
|2|Bassa|Formato frame non valido|
|
|
|3|Bassa|Caratteri non numerici|
|
|
|4|Media|Dati fuori range (4-20mA)|
|
|
|5|Media|Frame consecutivi errati|
|
|
|6|Media|Frame persi rilevati|
|
|
|7|Alta|Buffer TRCV troppo piccolo|
|
|
|8|Alta|Errore comunicazione TRCV|
|
|
|9|Critica|Timeout ricezione dati|
|
|
|10|Critica|Timeout connessione|
|
|
|11|Critica|Connessione TCP fallita|
|
|
|12|Critica|Connessione TCP terminata|
|
|
|
|
## Parametri di Configurazione
|
|
|
|
### Input Parameters
|
|
|
|
- **xEnable**: Abilitazione comunicazione
|
|
- **aRemoteIP**: IP del gateway [10,1,33,100]
|
|
- **iRemotePort**: Porta TCP (default: 8899)
|
|
- **rBrixMax**: Valore Brix massimo a 20mA (default: 80.0)
|
|
- **wConnectionID**: ID connessione TCP
|
|
- **xEnableChecksum**: Abilitazione validazione checksum
|
|
- **rFramesPerSecond**: Frame attesi per secondo (default: 3.0)
|
|
- **iDeviceID**: ID dispositivo da validare (0=disabilitato)
|
|
|
|
### Output Parameters
|
|
|
|
- **xConnected**: Stato connessione
|
|
- **xDataValid**: Pulse per nuovo dato valido
|
|
- **xError**: Errore attivo
|
|
- **iErrorCode**: Codice errore strutturato
|
|
- **rCurrentMA**: Valore corrente in mA
|
|
- **rBrixValue**: Valore Brix calcolato
|
|
- **diTimeBetweenFramesMs**: Tempo tra frame consecutivi
|
|
|
|
## Calcolo Brix
|
|
|
|
La conversione dalla corrente 4-20mA al valore Brix segue la formula:
|
|
|
|
```
|
|
rBrixValue = (rCurrentMA - 4.0) * rBrixMax / 16.0
|
|
```
|
|
|
|
**Esempio**:
|
|
|
|
- Corrente ricevuta: 12.0 mA
|
|
- Brix Max configurato: 80.0
|
|
- Calcolo: (12.0 - 4.0) * 80.0 / 16.0 = 40.0 Brix
|
|
|
|
## Sistema FIFO (Debug Mode)
|
|
|
|
Quando `xEnableFifoDebug = TRUE`, il sistema mantiene le ultime 10 letture:
|
|
|
|
- **arBrixHistory[0..9]**: Valori Brix (newest → oldest)
|
|
- **auiTimeHistory[0..9]**: Timestamp (newest → oldest)
|
|
|
|
I dati vengono spostati ad ogni nuovo valore valido, con il più recente sempre in posizione [0].
|
|
|
|
## Vantaggi Implementativi
|
|
|
|
### Ottimizzazioni v1.8
|
|
|
|
- **Buffer ottimizzato**: Ridotto da 128 a 23 byte
|
|
- **State machine migliorata**: Fase di inizializzazione separata
|
|
- **Lettura adattiva**: Finestre temporali ottimizzate
|
|
- **Gestione errori avanzata**: Codici gerarchici strutturati
|
|
- **Sincronizzazione migliorata**: Flag xInitPhaseFinish
|
|
|
|
### Resilienza del Sistema
|
|
|
|
- **Riconnessione automatica**: Gestione intelligente dei timeout
|
|
- **Buffer circolare**: Gestione efficace dei dati asincroni
|
|
- **Validazione multipla**: Formato, checksum, range dati
|
|
- **Statistiche dettagliate**: Monitoraggio prestazioni e affidabilità
|
|
|
|
## Configurazione Hardware Richiesta
|
|
|
|
### Gateway Suggerito
|
|
|
|
- **Waveshare Industrial Grade Serial Server RS232/485 to WiFi And Ethernet**
|
|
- Configurazione: Server TCP trasparente
|
|
- Porta: 8899 (configurabile)
|
|
- Modalità: Trasparente RS485 → TCP
|
|
|
|
### PLC Requirements
|
|
|
|
- **Siemens S7-300** con supporto TCP/IP
|
|
- **Function Blocks**: TCON, TRCV, TDISCON (standard Siemens)
|
|
- **Memoria**: ~2KB per istanza FB
|
|
- **Nessuna configurazione NetPro richiesta**
|
|
|
|
## Utilizzo Pratico
|
|
|
|
1. **Istanziare FB2120** con parametri specifici del sensore
|
|
2. **Configurare IP/Porta** del gateway nel codice
|
|
3. **Impostare xEnable = TRUE** per avviare la comunicazione
|
|
4. **Monitorare xDataValid** per nuovi dati
|
|
5. **Verificare iErrorCode** per diagnostica
|
|
6. **Leggere rBrixValue** e rCurrentMA** per i valori processati
|
|
|
|
Il sistema è progettato per funzionare in parallelo ai sistemi ADAM esistenti, offrendo una soluzione digitale più precisa e affidabile per la lettura dei sensori Maselli.
|
|
|
|
## Reading State Machine e Burst-Reading
|
|
|
|
Durante lo stato READING, una sub-state machine gestisce la lettura ottimizzata dei frame con la tecnica del **burst-reading** per ottimizzare le risorse del PLC:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
|
|
[*] --> ACTIVE_READING : Ingresso in READING
|
|
|
|
state "Fase Inizializzazione" as INIT {
|
|
ACTIVE_READING : Entry: xTrcvTimeToCall = TRUE
|
|
ACTIVE_READING : Do: Lettura intensiva ogni ciclo
|
|
ACTIVE_READING : Do: Accumulo diAccumCycleMs
|
|
ACTIVE_READING : Do: Ricerca sincronizzazione frame
|
|
ACTIVE_READING --> COMPLETED : Frame valido ricevuto
|
|
|
|
COMPLETED : Entry: xTrcvTimeToCall = FALSE
|
|
COMPLETED : Do: Calcolo intervallo frame iniziale
|
|
COMPLETED : Do: Aggiornamento stTiming.diEstFrameMs
|
|
COMPLETED : Do: Reset diAccumCycleMs = 0
|
|
COMPLETED --> ACTIVE_READING : xInitPhaseFinish = FALSE
|
|
COMPLETED --> INIT_COMPLETE : Buffer sincronizzato E tempo > 2*intervallo
|
|
|
|
INIT_COMPLETE : Entry: xInitPhaseFinish = TRUE
|
|
INIT_COMPLETE : Do: Transizione a funzionamento normale
|
|
}
|
|
|
|
state "Fase Funzionamento Normale" as NORMAL {
|
|
ACTIVE_READING_BURST : Entry: xTrcvTimeToCall = TRUE
|
|
ACTIVE_READING_BURST : Do: Lettura burst intensiva
|
|
ACTIVE_READING_BURST : Do: diReadingStartMs = diAccumCycleMs
|
|
ACTIVE_READING_BURST --> PAUSED : (diNextFrameMs - diAccumCycleMs) > iMaxActiveReadingMs
|
|
ACTIVE_READING_BURST --> COMPLETED_NORMAL : Frame valido ricevuto
|
|
|
|
PAUSED : Entry: xTrcvTimeToCall = FALSE
|
|
PAUSED : Do: Risparmio risorse CPU
|
|
PAUSED : Do: Attesa finestra frame calcolata
|
|
PAUSED --> ACTIVE_READING_BURST : (diNextFrameMs - diAccumCycleMs) <= iPreReadOffsetMs
|
|
|
|
COMPLETED_NORMAL : Entry: xTrcvTimeToCall = FALSE
|
|
COMPLETED_NORMAL : Do: Elaborazione frame completa
|
|
COMPLETED_NORMAL : Do: Aggiornamento statistiche avanzate
|
|
COMPLETED_NORMAL : Do: Smoothing diEstFrameMs
|
|
COMPLETED_NORMAL : Do: Rilevamento frame persi
|
|
COMPLETED_NORMAL --> PAUSED : Sempre
|
|
}
|
|
|
|
INIT --> NORMAL : xInitPhaseFinish = TRUE
|
|
|
|
note right of INIT
|
|
**Fase Inizializzazione:**
|
|
- Lettura continua per sincronizzazione
|
|
- Apprendimento timing frame
|
|
- Pulizia buffer da dati residui
|
|
- Stima intervallo frame iniziale
|
|
end note
|
|
|
|
note right of NORMAL
|
|
**Burst-Reading Ottimizzato:**
|
|
- Lettura intensiva solo quando necessario
|
|
- Pausa durante attese lunghe
|
|
- Risparmio risorse CPU del 60-80%
|
|
- Finestre temporali adattive
|
|
end note
|
|
|
|
note bottom of PAUSED
|
|
**Ottimizzazione Risorse:**
|
|
- TRCV non chiamato
|
|
- CPU dedicata ad altri task
|
|
- Calcolo dinamico finestra lettura
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
## Sequenza Dettagliata Burst-Reading
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
title Sequenza Burst-Reading - Ottimizzazione Risorse PLC
|
|
|
|
actor "Ciclo PLC" as plc
|
|
participant "iReadingState\nMachine" as rsm
|
|
participant "TRCV" as trcv
|
|
participant "Buffer\nCircolare" as buffer
|
|
participant "Gateway\nTCP" as gateway
|
|
participant "Sensore\nMaselli" as sensor
|
|
|
|
== Fase Inizializzazione (xInitPhaseFinish = FALSE) ==
|
|
|
|
loop Sincronizzazione Iniziale
|
|
plc -> rsm : Ciclo PLC (ogni 10-50ms)
|
|
rsm -> rsm : iReadingState = 0 (ACTIVE_READING)
|
|
rsm -> rsm : xTrcvTimeToCall = TRUE
|
|
rsm -> trcv : TRCV(EN_R=TRUE) - **Lettura Intensiva**
|
|
|
|
alt Frame disponibile
|
|
sensor -> gateway : Frame ADAM #01XX.YYYCKHR
|
|
gateway -> trcv : TCP Data
|
|
trcv -> rsm : NDR=TRUE + 12 bytes
|
|
rsm -> buffer : Copia in buffer circolare
|
|
rsm -> rsm : Parsing e validazione frame
|
|
|
|
alt Frame valido
|
|
rsm -> rsm : iReadingState = 1 (COMPLETED)
|
|
rsm -> rsm : Calcolo primo intervallo
|
|
rsm -> rsm : diAccumCycleMs = 0 (reset timer)
|
|
rsm -> rsm : iConsecutiveGoodFrames++
|
|
|
|
alt Sincronizzazione completa
|
|
rsm -> rsm : xInitPhaseFinish = TRUE
|
|
rsm -> rsm : **Transizione a Burst-Reading**
|
|
end
|
|
end
|
|
else Nessun frame
|
|
rsm -> rsm : Continua accumulo diAccumCycleMs
|
|
end
|
|
end
|
|
|
|
== Fase Funzionamento Normale (Burst-Reading) ==
|
|
|
|
loop Ciclo Ottimizzato
|
|
plc -> rsm : Ciclo PLC
|
|
rsm -> rsm : Calcolo finestra frame
|
|
|
|
alt Finestra Attiva (vicino al frame atteso)
|
|
rsm -> rsm : iReadingState = 0 (ACTIVE_READING_BURST)
|
|
rsm -> rsm : xTrcvTimeToCall = TRUE
|
|
rsm -> trcv : **TRCV(EN_R=TRUE) - Burst Intensivo**
|
|
|
|
note right : **Lettura Burst:**\nTRCV chiamato ogni ciclo\nper massima reattività
|
|
|
|
alt Frame ricevuto
|
|
trcv -> rsm : NDR=TRUE + frame data
|
|
rsm -> rsm : iReadingState = 1 (COMPLETED_NORMAL)
|
|
rsm -> rsm : Elaborazione completa frame
|
|
rsm -> rsm : Aggiornamento statistiche
|
|
rsm -> rsm : Smoothing diEstFrameMs
|
|
rsm -> rsm : diNextFrameMs = nuovo calcolo
|
|
rsm -> rsm : iReadingState = 2 (PAUSED)
|
|
else Timeout burst
|
|
rsm -> rsm : iReadingState = 2 (PAUSED)
|
|
note right : Evita lettura continua\neccessiva
|
|
end
|
|
|
|
else Finestra Inattiva (troppo presto per il prossimo frame)
|
|
rsm -> rsm : iReadingState = 2 (PAUSED)
|
|
rsm -> rsm : xTrcvTimeToCall = FALSE
|
|
rsm -> trcv : **TRCV(EN_R=FALSE) - Risparmio CPU**
|
|
|
|
note right : **Modalità Pausa:**\nTRCV non chiamato\nCPU disponibile per altri task\nRisparmio energetico
|
|
|
|
rsm -> rsm : Calcolo: (diNextFrameMs - diAccumCycleMs)
|
|
rsm -> rsm : Se <= iPreReadOffsetMs → Attiva burst
|
|
end
|
|
end
|
|
|
|
note over plc, sensor
|
|
**Vantaggi Burst-Reading:**
|
|
• Risparmio CPU: 60-80% in modalità PAUSED
|
|
• Reattività massima durante burst
|
|
• Sincronizzazione automatica con sensore
|
|
• Adattamento dinamico agli intervalli frame
|
|
• Riduzione interferenze con altri task PLC
|
|
end note
|
|
@enduml
|
|
```
|
|
|
|
## Fase di Inizializzazione Dettagliata
|
|
|
|
La fase di inizializzazione è critica per sincronizzare il PLC con il flusso dati del sensore Maselli:
|
|
|
|
```plantuml
|
|
@startuml
|
|
!theme plain
|
|
title Sequenza Fase di Inizializzazione - Sincronizzazione con Sensore
|
|
|
|
participant "FB2120" as fb
|
|
participant "Buffer\nCircolare" as buffer
|
|
participant "Frame\nParser" as parser
|
|
participant "Timing\nEngine" as timing
|
|
participant "Statistiche" as stats
|
|
|
|
== Avvio Inizializzazione ==
|
|
fb -> fb : xInitPhaseFinish = FALSE
|
|
fb -> fb : iReadingState = 0 (ACTIVE_READING)
|
|
fb -> fb : diAccumCycleMs = 0
|
|
fb -> fb : iConsecutiveGoodFrames = 0
|
|
fb -> timing : diInitPhaseStartMs = diAccumCycleMs
|
|
|
|
== Raccolta Dati Iniziale ==
|
|
loop Lettura Continua (xTrcvTimeToCall = TRUE)
|
|
fb -> buffer : Ricezione dati TCP asincroni
|
|
buffer -> buffer : Accumulo bytes in buffer circolare
|
|
buffer -> parser : Ricerca pattern #XX.YYY
|
|
|
|
alt Buffer contiene dati residui/parziali
|
|
parser -> buffer : Pulizia dati non validi
|
|
parser -> buffer : Allineamento a boundary frame
|
|
note right : Rimozione garbage data\nda precedenti connessioni
|
|
end
|
|
|
|
alt Frame completo trovato
|
|
parser -> parser : Validazione formato
|
|
alt Frame strutturalmente valido
|
|
parser -> fb : Frame OK + dati estratti
|
|
fb -> fb : iConsecutiveGoodFrames++
|
|
fb -> fb : Calcolo intervallo grezzo
|
|
fb -> timing : Aggiornamento diEstFrameMs iniziale
|
|
fb -> stats : Incremento contatori successo
|
|
|
|
alt Prima sincronizzazione (frames >= 2)
|
|
fb -> timing : diEstFrameMs = intervallo_misurato
|
|
fb -> timing : Calcolo finestre ottimizzate
|
|
note right : **Parametri Calcolati:**\ndiFrameIntervalMs = 1000/rFramesPerSecond\niPreReadOffsetMs = intervallo/6\niMaxActiveReadingMs = intervallo/3
|
|
end
|
|
else Frame non valido
|
|
parser -> stats : Incremento errori formato
|
|
parser -> buffer : Scarta frame e continua
|
|
end
|
|
end
|
|
|
|
alt Condizioni per completamento inizializzazione
|
|
fb -> fb : Verifica: diAccumCycleMs > (diFrameIntervalMs * 2)
|
|
fb -> fb : Verifica: stBuffer.iRxLength = 12 (buffer pulito)
|
|
fb -> fb : Verifica: iConsecutiveGoodFrames >= 2
|
|
|
|
alt Tutte le condizioni soddisfatte
|
|
fb -> fb : **xInitPhaseFinish = TRUE**
|
|
fb -> timing : Finalizzazione parametri timing
|
|
fb -> fb : Transizione a funzionamento normale
|
|
|
|
note over fb : **Inizializzazione Completata:**\n• Buffer sincronizzato con frame\n• Timing affidabile stabilito\n• Sistema pronto per burst-reading
|
|
end
|
|
end
|
|
end
|
|
|
|
== Parametri Calcolati Automaticamente ==
|
|
timing -> timing : diFrameIntervalMs = 1000.0 / rFramesPerSecond
|
|
timing -> timing : iPreReadOffsetMs = MAX(20, diFrameIntervalMs/6)
|
|
timing -> timing : iMaxActiveReadingMs = MAX(50, diFrameIntervalMs/3)
|
|
timing -> timing : diNextFrameMs = diEstFrameMs
|
|
|
|
note over timing
|
|
**Calcoli Adattivi:**
|
|
• Intervallo teorico da configurazione
|
|
• Intervallo reale da misurazione
|
|
• Finestre dinamiche per ottimizzazione
|
|
• Sicurezza con valori minimi
|
|
end note
|
|
@enduml
|
|
```
|
|
|