Obsidean_VM/04-SIDEL/09 - SAE452 - Diet as Regul.../FB2120 - MasseliTCP/FB2120 - MasseliTCP Read - ...

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
```