*** ## 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 <> #LightBlue { [RS485] as MeterRS485 #SkyBlue } component "🌐 Gateway RS485-Ethernet" as Gateway <> #LightGreen { [RS485] as GatewayRS485 #SkyBlue [Ethernet] as GatewayEth #LightYellow } component "🖥️ PLC 315F 2PN/DP" as 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 <> #LightBlue { [RS485] as MeterRS485 #SkyBlue } component "🌐 Gateway RS485-Ethernet" as Gateway <> #LightGreen { [RS485] as GatewayRS485 #SkyBlue [Ethernet] as GatewayEth #LightYellow } component "🖥️ PLC 315F 2PN/DP" as 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 ```