Funzioni ed FB gestione networking (eLLabNetworkLib) ---------------------------------------------------- Da linguaggio IEC e nella libreria **eLLabNetworkLib** sono disponibili funzioni e blocchi funzione per la gestione del networking. SysTCPServer, accepts TCP/IP connections ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |image1| +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | XTarget_12_0_0 | +-----------------------+-----------------------+ Questa function block gestisce la comunicazione con protocollo TCP/IP in modalità server. Occorre fornire l'indirizzo di un array di flussi dati streams al parametro **FilesArr**. Occorre definire la porta TCP da porre in ascolto ed il numero di connessioni contemporanee accettate. Attivando il comando **Enable** il server TCP viene posto in ascolto sulla porta indicata, sulla connessione di un client viene incrementato il numero di **ConnPeers** ed uno degli stream definiti in **FileArr** viene valorizzato ed aperto. Sullo stream aperto è possibile utilizzare le funzioni di TermIO per gestire la comunicazione. Per modificare i parametri occorre disattivare e poi riabilitare il comando **Enable**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando abilitazione server. | +-----------------------------------+-----------------------------------+ | **FilesArr** (@FILEP) | Pointer ad array streams di I/O. | | | I vari file streams saranno | | | valorizzati alla connessione dei | | | clients. Occorre definire un | | | numero di streams pari al numero | | | di connessioni contemporanee | | | accettate. | +-----------------------------------+-----------------------------------+ | **LocalAdd** (@USINT) | Range indirizzi IP da cui è | | | accettata la connessione. La | | | connessione è accettata se | | | indirizzo IP del peer in AND con | | | il valore non viene modificato. | | | **Default '0.0.0.0':** | | | connessione accettata da tutti | | | gli indirizzi IP. | +-----------------------------------+-----------------------------------+ | **LocalPort** (UINT) | Numero di porta in ascolto sul | | | server. | +-----------------------------------+-----------------------------------+ | **MaxConn** (USINT) | Numero massimo di connessioni | | | contemporanee accettate dal | | | server. Deve essere uguale al | | | numero di files definiti. | +-----------------------------------+-----------------------------------+ | **FlushTm** (UINT) | Tempo di flush dati, se non sono | | | caricati dati sullo **stream** | | | dopo il tempo definito i dati | | | presenti vengono automaticamente | | | inviati (mS). | +-----------------------------------+-----------------------------------+ | **LifeTm** (UINT) | Tempo di vita socket, se non sono | | | ricevuti o inviati dati dopo il | | | tempo definito il socket viene | | | automaticamente chiuso (Sec). Se | | | definito tempo “0” il socket non | | | viene mai chiuso. | +-----------------------------------+-----------------------------------+ | **RxSize** (UINT) | Dimensione buffer ricezione dati. | +-----------------------------------+-----------------------------------+ | **TxSize** (UINT) | Dimensione buffer trasmissione | | | dati. | +-----------------------------------+-----------------------------------+ | **Enabled** (BOOL) | Attivo se TCP server | | | correttamente impostato e pronto. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo se errore gestione. | +-----------------------------------+-----------------------------------+ | **ConnPeers** (FILEP) | Numero di clients connessi al | | | server. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 9942005 | Blocco funzione non supportato. | +-----------------------------------+-----------------------------------+ | 9942050 | Errore allocazione blocco | | | funzione. | +-----------------------------------+-----------------------------------+ | 9942060 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 9942070 | Errore versione blocco funzione. | +-----------------------------------+-----------------------------------+ | 9942100 | FB eseguita in task diversa da | | | **Back**. | +-----------------------------------+-----------------------------------+ | 9942110 | File pointer non null | +-----------------------------------+-----------------------------------+ | 9942115 | Errore apertura socket. | +-----------------------------------+-----------------------------------+ | 9942120 | Errore set socket option. | +-----------------------------------+-----------------------------------+ | 9942125 | Errore definizione IP locale. | +-----------------------------------+-----------------------------------+ | 9942130 | Errore bind. | +-----------------------------------+-----------------------------------+ | 9942990 | Non implementata nel simulatore. | +-----------------------------------+-----------------------------------+ **Esempi** """"""""""" Nell'esempio è attivato un server TCP in ascolto sulla porta 1000. Il server accetta massimo 2 connessioni. Connettendosi in telnet alla porta 1000 inviando un carattere se ne riceve l'echo. **Definizione variabili** |image2| **Esempio FBD** *(PTP116B000, FBD_SysTCPServer)* |image3| Un esempio identico funzionalmente al precedente realizzato in linguaggio ST **Definizione variabili** |image4| **Esempio ST** *(PTP116B000, ST_SysTCPServer)* .. code-block:: none (\* TCPServer initialization. \*) IF (SysFirstLoop) THEN TCPServer.FilesArr:=ADR(Fp); (\* Files array \*) TCPServer.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) TCPServer.LocalPort:=1000; (\* Local port \*) TCPServer.MaxConn:=2; (\* Accepted connections \*) TCPServer.FlushTm:=50; (\* Flush time (mS) \*) TCPServer.LifeTm:=0; (\* Life time (S) \*) TCPServer.RxSize:=128; (\* Rx buffer size \*) TCPServer.TxSize:=128; (\* Tx buffer size \*) END_IF; (\* Manage the TCP server. \*) TCPServer(Enable:=TRUE); (\* TCPServer management \*) (\* Execute the echoes loop on opened connections. \*) FOR j:=0 TO (TCPServer.MaxConn-1) DO (\* Check if TCP connection is opened. \*) IF (SysFIsOpen(Fp[j])) THEN IF (TO_BOOL(SysGetIChars(Fp[j])) AND TO_BOOL(SysGetOSpace(Fp[j]))) THEN i:=Sysfputc(Sysfgetc(Fp[j]), Fp[j]); (\* Character echo \*) END_IF; END_IF; END_FOR; |image5| Per testare l'esempio è possibile utilizzare il programma Toolly scaricabile dal nostro sito. Aprendo due sessioni terminale è possibile verificare come siano entrambe servite dal server. SysTCPClient, opens a TCP/IP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | XTarget_12_0_0 | +-----------------------+-----------------------+ |image6| Questa function block gestisce la comunicazione con protocollo TCP/IP in modalità client. Occorre definire l'indirizzo IP **PeerAdd** e la porta TCP **PeerPort** del sistema server a cui ci si vuole connettere. Attivando il comando **Connect** viene aperta la connessione con il sistema server. Se la connessione và a buon fine viene attivato **Connected** e sull'uscita **File** viene ritornato lo stream da utilizzarsi per lo scambio dati con il sistema server. Se il server chiude la connessione si resetta **Connected** e in **File** viene ritornato NULL. In **LocalAdd** e **LocalPort** è possibile definire l'indirizzo IP e la porta della interfaccia di rete da cui effettuare la connessione. Se la connessione non è possibile viene generato **Fault**. +-----------------------------------+-----------------------------------+ | **Connect** (BOOL) | Comando abilitazione connessione | +-----------------------------------+-----------------------------------+ | **PeerAdd**\ (@USINT) | Indirizzo IP del sistema server a | | | cui connettersi. | +-----------------------------------+-----------------------------------+ | **PeerPort** (UINT) | Numero porta TCP a cui | | | connettersi. | +-----------------------------------+-----------------------------------+ | **LocalAdd** (@USINT) | Indirizzo IP della interfaccia di | | | rete da cui effettuare la | | | connessione. | | | | | | **Default '0.0.0.0':** | | | l'interfaccia è scelta | | | automaticamente in base all'IP a | | | cui connettersi. | +-----------------------------------+-----------------------------------+ | **LocalPort** (UINT) | Numero porta TCP da cui parte la | | | connessione (0 scelta | | | automaticamente). | +-----------------------------------+-----------------------------------+ | **FlushTm** (UINT) | Tempo di flush dati, se non sono | | | caricati dati sullo **stream** | | | dopo il tempo definito i dati | | | presenti vengono automaticamente | | | inviati (mS). | +-----------------------------------+-----------------------------------+ | **LifeTm** (UINT) | Tempo di vita socket, se non sono | | | ricevuti o inviati dati dopo il | | | tempo definito il socket viene | | | automaticamente chiuso (Sec). | +-----------------------------------+-----------------------------------+ | **RxSize** (UINT) | Dimensione buffer ricezione dati. | +-----------------------------------+-----------------------------------+ | **TxSize** (UINT) | Dimensione buffer trasmissione | | | dati. | +-----------------------------------+-----------------------------------+ | **Connected** (BOOL) | Attivo se connessione stabilita | | | con server. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo se errore gestione. | +-----------------------------------+-----------------------------------+ | **File** (FILEP) | Stream di I/O valorizzato su | | | connessione stabilita con il | | | sistema server. Se connessione | | | non attiva viene ritornato NULL. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 9941005 | Blocco funzione non supportato. | +-----------------------------------+-----------------------------------+ | 9941050 | Errore allocazione blocco | | | funzione. | +-----------------------------------+-----------------------------------+ | 9941060 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 9941070 | Errore versione blocco funzione. | +-----------------------------------+-----------------------------------+ | 9941100 | Blocco funzione eseguito in task | | | diversa da Back. | +-----------------------------------+-----------------------------------+ | 9941115 | Errore apertura socket. | +-----------------------------------+-----------------------------------+ | 9941120 | Errore set socket option. | +-----------------------------------+-----------------------------------+ | 9941125 | Errore definizione IP locale. | +-----------------------------------+-----------------------------------+ | 9941130 | Errore bind. | +-----------------------------------+-----------------------------------+ | 9941135 | Errore risoluzione indirizzo | +-----------------------------------+-----------------------------------+ | 9941140 | Errore connect. | +-----------------------------------+-----------------------------------+ | 9941990 | Non implementata nel simulatore. | +-----------------------------------+-----------------------------------+ **Esempi** """""""""""""" Nell'esempio è attivata una connessione verso un server TCP in ascolto sulla porta 1000. Eseguita la connessione i caratteri ricevuti dal server sono reinviati in echo. La porta locale è fissata a 1000. **Definizione variabili** |image7| **Esempio FBD** *(PTP116B000, FBD_SysTCPClient)* |image8| Un esempio identico al precedente in linguaggio ST Nell'esempio ho lasciato il client libero di scegliersi la porta. **Definizione variabili** |image9| **Esempio FBD** *(PTP116B000, FBD_SysTCPClient)* .. code-block:: none (\* TCPClient initialization. \*) IF (SysFirstLoop) THEN TCPClient.PeerAdd:=ADR('192.168.0.77'); (\* Peer address \*) TCPClient.PeerPort:=1000; (\* Peer port \*) TCPClient.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) TCPClient.LocalPort:=0; (\* Local port \*) TCPClient.FlushTm:=50; (\* Flush time (mS) \*) TCPClient.LifeTm:=20; (\* Life time (S) \*) TCPClient.RxSize:=128; (\* Rx buffer size \*) TCPClient.TxSize:=128; (\* Tx buffer size \*) END_IF; (\* Manage the TCP client. \*) TCPClient(Connect:=TRUE); (\* TCPClient management \*) Fp:=TCPClient.File; (\* File pointer \*) (\* Execute the echo loop. \*) IF (SysFIsOpen(Fp)) THEN IF (TO_BOOL(SysGetIChars(Fp)) AND TO_BOOL(SysGetOSpace(Fp))) THEN i:=Sysfputc(Sysfgetc(Fp), Fp); (\* Character echo \*) END_IF; END_IF; |image10| Per testare l'esempio è possibile utilizzare il programma Toolly scaricabile dal nostro sito. Aprendo una sessione terminale SysUDPServer, accepts UDP connections ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+--------------+ | **Type** | **Library** | | | | +----------+--------------+ | FB | XTarget_12_0 | +----------+--------------+ |image11| Questa function block gestisce la comunicazione con protocollo UDP in modalità server. Occorre fornire l'indirizzo di un array di flussi dati streams al parametro **FilesArr**. Occorre definire la porta UDP da porre in ascolto ed il numero di connessioni contemporanee accettate. Attivando il comando **Enable** il server UDP viene posto in ascolto sulla porta indicata, sulla connessione di un client viene incrementato il numero di **ConnPeers** ed uno degli stream definiti in **FileArr** viene valorizzato ed aperto. Sullo stream aperto è possibile utilizzare le funzioni di TermIO per gestire la comunicazione. Per modificare i parametri occorre disattivare e poi riabilitare il comando **Enable**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando abilitazione server | +-----------------------------------+-----------------------------------+ | **FilesArr** (@FILEP) | Pointer ad array streams di I/O. | | | I vari file streams saranno | | | valorizzati alla connessione dei | | | clients. Occorre definire un | | | numero di streams pari al numero | | | di connessioni contemporanee | | | accettate. | +-----------------------------------+-----------------------------------+ | **LocalAdd** (@USINT) | Range indirizzi IP da cui è | | | accettata la connessione. La | | | connessione è accettata se | | | indirizzo IP del peer in AND con | | | il valore non viene modificato. | | | **Default '0.0.0.0':** | | | connessione accettata da tutti | | | gli indirizzi IP. | +-----------------------------------+-----------------------------------+ | **LocalPort** (UINT) | Numero di porta in ascolto sul | | | server. | +-----------------------------------+-----------------------------------+ | **MaxConn** (USINT) | Numero massimo di connessioni | | | contemporanee accettate dal | | | server. Deve essere uguale al | | | numero di files definiti. | +-----------------------------------+-----------------------------------+ | **FlushTm** (UINT) | Tempo di flush dati, se non sono | | | caricati dati sullo **stream** | | | dopo il tempo definito i dati | | | presenti vengono automaticamente | | | inviati (mS). | +-----------------------------------+-----------------------------------+ | **LifeTm** (UINT) | Tempo di vita socket, se non sono | | | ricevuti o inviati dati dopo il | | | tempo definito il socket viene | | | automaticamente chiuso (Sec). Se | | | definito tempo “0” il socket non | | | viene mai chiuso. | +-----------------------------------+-----------------------------------+ | **RxSize** (UINT) | Dimensione buffer ricezione dati. | +-----------------------------------+-----------------------------------+ | **TxSize** (UINT) | Dimensione buffer trasmissione | | | dati. | +-----------------------------------+-----------------------------------+ | **Enabled** (BOOL) | Attivo se TCP server | | | correttamente impostato e pronto. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo se errore gestione. | +-----------------------------------+-----------------------------------+ | **ConnPeers** (FILEP) | Numero di clients connessi al | | | server. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 9944005 | Blocco funzione non supportato. | +-----------------------------------+-----------------------------------+ | 9944050 | Errore allocazione blocco | | | funzione. | +-----------------------------------+-----------------------------------+ | 9944060 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 9944070 | Errore versione blocco funzione. | +-----------------------------------+-----------------------------------+ | 9944100 | Blocco funzione eseguito in task | | | diversa da Back. | +-----------------------------------+-----------------------------------+ | 9944110 | File pointer non NULL. | +-----------------------------------+-----------------------------------+ | 9944115 | Errore apertura socket. | +-----------------------------------+-----------------------------------+ | 9944120 | Errore set socket option. | +-----------------------------------+-----------------------------------+ | 9944125 | Errore definizione IP locale. | +-----------------------------------+-----------------------------------+ | 9944130 | Errore bind. | +-----------------------------------+-----------------------------------+ | 9944990 | Non implementata nel simulatore. | +-----------------------------------+-----------------------------------+ **Esempi** """""""""""" Nell'esempio è attivato un server UDP in ascolto sulla porta 2000. Il server accetta massimo 2 connessioni. Connettendosi in telnet alla porta 1005 inviando un carattere se ne riceve l'echo. **Definizione variabili** |image12| **Esempio FBD** *(PTP116B000, FBD_SysUDPServer)* |image13| Un esempio identico funzionalmente al precedente realizzato in linguaggio ST **Definizione variabili** |image14| **Esempio ST** *(PTP116B000, ST_SysUDPServer)* .. code-block:: none (\* UDPServer initialization. \*) IF (SysFirstLoop) THEN UDPServer.FilesArr:=ADR(Fp); (\* Files array \*) UDPServer.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) UDPServer.LocalPort:=1000; (\* Local port \*) UDPServer.MaxConn:=2; (\* Accepted connections \*) UDPServer.FlushTm:=50; (\* Flush time (mS) \*) UDPServer.LifeTm:=0; (\* Life time (S) \*) UDPServer.RxSize:=128; (\* Rx buffer size \*) UDPServer.TxSize:=128; (\* Tx buffer size \*) END_IF; (\* Manage the UDP server. \*) UDPServer(Enable:=TRUE); (\* UDPServer management \*) (\* Execute the echoes loop on opened connections. \*) FOR j:=0 TO (UDPServer.MaxConn-1) DO (\* Check if UDP connection is opened. \*) IF (SysFIsOpen(Fp[j])) THEN IF (TO_BOOL(SysGetIChars(Fp[j])) AND TO_BOOL(SysGetOSpace(Fp[j]))) THEN i:=Sysfputc(Sysfgetc(Fp[j]), Fp[j]); (\* Character echo \*) END_IF; END_IF; END_FOR; |image15| Per testare l'esempio è possibile utilizzare il programma Toolly scaricabile dal nostro sito. Aprendo una sessione terminale SysUDPClient, opens a UDP connection ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+--------------+ | **Type** | **Library** | +----------+--------------+ | FB | XTarget_12_0 | +----------+--------------+ |image16| Questa function block gestisce la comunicazione con protocollo UDP in modalità client. Occorre definire l'indirizzo IP **PeerAdd** e la porta TCP **PeerPort** del sistema server a cui ci si vuole connettere. Attivando il comando **Connect** viene aperta la connessione con il sistema server. Se la connessione và a buon fine viene attivato **Connected** e sull'uscita **File** viene ritornato lo stream da utilizzarsi per lo scambio dati con il sistema server. Se la connessione non è possibile viene generato **Fault**. +-----------------------------------+-----------------------------------+ | **Connect** (BOOL) | Comando abilitazione connessione | +-----------------------------------+-----------------------------------+ | **PeerAdd**\ (@USINT) | Indirizzo IP del sistema server a | | | cui connettersi. | +-----------------------------------+-----------------------------------+ | **PeerPort** (UINT) | Numero porta UDP a cui | | | connettersi. | +-----------------------------------+-----------------------------------+ | **LocalAdd** (@USINT) | Indirizzo IP della interfaccia di | | | rete da cui effettuare la | | | connessione. | | | | | | **Default '0.0.0.0':** | | | l'interfaccia è scelta | | | automaticamente in base all'IP a | | | cui connettersi. | +-----------------------------------+-----------------------------------+ | **LocalPort** (UINT) | Numero porta UDP da cui parte la | | | connessione (0 scelta | | | automaticamente). | +-----------------------------------+-----------------------------------+ | **FlushTm** (UINT) | Tempo di flush dati, se non sono | | | caricati dati sullo **stream** | | | dopo il tempo definito i dati | | | presenti vengono automaticamente | | | inviati (mS). | +-----------------------------------+-----------------------------------+ | **LifeTm** (UINT) | Tempo di vita socket, se non sono | | | ricevuti o inviati dati dopo il | | | tempo definito il socket viene | | | automaticamente chiuso (Sec). | +-----------------------------------+-----------------------------------+ | **RxSize** (UINT) | Dimensione buffer ricezione dati. | +-----------------------------------+-----------------------------------+ | **TxSize** (UINT) | Dimensione buffer trasmissione | | | dati. | +-----------------------------------+-----------------------------------+ | **Connected** (BOOL) | Attivo se connessione stabilita | | | con server. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo se errore gestione. | +-----------------------------------+-----------------------------------+ | **File** (FILEP) | Stream di I/O, viene valorizzato | | | su connessione stabilita con il | | | sistema server. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 9943005 | Blocco funzione non supportato. | +-----------------------------------+-----------------------------------+ | 9943050 | Errore allocazione blocco | | | funzione. | +-----------------------------------+-----------------------------------+ | 9943060 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 9943070 | Errore versione blocco funzione. | +-----------------------------------+-----------------------------------+ | 9943100 | Blocco funzione eseguito in task | | | diversa da Back. | +-----------------------------------+-----------------------------------+ | 9943115 | Errore apertura socket. | +-----------------------------------+-----------------------------------+ | 9943120 | Errore set socket option. | +-----------------------------------+-----------------------------------+ | 9943125 | Errore definizione IP locale. | +-----------------------------------+-----------------------------------+ | 9943130 | Errore bind. | +-----------------------------------+-----------------------------------+ | 9943135 | Errore risoluzione indirizzo | +-----------------------------------+-----------------------------------+ | 9943145 | Errore apertura file. | +-----------------------------------+-----------------------------------+ | 9943990 | Non implementata nel simulatore. | +-----------------------------------+-----------------------------------+ **Esempi** """"""""""""""" Nell'esempio è attivata una connessione verso un server TCP in ascolto sulla porta 1000. Eseguita la connessione i caratteri ricevuti dal server sono reinviati in echo. **Definizione variabili** |image17| **Esempio FBD** *(PTP116B000, FBD_SysUDPClient)* |image18| Un esempio identico funzionalmente al precedente realizzato in linguaggio ST **Definizione variabili** |image20| **Esempio ST** *(PTP116B000, ST_SysUDPClient)* .. code-block:: none (\* UDPClient initialization. \*) IF (SysFirstLoop) THEN UDPClient.PeerAdd:=ADR('192.168.0.77'); (\* Peer address \*) UDPClient.PeerPort:=1000; (\* Peer port \*) UDPClient.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) UDPClient.LocalPort:=1000; (\* Local port \*) UDPClient.FlushTm:=50; (\* Flush time (mS) \*) UDPClient.LifeTm:=20; (\* Life time (S) \*) UDPClient.RxSize:=128; (\* Rx buffer size \*) UDPClient.TxSize:=128; (\* Tx buffer size \*) END_IF; (\* Manage the TCP client. \*) UDPClient(Connect:=TRUE); (\* UDPClient management \*) Fp:=UDPClient.File; (\* File pointer \*) (\*---------------------------------------------------------------------\*) (\* ECHO LOOP \*) (\*---------------------------------------------------------------------\*) (\* Execute the echo loop. \*) IF (SysFIsOpen(Fp)) THEN IF (TO_BOOL(SysGetIChars(Fp)) AND TO_BOOL(SysGetOSpace(Fp))) THEN i:=Sysfputc(Sysfgetc(Fp), Fp); (\* Character echo \*) END_IF; END_IF; |image21| Per testare l'esempio è possibile utilizzare il programma Toolly scaricabile dal nostro sito. Aprendo una sessione terminale SysGetIpInfos, returns IP infos ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+--------------+ | **Type** | **Library** | | | | +----------+--------------+ | FB | XTarget_12_0 | +----------+--------------+ |image22| Questo blocco funzione ritorna le informazioni della connessione. Passando al blocco funzione un File di tipo TCP o UDP è possibile avere in uscite le informazioni relative. +-----------------------------------+-----------------------------------+ | **File** (FILEP) | File pointer (Deve essere di tipo | | | TCP o UDP). | +-----------------------------------+-----------------------------------+ | **PeerIP** (STRING[15]) | Stringa di definizione indirizzo | | | IP del peer connesso al file. | +-----------------------------------+-----------------------------------+ | **PerrPort** (UINT) | Porta del peer connesso al file. | +-----------------------------------+-----------------------------------+ | **Status** (DWORD) | Stato connessione (Non gestito) | +-----------------------------------+-----------------------------------+ **Esempi** """"""""""" Nell'esempio sono visualizzate le informazioni di connessione al socket. **Definizione variabili** |image23| **Esempio FBD** *(PTP116B000, FBD_SysGetIpInfos)* |image24| SysIPReach, IP address is reachable ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+--------------+ | **Type** | **Library** | +----------+--------------+ | FB | XTarget_07_0 | +----------+--------------+ |image25| Questo blocco funzione esegue controllo se un indirizzo IP è raggiungibile, viene eseguito l'invio del comando Ping al sistema e se si ottiene risposta viene attivato **Done**. La variabile **Refresh** ritorna la percentuale di tempo trascorsa dall'ultima esecuzione del comando Ping sul sistema. Raggiunto il 50% del tempo circa 25 Secondi viene eseguito un nuovo comando Ping. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Abilitazione blocco funzione, | | | attivandolo viene eseguito un | | | ping ogni 25 Sec | +-----------------------------------+-----------------------------------+ | **PeerIP** (STRING[15]) | Stringa di definizione indirizzo | | | IP di cui eseguire la ricerca. | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Attivo se indirizzo IP è | | | raggiungibile (Risposta da Ping). | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | se errore gestione. | +-----------------------------------+-----------------------------------+ | **Refresh** (USINT) | Percentuale di tempo da ultima | | | esecuzione Ping. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 9974005 | Blocco funzione non supportato. | +-----------------------------------+-----------------------------------+ | 9974050 | Errore allocazione blocco | | | funzione. | +-----------------------------------+-----------------------------------+ | 9974060 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 9974070 | Errore versione blocco funzione. | +-----------------------------------+-----------------------------------+ | 9974100 | Blocco funzione eseguito in una | | | task diversa da Back. | +-----------------------------------+-----------------------------------+ | 9974110 | Errore indirizzo IP definito | | | **PeerIP**. | +-----------------------------------+-----------------------------------+ | 9974200 | Errore invio richiesta Ping. | +-----------------------------------+-----------------------------------+ | 9974250 | Errore risposta a richiesta Ping. | +-----------------------------------+-----------------------------------+ | 9974990 | Non implementata nel simulatore. | +-----------------------------------+-----------------------------------+ **Esempi** """""""""""" Nell'esempio viene controllato se l'indirizzo IP **8.8.8.8** è raggiungibile, in tal caso si attiva l'uscita **Done**. **Definizione variabili** |image26| **Esempio LD** *(PTP116B000, FBD_SysIPReach)* |image27| UDPDataTxfer, UDP data transfer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+----------------------+ | **Type** | **Library** | | | | +----------+----------------------+ | FB | eLLabNetworkLib_A000 | +----------+----------------------+ |image28| Questo blocco funzione esegue il trasferimento di un blocco di memoria tra due sistemi utilizzando una connessione UDP su rete ethernet. Occorre passare alla FB un flusso dati **stream** indicato dal parametro **File**, precedentemente aperto dalla funzione `Sysfopen <#FctSysfopen>`__ ed il socket deve essere stato posto in condizione di listening dalla FB `SysSktListen <#FblSysSktListen>`__. Il parametro **PeerIP** indica l'indirizzo IP del sistema con cui avviene il trasferimento dati, **Port** indica la porta tramite la quale il trasferimento avviene (Deve assumere lo stesso valore su entrambi i sistemi). Il parametro **Timeout** definisce il tempo massimo per il trasferimento dei dati, l'invio dei dati si conclude con la ricezione di un acknowledge da parte dell'altro sistema, un ciclo di invio dati e ricezione acknowledge richiede 2 loop di esecuzione programma. Se dopo l'invio non viene ricevuto Ack entro un tempo pari a **Timeout/4**, viene effettuato un altro invio e cosi di seguito fino allo scadere del tempo definito. Per garantire almeno 3 retries si consiglia di **impostare come tempo di timeout un valore pari a 10 volte il tempo massimo di loop** (Scegliendo quello maggiore tra i due sistemi in comunicazione). L'invio dei dati è automatico sulla variazione di uno qualsiasi dei bytes del buffer di trasmissione, per garantire il controllo sul collegamento tra i due sistemi, ogni tempo pari a **Timeout** viene comunque eseguito un invio del buffer di memoria. Se i due sistemi sono in comunicazione si attiva l'uscita **Done**, **RxDataOk** si attiva per un loop ad ogni ricezione del buffer dati dall'altro sistema, mentre **TxDataSent** si attiva per un loop al termine della trasmissione del buffer dati verso l'altro sistema. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Abilitazione blocco funzione. | +-----------------------------------+-----------------------------------+ | **File** (FILEP) | Flusso dati **stream** ritornato | | | dalla funzione **Sysfopen**. | +-----------------------------------+-----------------------------------+ | **PeerIP** (STRING[15]) | Stringa di definizione indirizzo | | | IP del sistema con cui avviene il | | | trasferimento dati. | +-----------------------------------+-----------------------------------+ | **Port** (UINT]) | Porta tramite la quale avviene il | | | trasferimento dati (Stesso valore | | | su entrambi i sistemi). | +-----------------------------------+-----------------------------------+ | **RxDBuffer** (@USINT]) | Puntatore al buffer dove devono | | | essere trasferiti i dati | | | ricevuti. | +-----------------------------------+-----------------------------------+ | **TxDBuffer** (@USINT]) | Puntatore al buffer dove sono | | | presenti i dati da trasmettere. | +-----------------------------------+-----------------------------------+ | **ByteNr** (UDINT]) | Numero di bytes scambiati. | +-----------------------------------+-----------------------------------+ | **Timeout** (UINT]) | Tempo massimo per il | | | trasferimento del buffer dati | | | (mS). | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Attivo se i due sistemi sono in | | | comunicazione tra di loro. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | se errore gestione. | +-----------------------------------+-----------------------------------+ | **RxDataOk** (BOOL) | Attivo per un loop di programma | | | su ricezione buffer dati da altro | | | sistema. | +-----------------------------------+-----------------------------------+ | **TxDataSent** (BOOL) | Attivo per un loop di programma | | | al termine trasmissione buffer | | | dati verso altro sistema. | +-----------------------------------+-----------------------------------+ | **Errors** (UINT]) | Numero di errori, incrementato ad | | | ogni nuovo errore, raggiunto | | | valore massimo riparte da 0. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 10014050 | Valore di **File** non definito. | +-----------------------------------+-----------------------------------+ | 10014100 | Terminato spazio memoria | | | rilocabile, non è possibile | | | eseguire l''FB. | +-----------------------------------+-----------------------------------+ | 10014200~2 | Errore ricezione frame dati | | | blocco di memoria. | +-----------------------------------+-----------------------------------+ | 10014300~2 | Errore ricezione frame | | | acknowledge. | +-----------------------------------+-----------------------------------+ | 10014400 | Ricevuto comando non gestito. | +-----------------------------------+-----------------------------------+ | 10014500~1 | Errore sequenze di trasmissione. | +-----------------------------------+-----------------------------------+ | 10014600 | Timeout invio frame dati blocco | | | di memoria. | +-----------------------------------+-----------------------------------+ **Esempi** """""""""""""" Nell'esempio viene scambiato un blocco di memoria di 16 bytes verso il sistema con IP 192.168.0.126. **Definizione variabili** |image29| **Esempio LD** *(PTP119A300, UDPDataTransfer)* |image30| DataStreamExch_v1, exchanges data between two I/O streams ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | Function | eLLabNetworkLib_A600 | +-----------------------+-----------------------+ |image31| Questo blocco funzione esegue lo scambio data tra due streams di I/O. Definendo uno stream come socket TCP e l'altro come seriale è possibile realizzare un convertitore Ethernet/Seriale. In **FpA** ed **FpB** occorre indicare i file pointers degli streams di I/O. Il FB riceve i dati da uno stream e li invia sull'altro stream. Per il trasferimento dei dati viene allocato dinamicamente un buffer di memoria che può raggiungere al massimo la dimensione definita in **DBMax** (Si consiglia 2048 bytes). Se non c'è comunicazione tra gli streams dopo il tempo definito in **DBLife** (Si consiglia 5 secondi) il buffer di memoria viene disallocato liberando risorse di sistema. Se valore impostato è 0 il buffer non viene mai disallocato. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Abilitazione blocco funzione. | +-----------------------------------+-----------------------------------+ | **FpA** (FILEP) | Flusso dati **stream** di | | | comunicazione. | +-----------------------------------+-----------------------------------+ | **FpB** (FILEP) | Flusso dati **stream** di | | | comunicazione. | +-----------------------------------+-----------------------------------+ | **DBMax** (UINT) | Dimensione massima allocazione | | | buffer dati (Bytes). Valore | | | massimo 4096. | +-----------------------------------+-----------------------------------+ | **DBLife** (REAL) | Tempo di vita buffer dati (S). | +-----------------------------------+-----------------------------------+ | **Enabled** (BOOL) | Blocco funzione abilitato. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | in caso di errore. | +-----------------------------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +----------+----------------------+ | 10048100 | Errore valore DBMax. | +----------+----------------------+ **Esempi** """"""""""""" Semplice convertitore Ethernet/Seriale, accetta connessione TCP su porta 2000 e utilizza la porta seriale COM0. **Definizione variabili** |image33| **Esempio ST** *(PTP119B400, ST_DataStreamExch_v1)* .. code-block:: none (\* INITIALIZATIONS \*) (\* Program initializations. \*) IF (SysFirstLoop) THEN (\* Initialize serial port. \*) Sp.COM:=ADR('COM0'); (\* Serial port \*) Sp.Baudrate:=115200; (\* Baud rate \*) Sp.Parity:='E'; (\* Parity \*) Sp.DataBits:=8; (\* Data bits \*) Sp.StopBits:=1; (\* Stop bits \*) Sp.DTRManagement:=DTR_AUTO_WO_TIMES; (\* DTR management \*) (\* Initialize socket server. \*) Sk.FilesArr:=ADR(Fp); (\* File array \*) Sk.MaxConn:=1; (\* Number of connections accepted \*) Sk.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) Sk.LocalPort:=2000; (\* Local port \*) Sk.LifeTm:=60; (\* TSocket life time (S) \*) Sk.FlushTm:=10; (\* Socket flush time (mS) \*) Sk.RxSize:=1024; (\* Rx size buffer \*) Sk.TxSize:=1024; (\* Tx size buffer \*) (\* Initialize data stream exchange . \*) DExch.DBMax:=2048; (\* Data buffer maximum size \*) DExch.DBLife:=5.0; (\* Data buffer life (S) \*) END_IF; (\* DATA STREAM EXCHANGE \*) (\* Execute the data stream exchange. \*) Sp(Open:=TRUE); (\* Serial port management \*) Sk(Enable:=TRUE); (\* TCP server management \*) DExch.FpA:=Sp.File; (\* File pointer \*) DExch.FpB:=Fp; (\* File pointer \*) DExch(Enable:=(Sk.ConnPeers <> 0)); (\* Data exchange \*) (\* [End of file] \*) ModbusTCPGateway_v1, modbus TCP gateway ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | eLLabNetworkLib_A700 | +-----------------------+-----------------------+ |image34| Questo blocco funzione opera come gateway Modbus tra una connessione modbus TCP ed una connessione seriale Modbus RTU. Il FB può gestire più streams Modbus TCP, per questo in **FpTCP** occorre passare l'array di streams di I/O da cui arrivano le richieste Modbus TCP. In **FpRTU** occorre passare lo stream verso cui sono inviate le richieste convertite in Modbus RTU. In MaxConn occorre definire il numero di connessioni massime gestite sullo stream Modbus TCP. In **IFTime** occorre definire il tempo di pausa su ricezione caratteri da porta seriale (Modbus RTU). In **Timeout** si definisce il tempo massimo di esecuzione di un comando Modbus TCP (Da quando il comando viene ricevuto a quando dopo la conversione in RTU viene ritornata la risposta). L'ingresso **SpyOn** se attivo permette di spiare il funzionamento della FB. In caso di errore esecuzione o tempo di esecuzione superiore al tempo definito in Timeout, viene attivata per un loop di programma l'uscita **Fault**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Abilitazione blocco funzione. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **MaxConn** (USINT) | Numero massimo di **streams** di | | | I/O connessioni Modbus TCP | | | gestiti. | +-----------------------------------+-----------------------------------+ | **FpTCP** (@FILEP) | Pointer ad array **streams** di | | | I/O delle connessioni Modbus TCP. | +-----------------------------------+-----------------------------------+ | **FpRTU** (FILEP) | Flusso dati **stream** della | | | connessione Modbus RTU. | +-----------------------------------+-----------------------------------+ | **IFTime** (UDINT) | Tempo ricezione caratteri (μS), | | | deve essere definito in base al | | | baud rate. | | | | | | | 300 Baud - 112000 (uS) | | | | 600 Baud - 56000 (uS) | | | | 1200 Baud - 28000 (uS) | | | | 2400 Baud - 14000 (uS) | | | | 4800 Baud - 7000 (uS) | | | | 9600 Baud - 3430 (uS) | | | | 19200 Baud - 1720 (uS) | | | | 38400 Baud - 860 (uS) | | | | 57600 Baud - 573 (uS) | | | | 76800 Baud - 429 (uS) | | | | 115200 Baud - 286 (uS) | +-----------------------------------+-----------------------------------+ | **Timeout** (UINT) | Tempo massimo esecuzione comando | | | espresso in mS. Se il comando non | | | termina nel tempo definito viene | | | abortito ed attivata l'uscita | | | **Fault**. | +-----------------------------------+-----------------------------------+ | **Enabled** (BOOL) | Blocco funzione abilitato. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | in caso di errore. | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+----------------------------------------------+ | **TFlags** | **Descrizione** | +-------------+----------------------------------------------+ | 16#00000001 | **Tx:** Invio frame comando modbus RTU. | +-------------+----------------------------------------------+ | 16#00000002 | **Rx:** Ricezione frame risposta modbus RTU. | +-------------+----------------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +------------+-----------------------------------+ | 10053050 | Timeout esecuzione. | +------------+-----------------------------------+ | 10053100~1 | Errori gestione frame Modbus TCP. | +------------+-----------------------------------+ | 10053200~1 | Errori gestione frame Modbus RTU. | +------------+-----------------------------------+ **Esempi** """""""""""""" Semplice gateway Modbus TCP/RTU, accetta 1 connessione TCP su porta 2000 e utilizza la porta seriale COM2. **Definizione variabili** .. code-block:: none **VAR** **Fp : FILEP; (\* File pointer \*)** **MTCPGw : ModbusTCPGateway_v1; (\* Modbus TCP gateway \*)** **TCPServer : SysTCPServer; (\* TCP server \*)** **SPort : SysSerialPort; (\* Serial port \*)** **END_VAR** **Esempio ST** *(PTP119B500, ST_ModbusTCPGateway_v1)* .. code-block:: none (\* INITIALIZATIONS \*) (\* Program initializations. \*) IF (SysFirstLoop) THEN (\* Initialize serial port. \*) SPort.COM:=ADR('COM2'); (\* Serial port \*) SPort.Baudrate:=19200; (\* Baud rate \*) SPort.Parity:='E'; (\* Parity \*) SPort.DataBits:=8; (\* Data bits \*) SPort.StopBits:=1; (\* Stop bits \*) SPort.DTRManagement:=DTR_AUTO_WO_TIMES; (\* DTR management \*) (\* Initialize socket server. \*) TCPServer.FilesArr:=ADR(Fp); (\* File array \*) TCPServer.MaxConn:=1; (\* Number of connections accepted \*) TCPServer.LocalAdd:=ADR('0.0.0.0'); (\* Local address \*) TCPServer.LocalPort:=2000; (\* Local port \*) TCPServer.LifeTm:=60; (\* TSocket life time (S) \*) TCPServer.FlushTm:=10; (\* Socket flush time (mS) \*) TCPServer.RxSize:=512; (\* Rx size buffer \*) TCPServer.TxSize:=512; (\* Tx size buffer \*) (\* Initialize Modbus TCP gateway. \*) MTCPGw.IFTime:=1720; (\* Interframe time \*) MTCPGw.Timeout:=500; (\* Command execution timeout (mS) \*) END_IF; (\* MODBUS TCP/RTU GATEWAY \*) (\* Execute the Modbus TCP/RTU gateway. \*) SPort(Open:=TRUE); (\* Serial port management \*) TCPServer(Enable:=TRUE); (\* TCP server management \*) MTCPGw.MaxConn:=TCPServer.MaxConn; (\* Number of connections accepted \*) MTCPGw.FpRTU:=SPort.File; (\* File pointer (Modbus RTU) \*) MTCPGw.FpTCP:=ADR(Fp); (\* File pointer (Modbus TCP) \*) MTCPGw(Enable:=(TCPServer.ConnPeers <> 0)); (\* Modbus TCP gateway \*) (\* [End of file] \*) **Esempi** """""""""""" Semplice gateway Modbus TCP/RTU, accetta 3 connessione TCP su porta 1000 e utilizza la porta seriale COM0. **Definizione variabili** **VAR** **TCPServer : SysTCPServer; (\* TCP server \*)** **SPort : SysSerialPort; (\* Serial port \*)** **MTCPGw : ModbusTCPGateway_v1; (\* Modbus TCP gateway \*)** **Fp : ARRAY[ 0..2 ] OF FILEP; (\* File pointer \*)** **END_VAR** **Esempio FBD** *(PTP119B500, FBD_ModbusTCPGateway_v1)* |image35| SNTPRequest, sends a SNTP request +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | eLLabNetworkLib_A100 | +-----------------------+-----------------------+ |image36| Questo blocco funzione esegue la lettura da un server di tempo del valore di UTC. Attivando il comando di **Query** viene eseguita la richiesta del valore di tempo dal server il cui indirizzo IP è passato in **NTPServer**. L'FB interroga il server e se riceve risposta corretta ritorna in **UTCTime** il valore di tempo UTC in Epoch. In **Offset** viene ritornata la differenza in mS tra il valore UTC ritornato e l'orologio NTP di riferimento. Terminata l'esecuzione si attiva l'uscita **Done**, per effettuare una nuova lettura di tempo occorre disattivare e poi riattivare l'ingresso **Query**. In **RTDelay** è ritornato il tempo necessario all'invio della richiesta ed alla ricezione della risposta dal server NTP. +-----------------------------------+-----------------------------------+ | **Query** (BOOL) | Comando attivazione richiesta. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB | +-----------------------------------+-----------------------------------+ | **NTPServer** (@USINT) | Pointer definizione server NTP. | | | Può essere definito sia l'IP che | | | l'URL. | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Attivo a fine esecuzione, si | | | attiva anche in caso di | | | **Fault**. | +-----------------------------------+-----------------------------------+ | **Ok** (BOOL) | Attivo per un loop di programma | | | se query eseguita correttamente. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | se errore gestione. | +-----------------------------------+-----------------------------------+ | **RTDelay** (REAL) | Round trip delay, tempo per | | | inviare la richiesta e ricevere | | | la risposta dal server (mS). | +-----------------------------------+-----------------------------------+ | **UTCTime** (UDINT) | Data/Ora in UTC espressa in Epoch | | | time. | +-----------------------------------+-----------------------------------+ | **Offset** (REAL]) | Differenza tra il valore UTC | | | ritornato e l'orologio NTP di | | | riferimento (mS). | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+----------------------------------------------+ | **TFlags** | **Descrizione** | +-------------+----------------------------------------------+ | 16#00000001 | '--' Informazioni stato richiesta NTP. | +-------------+----------------------------------------------+ | 16#00000002 | '--' Report di tutte le operazioni eseguite. | +-------------+----------------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 10052010 | FB eseguita in una task diversa | | | dalla task di background. | +-----------------------------------+-----------------------------------+ | 10052110 | Errore connessione UDP. Se attivo | | | Spy viene ritornato in Spy numero | | | di errore connessione UDP. | +-----------------------------------+-----------------------------------+ | 10014200~2 | Errore nelle sequenze di | | | gestione. | +-----------------------------------+-----------------------------------+ **Esempi** """""""""""""" Nell'esempio attivando l'ingresso **Di00M00** viene richiesto il tempo dal server ntp1.inrim.it ed aggiornato il real time clock del sistema **Definizione variabili** |image40| **Esempio LD** *(PTP119B000, LD_SNTPRequest)* |image41| **Definizione variabili** |image42| **Esempio ST** .. code-block:: none (\* Check if time theshold to perform synchronization (Every 60 Sec).\*) IF ((SysGetUTCDateTime(TRUE)-TimeRef) > 60) THEN TimeRef:=SysGetUTCDateTime(TRUE); (\* UTC Date/Time reference \*) SNTPReq.Query:=TRUE; (\* Query On \*) END_IF; (\* Manage the NTP request to the server. \*) SNTPReq(NTPServer:=ADR('0.pool.ntp.org')); (\* NTP request \*) (\* Execution done, if Ok set the real time clock. \*) IF (SNTPReq.Done) THEN SNTPReq.Query:=FALSE; (\* Query On \*) IF (SNTPReq.Ok) THEN i:=SysSetUTCDateTime(SNTPReq.UTCTime); END_IF; END_IF; DNSRequest, sends a DNS request ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+----------------------+ | **Type** | **Library** | +----------+----------------------+ | FB | eLLabNetworkLib_A000 | +----------+----------------------+ |image43| Questo blocco funzione invia una richiesta DNS. Indicando in **DNSServerIP** l'indirizzo IP di un server DNS (Esempio quello di Google 8.8.8.8) è possibile effettuare la richiesta di risoluzione di un dominio. Viene ritornato l'indirizzo IP ed il tempo di vita dell'URL. Attivando l'ingresso **Enable** viene effettuata la richiesta di risoluzione dell'URL al server DNS. Se il server risolve l'URL viene attivata l'uscita **Done** e su **DomainIP** viene ritornato l'IP relativo. Se **Enable** rimane attivo il FB controlla in tempo di vita della voce DNS ed esegue il riaggiornamento automatico dell'indirizzo IP. L'ingresso **SpyOn** se attivo permette di spiare il funzionamento del FB. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando abilitazione esecuzione. | | | Per rieseguire il comando | | | disabilitare e poi riabilitare | | | questo ingresso. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **DNSServerIP** (STRING[15]) | Stringa di definizione IP server | | | DNS. | +-----------------------------------+-----------------------------------+ | **Domain** (@USINT) | Indirizzo stringa definizione URL | | | di cui si desidera risolvere | | | l'IP. | +-----------------------------------+-----------------------------------+ | **QType** (UINT) | Tipo di query. | | | | | | | 16#0001: | | | | A record (host addresses). | | | | | | | 16#0002: | | | | Name servers (NS) records. | | | Not managed | | | | | | | 16#000F: | | | | Mail server (MX). | | | | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Si attiva al termine della | | | esecuzione comando. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop se errore | | | esecuzione comando. | +-----------------------------------+-----------------------------------+ | **Domain** (STRING[15]) | Stringa di definizione IP | | | trovato. | +-----------------------------------+-----------------------------------+ | **RTime** (UDINT) | Tempo riferimento per controllo | | | sul tempo di vita richiesta (uS). | +-----------------------------------+-----------------------------------+ | **TTL** (UDINT) | Tempo di vita richiesta (S). | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+---------------------------------+ | **TFlags** | **Descrizione** | +-------------+---------------------------------+ | 16#00000001 | **Tx:** Invio richiesta DNS. | +-------------+---------------------------------+ | 16#00000002 | **Rx:** Ricezione risposta DNS. | +-------------+---------------------------------+ | 16#10000000 | **Lg:** Messaggio di log. | +-------------+---------------------------------+ | 16#20000000 | **Wr:** Messaggio di warning. | +-------------+---------------------------------+ | 16#40000000 | **Er:** Messaggio di errore. | +-------------+---------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +------------+-----------------------------------------------------------+ | **Codice** | **Descrizione** | +------------+-----------------------------------------------------------+ | 10055010 | FB eseguita in una task diversa dalla task di background. | +------------+-----------------------------------------------------------+ | 10055020 | **File** non corretto. | +------------+-----------------------------------------------------------+ | 10055100 | Errore lunghezza nome dominio da risolvere. | +------------+-----------------------------------------------------------+ | 10055200 | Timeout risposta da server. | +------------+-----------------------------------------------------------+ | 10055210~5 | Formato pacchetto ricevuto non corretto. | +------------+-----------------------------------------------------------+ | 10055800 | Errore esecuzione. | +------------+-----------------------------------------------------------+ **Esempi** """"""""""""" Nell'esempio attivando **Di00CPU** viene richiesto l'indirizzo IP di “elsist.it” al server DNS di Google. **Definizione variabili** |image44| **Esempio LD** *(PTP119B000, LD_DNSRequest)* |image45| HTTPClient, HTTP client ^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+----------------------+ | **Type** | **Library** | | | | +----------+----------------------+ | FB | eLLabNetworkLib_A700 | +----------+----------------------+ |image46| Questo blocco funzione esegue la richiesta di una pagina web con il protocollo HTTP. Attivando **Enable** viene inviata la richiesta HTTP della pagina definita in **Page** all'indirizzo IP o all'URL del server definito in **HostAddress**. E' possibile definire anche l'\ **HostName** che sarà utilizzato nella richiesta (Di solito è uguale a **HostAddress**). La pagina viene richiesta con i parametri definiti nel buffer **Request** passati secondo la definizione di **Method** (GET o POST). In **DBSize** occorre definire la dimensione del buffers che l'FB alloca (Con SysRMalloc) per la gestione dei pacchetti TCP in trasmissione e ricezione. La dimensione minima è 256 bytes, aumentando la dimensione si velocizza il trasferimento (Sono effettuati meno frazionamenti). **E' inutile definire lunghezze superiori al limite del pacchetto TCP 1500 bytes**. La pagina viene ricevuta in frammenti successivi in base al tipo di trasferimento del server, ad ogni ricezione di un frammento di pagina **DBChars** viene valorizzato (Per un solo loop di esecuzione) con il numero di bytes ricevuti che possono essere letti dal buffer all'indirizzo **DBAddress**. In questo modo è possibile ricevere pagine di qualsiasi dimensione, sarà cura del programma utente trasferire i dati di pagina rticevuti in una stringa o in un file: Al termine dell'invio della richiesta si attiva per un loop di programma l'uscita **Rsent**, su ricezione pagina si attiva per un loop di programma l'uscita **PLoad** ed in **PLength** è ritornata la lunghezza della pagina ricevuta, mentre in **PLTime** il tempo necessario per l'intera richiesta. In caso di errore esecuzione o tempo di esecuzione comando superiore al tempo definito in **Timeout**, viene attivata per un loop di programma l'uscita **Fault**. L'uscita **Done** si attiva al termine della esecuzione della richiesta e su errore. Per acquisire nuovamente la pagina occorre disabilitare e poi riabilitare l'ingresso **Enable**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando attivazione richiesta | | | pagina. | +-----------------------------------+-----------------------------------+ | **Method** (BOOL) | Metodo gestione richiesta | | | (FALSE=GET, TRUE=POST). | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **HostAddress** (@BYTE) | Indirizzo IP o URL del server a | | | cui connettersi. | +-----------------------------------+-----------------------------------+ | **HostName** (@BYTE) | Nome del server utilizzato nella | | | richiesta (Di solito è uguale a | | | **HostAddress**). | +-----------------------------------+-----------------------------------+ | **HostPort** (UINT) | Numero porta TCP a cui | | | connettersi (Default 80). | +-----------------------------------+-----------------------------------+ | **Page** (@BYTE)) | Stringa di definizione pagina web | | | richiesta. | +-----------------------------------+-----------------------------------+ | **Request** (@BYTE) | Indirizzo buffer dati da inviare | | | con la richiesta. | +-----------------------------------+-----------------------------------+ | **DBSize** (UINT) | Dimensione buffers Rx/Tx allocati | | | da FB (SysRMalloc). Minimo 256 | | | massimo 1500. | +-----------------------------------+-----------------------------------+ | **Timeout** (UINT) | Timeout esecuzione richiesta | | | pagina (mS). | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Attivo a fine esecuzione, si | | | attiva anche in caso di | | | **Fault**. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop di programma | | | se errore gestione. | +-----------------------------------+-----------------------------------+ | **RSent** (BOOL) | Attivo per un loop di programma | | | al termine dell'invio richiesta | | | HTTP. | +-----------------------------------+-----------------------------------+ | **PLoad** (BOOL) | Attivo per un loop di programma | | | su fine ricezione pagina. | | | | | | **I dati di pagina non vanno | | | acquisiti su PLoad ma ad ogni | | | valorizzazione di DBChars.** | +-----------------------------------+-----------------------------------+ | **HTTPStatus** (STRING[64]) | Status risposta HTTP ricevuta. | +-----------------------------------+-----------------------------------+ | **DBAddress** (@BYTE) | Indirizzo buffer dati ricevuti | | | allocato da FB (Con SysRMalloc) | | | di dimensione DBSize. | +-----------------------------------+-----------------------------------+ | **DBChars** (UDINT) | Bytes di pagina ricevuti, viene | | | valorizzato per un loop. | | | | | | **Ad ogni valorizzazione occorre | | | estrarre i dati di pagina da | | | DBAddress.** | +-----------------------------------+-----------------------------------+ | **PLength** (UINT) | Dimensione pagina ricevuta. | +-----------------------------------+-----------------------------------+ | **PLTime** (REAL) | Tempo impiegato per caricamento | | | pagina (S). | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+------------------------------------+ | **TFlags** | **Descrizione** | +-------------+------------------------------------+ | 16#00000001 | 'Tx' Invio dati verso server HTTP | +-------------+------------------------------------+ | 16#00000002 | 'Rx' Ricezione dati da server HTTP | +-------------+------------------------------------+ | 16#00000004 | 'Rq' Stringa richiesta | +-------------+------------------------------------+ | 16#08000000 | 'Lg' Log dati di esecuzione | +-------------+------------------------------------+ | 16#10000000 | 'Pi' Informazioni di pagina | +-------------+------------------------------------+ | 16#40000000 | 'Er' Errori di esecuzione | +-------------+------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +------------+-----------------------------------------------------------+ | **Codice** | **Descrizione** | +------------+-----------------------------------------------------------+ | 10054020 | FB eseguita in una task diversa dalla task di background. | +------------+-----------------------------------------------------------+ | 10054030 | Valore di **DBSize** errato. | +------------+-----------------------------------------------------------+ | 10054100 | Timeout richiesta pagina. | +------------+-----------------------------------------------------------+ | 10054200 | Errore acquisizione valore di lunghezza pagina | +------------+-----------------------------------------------------------+ | 10054210 | Errore ricezione pagina | +------------+-----------------------------------------------------------+ | 10054300 | Errore acquisizione valore di lunghezza chunk | +------------+-----------------------------------------------------------+ **Esempio ricezione pagina su stringa** Nell'esempio attivando **Di00CPU** viene eseguita la richiesta di una pagina sul sito altervista, sono passati in GET 2 parametri **Dividend** e **Divisor**. La pagina ruichiesta è uno script PHP che esegue la divisione tra i valori passati. E' possibile testare il funzionamento dello script digitando in un browser l'indirizzo: `http:\\www.slimline.altervista.org/Mdp095a000/Ptp119b000/Division.php?Dividend=500&Divisor=10 <#http:\\www.slimline.altervista.org/Mdp095a000/Ptp119b000/Division.php?Dividend=500&Divisor=10>`__ Se lo script è attivo viene ritornata una pagina con: **The result is: 50** La stessa stringa ritornata nel browser è visibile nella variabile **Result**. **Definizione variabili** .. code-block:: none VAR CaseNr : USINT; (\* Case gestione \*) HTTPRq : HTTPClient; (\* HTTP client \*) i : UDINT; (\* Auxiliary variable \*) Result : STRING[ 32 ]; (\* Result string \*) END_VAR **Esempio ST** *(PTP119B500, ST_HTTPClient)* .. code-block:: none (\* Program initializations. \*) IF (SysFirstLoop) THEN HTTPRq.SpyOn:=TRUE; (\* Activate the spy \*) HTTPRq.Method:=FALSE; (\* Request method, GET \*) HTTPRq.HostAddress:=ADR('www.slimline.altervista.org'); (\* Main coordinator \*) HTTPRq.HostName:=HTTPRq.HostAddress; (\* Hostname \*) HTTPRq.HostPort:=80; (\* Server port \*) HTTPRq.Page:=ADR('/Mdp095a000/Ptp119b000/Division.php'); (\* Web page \*) HTTPRq.Request:=ADR('Dividend=500$26Divisor=10'); (\* Request string \*) HTTPRq.DBSize:=256; (\* Data buffer size \*) HTTPRq.Timeout:=10000; (\* Execution timeout \*) END_IF; HTTPRq(); (\* HTTP client \*) (\* Case gestione sequenze programma. \*) CASE (CaseNr) OF (\* Se comando attivo aspetto si disattivi. \*) 0: HTTPRq.Enable:=FALSE; (\* HTTP get page enable \*) IF NOT(Di00CPU) THEN CaseNr:=CaseNr+1; END_IF; (\* Attesa comando, controllo fronte salita. \*) 1: IF NOT(Di00CPU) THEN RETURN; END_IF; i:=Sysmemset(ADR(Result), 0, SIZEOF(Result)); (\* Empty result \*) HTTPRq.Enable:=TRUE; (\* HTTP get page enable \*) CaseNr:=CaseNr+1; (\* Case gestione \*) (\* Acquisizione pagina, su ricezione eseguo trasferimento in stringa. \*) 2: IF (HTTPRq.DBChars <> 0) THEN IF ((Sysstrlen(ADR(Result))+HTTPRq.DBChars) < SIZEOF(Result)) THEN i:=Sysmemmove(ADR(Result)+Sysstrlen(ADR(Result)), HTTPRq.DBAddress, HTTPRq.DBChars); END_IF; END_IF; (\* Se Done fine esecuzione. \*) IF (HTTPRq.Done) THEN CaseNr:=0; (\* Case gestione \*) IF NOT(HTTPRq.PLoad) THEN RETURN; END_IF; (\* Se Done ma non Ok la richiesta HTTP è in errore. \*) END_IF; END_CASE; (\* [End of file] \*) Lo script PHP sul server è del tipo: .. code-block:: php Come si vede lo script invia in echo il risultato della divisione. I parametri posti in GET alla richiesta sono automaticamente trasferiti negli statements **$_REQUEST['Dividend']** e **$_REQUEST['Divisor']**. Come si vede è quindi possibile passare in GET allo script tutti i valori che si desiderano. Il valore di ritorno dallo script definito con lo statement echo verrà trasferito nel buffer **Result** del nostro programma e quindi è possibile operare su di esso con le istruzioni di gestione stringa. **Scelta tra metodo GET o POST** Ecco una tabella che riporta le differenze tra il metodo GET ed il POST. +-----------------------+-----------------------+-----------------------+ | | **GET** | **POST** | +-----------------------+-----------------------+-----------------------+ | BACK button/Reload | Harmless | Data will be | | | | re-submitted (the | | | | browser should alert | | | | the user that the | | | | data are about to be | | | | re-submitted) | +-----------------------+-----------------------+-----------------------+ | Bookmarked | Can be bookmarked | Cannot be bookmarked | +-----------------------+-----------------------+-----------------------+ | Cached | Can be cached | Not cached | +-----------------------+-----------------------+-----------------------+ | Encoding type | application/x-www-for | application/x-www-for | | | m-urlencoded | m-urlencoded | | | | or | | | | multipart/form-data. | | | | Use multipart | | | | encoding for binary | | | | data | +-----------------------+-----------------------+-----------------------+ | History | Parameters remain in | Parameters are not | | | browser history | saved in browser | | | | history | +-----------------------+-----------------------+-----------------------+ | Restrictions on data | Yes, when sending | No restrictions | | length | data, the GET method | | | | adds the data to the | | | | URL; and the length | | | | of a URL is limited | | | | (maximum URL length | | | | is 2048 characters) | | +-----------------------+-----------------------+-----------------------+ | Restrictions on data | Only ASCII characters | No restrictions. | | type | allowed | Binary data is also | | | | allowed | +-----------------------+-----------------------+-----------------------+ | Security | GET is less secure | POST is a little | | | compared to POST | safer than GET | | | because data sent is | because the | | | part of the URL | parameters are not | | | | stored in browser | | | | history or in web | | | | server logs | +-----------------------+-----------------------+-----------------------+ | Visibility | Data is visible to | Data is not displayed | | | everyone in the URL | in the URL | +-----------------------+-----------------------+-----------------------+ Molti server (Altervista compreso) utilizzano un servizio CDN che esegue il caching delle pagine, se si usa il metodo GET per essere certi che non venga ritornata la pagina in catch è preferibile aggiungere nel request un parametro variabile (Esempio Rq=xxxx dove xxxx è un numero diverso per ogni richiesta. **Esempio ricezione pagina su file** Nell'esempio attivando **Di00CPU** viene eseguita la richiesta della pagina **index.htm** dal sito `www.slimline.altervista.org `__. Il contenuto della pagina è trasferito nel file **Storage/index.htm**. **Definizione variabili** VAR CaseNr : USINT; (\* Case gestione \*) Error : USINT; (\* Execution error \*) i : INT; (\* Auxiliary variable \*) Filename : STRING[ 32 ]; (\* File appoggio pagina \*) Fp : FILEP; (\* File pointer \*) HTTPRq : HTTPClient; (\* HTTP client \*) END_VAR **Esempio ST** *(PTP119B500, ST_HTTPClient_ToFile)* .. code-block:: none (\* Program initializations. \*) IF (SysFirstLoop) THEN HTTPRq.SpyOn:=TRUE; (\* Activate the spy \*) HTTPRq.Method:=FALSE; (\* Request method, GET \*) HTTPRq.HostAddress:=ADR('www.slimline.altervista.org'); (\* Main coordinator \*) HTTPRq.HostName:=HTTPRq.HostAddress; (\* Hostname \*) HTTPRq.HostPort:=80; (\* Server port \*) HTTPRq.Page:=ADR('/index.htm'); (\* Web page \*) HTTPRq.Request:=NULL; (\* Request string \*) HTTPRq.DBSize:=256; (\* Data buffer size \*) HTTPRq.Timeout:=10000; (\* Execution timeout \*) Filename:='Storage/index.htm'; (\* File appoggio pagina \*) END_IF; (\* Eseguo FBs. \*) HTTPRq(); (\* HTTP client \*) CASE (CaseNr) OF (\* Se comando attivo aspetto si disattivi. \*) 0: HTTPRq.Enable:=FALSE; (\* HTTP get page enable \*) IF NOT(Di00CPU) THEN CaseNr:=CaseNr+1; END_IF; (\* Attesa comando, controllo fronte salita. \*) 1: IF NOT(Di00CPU) THEN RETURN; END_IF; i:=Sysremove(Filename); (\* Cancellazione file \*) HTTPRq.Enable:=TRUE; (\* HTTP get page enable \*) Error:=0; (\* Execution error \*) CaseNr:=CaseNr+1; (\* Case gestione \*) (\* Acquisizione pagina, su ricezione eseguo trasferimento nel file.\*) 2: IF (HTTPRq.DBChars <> 0) THEN (\* Apertura file in append. Se non esiste, viene creato. \*) Fp:=Sysfopen(Filename, 'a'); (\* File pointer \*) IF (Fp = NULL) THEN Error:=10; CaseNr:=0; RETURN; END_IF; (\* Eseguo scrittura su file. \*) IF (Sysfwrite(HTTPRq.DBAddress, TO_INT(HTTPRq.DBChars), 1, Fp) <> TO_INT(HTTPRq.DBChars)) THEN i:=Sysfclose(Fp); (\* Eseguo chiusura file \*) Error:=20; (\* Execution error \*) CaseNr:=0; (\* Case gestione \*) RETURN; END_IF; (\* Eseguo chiusura file. \*) i:=Sysfclose(Fp); (\* Eseguo chiusura file \*) END_IF; (\* Controllo se terminato. \*) IF (HTTPRq.Done) THEN (\* Se Done ma non Ok la richiesta HTTP è in errore. \*) IF NOT(HTTPRq.PLoad) THEN Error:=50; CaseNr:=0; RETURN; END_IF; CaseNr:=0; (\* Case gestione \*) END_IF; END_CASE; (\* [End of file] \*) FTPClient_v1, connect to a FTP server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | eLLabNetworkLib_A700 | +-----------------------+-----------------------+ |image47| Questo blocco funzione permette di gestire la connessione ad un server FTP definito in **FTPServer**. Con il comando **Connect** si forza la connessione al server utilizzando il username definito in **User** e la password definita in **Password**. Se la connessione và a buon fine si attiva l'uscita **Connected**. A connessione avvenuta ogni tempo definito in **CnAliveTm** viene inviato un comando di NOOP pe mantenere la connessione. In **Timeout** è possibile definire il tempo di attesa risposte dal server. In **DBSize** occorre definire la dimensione del buffer che l'FB alloca (Con SysRMalloc) per la gestione della richiesta e della ricezione. La dimensione minima è 256 bytes, aumentando la dimensione si aumenta anche la dimensione dei pacchetti TCP velocizzando il trasferimento. **E' inutile definire lunghezze superiori al limite del pacchetto TCP 1500 bytes**. Attivando **Store** il file locale definito in **LocalFile** viene trasferito nel server FTP con il nome indicato in **RemoteFile**. Terminato il trasferimento si attiva per un loop **Done**. Attivando **Retrieve** il file nel server FTP con il nome indicato in **RemoteFile** viene trasferito in locale con il nome definito in **LocalFile**. Terminato il trasferimento si attiva per un loop **Done**. Attivando **Delete** il file nel server FTP con il nome indicato in **RemoteFile** viene cancellato e si attiva per un loop **Done**. In caso di errore il comando termina e si attiva per un loop l'uscita **Fault**. +-----------------------------------+-----------------------------------+ | **Connect** (BOOL) | Comando abilitazione connessione | | | al server FTP. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **Store** (BOOL) | Comando trasferimento file da | | | locale a server FTP. | +-----------------------------------+-----------------------------------+ | **Retrieve** (BOOL) | Comando trasferimento file da | | | server FTP a locale. | +-----------------------------------+-----------------------------------+ | **Delete** (BOOL) | Comando cancellazione file su | | | server FTP. | +-----------------------------------+-----------------------------------+ | **DBSize** (UINT) | Dimensione buffer allocato da FB | | | (Con SysRMalloc). Minimo 256 | | | massimo 1500. | +-----------------------------------+-----------------------------------+ | **Timeout** (REAL) | Tempo attesa risposte da server | | | FTP (S). | +-----------------------------------+-----------------------------------+ | **CnAliveTm** (REAL) | Tempo invio comando NOOP. Se “0” | | | comando non viene inviato (S). | +-----------------------------------+-----------------------------------+ | **FTPServer** (@USINT) | Puntatore stringa definizione | | | server FTP. | +-----------------------------------+-----------------------------------+ | **User** (@USINT) | Puntatore stringa definizione | | | nome utente. | +-----------------------------------+-----------------------------------+ | **Password** (@USINT) | Puntatore stringa definizione | | | password accesso. | +-----------------------------------+-----------------------------------+ | **LocalFile** (@USINT) | Puntatore stringa definizione | | | nome del file locale. | +-----------------------------------+-----------------------------------+ | **RemoteFile** (@USINT) | Puntatore stringa definizione | | | nome del file su server FTP. | +-----------------------------------+-----------------------------------+ | **Connected** (BOOL) | Si attiva se connessione al | | | server FTP avvenuta. | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Si attiva al termine della | | | esecuzione comando. Rimane attivo | | | fino alla disabilitazione di | | | tutti i comandi, per eseguire un | | | nuovo comando disabilitare e poi | | | riabilitare il comando. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop se errore | | | esecuzione comando. | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+----------------------------------------+ | **TFlags** | **Descrizione** | +-------------+----------------------------------------+ | 16#00000001 | **Tx:** Comandi inviati al server FTP. | +-------------+----------------------------------------+ | 16#00000002 | **Rx:** Stati risposta dal server FTP. | +-------------+----------------------------------------+ | 16#10000000 | **Lg:** Messaggio di log. | +-------------+----------------------------------------+ | 16#40000000 | **Er:** Messaggio di errore. | +-------------+----------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 10063020 | FB eseguita in una task diversa | | | dalla task di background. | +-----------------------------------+-----------------------------------+ | 10063030 | Valore di **DBSize** errato. | +-----------------------------------+-----------------------------------+ | 10063050 | Timeout esecuzione. | +-----------------------------------+-----------------------------------+ | 10063100~3 | Errore ricezione indirizzo IP | | | passive connection. | +-----------------------------------+-----------------------------------+ | 10063110~1 | Errore ricezione porta passive | | | connection. | +-----------------------------------+-----------------------------------+ | 10063200 | Errore apertura file locale su | | | comando Store. | +-----------------------------------+-----------------------------------+ | 10063210 | Errore 550 da server FTP, non è | | | possibile accedere a cartella | | | remoto su comando Store. | +-----------------------------------+-----------------------------------+ | 10063211 | Errore 553 da server FTP, non è | | | possibile aprire il file remoto | | | su comando Store. | +-----------------------------------+-----------------------------------+ | 10063215 | Server FTP ha chiuso connessione | | | dati su comando Store. | +-----------------------------------+-----------------------------------+ | 10063300 | Errore apertura file locale su | | | comando Retrieve. | +-----------------------------------+-----------------------------------+ | 10063310 | Errore 550 da server FTP, non è | | | possibile accedere a cartella | | | remoto su comando Retrieve. | +-----------------------------------+-----------------------------------+ | 10063311 | Errore 553 da server FTP, non è | | | possibile aprire il file remoto | | | su comando Retrieve. | +-----------------------------------+-----------------------------------+ | 10063390 | Errore scrittura file locale su | | | comando Retrieve. | +-----------------------------------+-----------------------------------+ | 10063410 | Errore 550 da server FTP, non è | | | possibile cancellare il file | | | remoto su comando Delete. | +-----------------------------------+-----------------------------------+ | 10063500 | Ricezione stringa troppo lunga da | | | server FTP. | +-----------------------------------+-----------------------------------+ **Esempi** """"""""""""" Nell'esempio attivando **Di00CPU** viene eseguito un comando di **Store**, il file locale **Storage/MyForm.bin** viene trasferito sul server FTP con il nome **MyForm.bin**. Attivando **Di01CPU** viene eseguito un comando di **Retrieve**, il file **MyForm.bin** viene trasferito dal server FTP verso il file locale **Storage/MyForm.bin**. Attivando **Di02CPU** viene eseguito un comando di **Delete**, il file **MyForm.bin** viene cancellato dal server FTP. **Definizione variabili** |image49| **Esempio ST** *(PTP119B300, ST_FTPClient_v1)* .. code-block:: none (\* Eseguo inizializzazioni. \*) IF (SysFirstLoop) THEN FTP.SpyOn:=TRUE; (\* Spy active \*) FTP.DBSize:=256; (\* Data buffer size \*) FTP.Timeout:=5.0; (\* Timeout (S) \*) FTP.CnAliveTm:=10.0; (\* Connection alive time (S) \*) FTP.FTPServer:=ADR('MyServer'); (\* Server FTP \*) FTP.User:='MyUser'; (\* User \*) FTP.Password:='MyPassword'; (\* Password \*) END_IF; (\* ESEGUO FTP CLIENT \*) (\* Esecuzione FB, su errore disabilito tutti i comandi FTP(); (\* FTP client \*) IF (FTP.Fault) THEN FTP.Store:=FALSE; (\* Store command \*) FTP.Retrieve:=FALSE; (\* Retrieve command \*) FTP.Delete:=FALSE; (\* Delete command \*) CaseNr:=0; (\* Program case \*) END_IF; (\* CASES GESTIONE \*) (\* Cases gestione programma. \*) CASE (CaseNr) OF (\* GESTIONE COMANDI \*) (\* Disattivo le richieste in corso. \*) 0: FTP.Connect:=FALSE; (\* Abilitazione connessione \*) IF (Di00CPU) THEN CaseNr:=10; RETURN; END_IF; IF (Di01CPU) THEN CaseNr:=20; RETURN; END_IF; IF (Di02CPU) THEN CaseNr:=30; RETURN; END_IF; (\* GESTIONE COMANDO STORE \*) (\* Connessione al server. \*) 10: FTP.Connect:=TRUE; (\* Connect to server \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa connessione al server. \*) 11: IF NOT(FTP.Connected) THEN RETURN; END_IF; FTP.LocalFile:=ADR('Storage/MyForm.bin'); FTP.RemoteFile:=ADR('MyForm.bin'); FTP.Store:=TRUE; (\* Store command \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa fine comando. \*) 12: IF NOT(FTP.Done) THEN RETURN; END_IF; FTP.Store:=FALSE; (\* Store command \*) CaseNr:=0; (\* Program case \*) (\* GESTIONE COMANDO RETRIEVE \*) (\* Connessione al server. \*) 20: FTP.Connect:=TRUE; (\* Connect to server \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa connessione al server. \*) 21: IF NOT(FTP.Connected) THEN RETURN; END_IF; FTP.LocalFile:=ADR('Storage/MyForm.bin'); FTP.RemoteFile:=ADR('MyForm.bin'); FTP.Retrieve:=TRUE; (\* Retrieve command \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa fine comando. \*) 22: IF NOT(FTP.Done) THEN RETURN; END_IF; FTP.Retrieve:=FALSE; (\* Retrieve command \*) CaseNr:=0; (\* Program case \*) (\* GESTIONE COMANDO DELETE \*) (\* Connessione al server. \*) 30: FTP.Connect:=TRUE; (\* Connect to server \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa connessione al server. \*) 31: IF NOT(FTP.Connected) THEN RETURN; END_IF; FTP.LocalFile:=NULL; FTP.RemoteFile:=ADR('MyForm.bin'); FTP.Delete:=TRUE; (\* Delete command \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Attesa fine comando. \*) 32: IF NOT(FTP.Done) THEN RETURN; END_IF; FTP.Delete:=FALSE; (\* Delete command \*) CaseNr:=0; (\* Program case \*) END_CASE; (\* [End of file] \*) MQTTClient, client for a MQTT server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | eLLabNetworkLib_A400 | +-----------------------+-----------------------+ |image50| Questo blocco funzione permette di gestire la connessione ad un server utilizzando il protocollo MQTT (Message Queuing Telemetry Transport) di IBM che l'Organization for the Advancement of Structured Information Standards (OASIS) ha dichiarato come lo standard di riferimento per la comunicazione per l'Internet delle Cose. Il protocollo adotta un meccanismo di pubblicazione e sottoscrizione per scambiare messaggi tramite un appostivo "message broker” che fa da server. Il FB permette sia di pubblicare che di sottoscrivere topics sul broker. Questo è un blocco funzione protetto per utilizzarlo occorre richiedere il codice di protezione, vedi `protezione funzioni e blocchi funzione <#ChpFctFBProtection>`__. **E' comunque possibile utilizzarlo liberamente su tutti i broker che non richiedono autenticazione (Username e Password non definiti)**. Sui broker autenticati il FB funziona in modo test per 30 Min. Con il comando **Enable** si forza la connessione al **Server** (Message broker) sulla porta **Port**, utilizzando il **Username** e la **Password** definite. Se la connessione và a buon fine si attiva l'uscita **Connected**. A connessione avvenuta ogni 1/3 del tempo definito in **KeepAlive** viene inviato un comando di ping per mantenere la connessione. Se il broker non riceve il ping nel tempo definito in **KeepAlive** ritiene la connessione terminata. Il comando di **Publish** permette di pubblicare sul broker il **Topic** indicato con relative **Value**, **Flags** e **QoS**. Se la pubblicazione và a buon fine si attiva per un loop l'uscita **Published**. Il comando di **Subscribe** permette di sottoscrivere sul broker il **Topic** indicato con relative **Flags** e **QoS**. Se la sottoscrizione và a buon fine si attiva per un loop l'uscita **Subscribed**. Ad ogni sottoscrizione del valore di un topic sul broker, il broker ne invia il valore a tutti i client che lo hanno sottoscritto. Il FB riceve sia il nome del topic ritornato in **TBufferRxD** che il valore ritornato in **VbufferRxD** ed attiva per un loop **TopicRxD**. In **VLengthRxD** è ritornata la lunghezza del valore di topic ricevuto. In **CTime** è ritornato il tempo di comunicazione con broker, rilevato alla connessione ed a ogni esecuzione di ping. O sulla pubblicazione di topic solo se **QoS** è 1. In caso di errore viene eseguita una disconnessione e riconnessione al broker e si attiva per un loop l'uscita **Fault**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando abilitazione connessione | | | al server MQTT "message broker”. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento del FB. | +-----------------------------------+-----------------------------------+ | **Publish** (BOOL) | Comando pubblicazione di un topic | | | sul server. | +-----------------------------------+-----------------------------------+ | **Subscribe** (BOOL) | Comando sottoscrizione di un | | | topic sul server. | +-----------------------------------+-----------------------------------+ | **Server** (@USINT) | Puntatore stringa definizione | | | server MQTT. | +-----------------------------------+-----------------------------------+ | **Port** (UINT) | Numero porta TCP a cui | | | connettersi. | +-----------------------------------+-----------------------------------+ | **Username** (@USINT) | Puntatore stringa definizione | | | nome utente. | +-----------------------------------+-----------------------------------+ | **Password** (@USINT) | Puntatore stringa definizione | | | password accesso. | +-----------------------------------+-----------------------------------+ | **ClientID** (@USINT) | Puntatore stringa definizione | | | identificativo client (Massimo 23 | | | caratteri). | +-----------------------------------+-----------------------------------+ | **RemoteFile** (@USINT) | Puntatore stringa definizione | | | nome del file su server FTP. | +-----------------------------------+-----------------------------------+ | **KeepAlive** (UINT) | Tempo di vita connessione da | | | parte del broker (S). | +-----------------------------------+-----------------------------------+ | **Flags** (DWORD) | Flags connessione, pubblicazione, | | | sottoscrizione. | +-----------------------------------+-----------------------------------+ | **QoS** (USINT) | Quality of Service. | +-----------------------------------+-----------------------------------+ | **Topic** (@USINT) | Puntatore stringa definizione | | | nome topic | | | (Pubblicazione/Sottoscrizione). | +-----------------------------------+-----------------------------------+ | **Value** (@USINT) | Puntatore valore topic | | | (Pubblicazione). | +-----------------------------------+-----------------------------------+ | **VLength** (UDINT) | Lunghezza valore topic | | | (Pubblicazione). | +-----------------------------------+-----------------------------------+ | **TBufferRxD** (@USINT) | Puntatore buffer nome topic | | | ricevuto da broker. | +-----------------------------------+-----------------------------------+ | **TBLengthRxD** (UDINT) | Dimensione buffer nome topic | | | ricevuto da broker. | +-----------------------------------+-----------------------------------+ | **VBufferRxD** (@USINT) | Puntatore buffer valore topic | | | ricevuto da broker. | +-----------------------------------+-----------------------------------+ | **VBLengthRxD** (UDINT) | Dimensione buffer valore topic | | | ricevuto da broker. | +-----------------------------------+-----------------------------------+ | **Connected** (BOOL) | Si attiva se connessione al | | | server MQTT avvenuta. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop se errore | | | esecuzione. | +-----------------------------------+-----------------------------------+ | **Published** (BOOL) | Attivo per un loop su | | | pubblicazione di un topic sul | | | server. | +-----------------------------------+-----------------------------------+ | **Subscribed** (BOOL) | Attivo per un loop su | | | sottoscrizione di un topic sul | | | server. | +-----------------------------------+-----------------------------------+ | **TopicRxD** (BOOL) | Attivo per un loop su ricezione | | | di un topic dal server. | +-----------------------------------+-----------------------------------+ | **VLengthRxD** (UINT) | Lunghezza valore topic ricevuto | | | dal broker | +-----------------------------------+-----------------------------------+ | **CTime** (REAL) | Tempo di comunicazione con il | | | broker (S). | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+-----------------------------------------------------+ | **TFlags** | **Descrizione** | +-------------+-----------------------------------------------------+ | 16#00000001 | **Tx:** Frame comando inviati al server. | +-------------+-----------------------------------------------------+ | 16#00000002 | **Rx:** Frame dati ricevuti dal server. | +-------------+-----------------------------------------------------+ | 16#00000100 | **Sc:** Stringa compilata da funzione compilazione. | +-------------+-----------------------------------------------------+ | 16#00000200 | **Rl:** Calcolo Remaining Length. | +-------------+-----------------------------------------------------+ | 16#00001000 | **Pt:** Topic pubblicato. | +-------------+-----------------------------------------------------+ | 16#00002000 | **St:** Topic sottoscritto. | +-------------+-----------------------------------------------------+ | 16#00004000 | **Rt:** Topic ricevuto. | +-------------+-----------------------------------------------------+ | 16#10000000 | **Lg:** Messaggio di log. | +-------------+-----------------------------------------------------+ | 16#40000000 | **Er:** Messaggio di erro | +-------------+-----------------------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +-----------------------------------+-----------------------------------+ | **Codice** | **Descrizione** | +-----------------------------------+-----------------------------------+ | 10067010 | FB eseguita in una task diversa | | | dalla task di background. | +-----------------------------------+-----------------------------------+ | 10067020 | FB protetta, terminato tempo | | | funzionamento in modo demo. | +-----------------------------------+-----------------------------------+ | 10067030 | **ClientID** non definito. | +-----------------------------------+-----------------------------------+ | 10067031 | **ClientID** non corretto (Troppo | | | corto o più lungo di 23 | | | caratteri). | +-----------------------------------+-----------------------------------+ | 10067032 | **ClientID** non corretto | | | (Contiene caratteri errati). | +-----------------------------------+-----------------------------------+ | 10067100 | FB di connessione al server in | | | fault | +-----------------------------------+-----------------------------------+ | 10067110 | Disconnessione dal server, il | | | server ha chiuso la connessione. | +-----------------------------------+-----------------------------------+ | 10067200 | Ricezione frame incompleto da | | | server. | +-----------------------------------+-----------------------------------+ | 10067210 | Ricevuto frame CONNACK non | | | atteso. | +-----------------------------------+-----------------------------------+ | 10067211~3 | Errore nel frame CONNACK | | | ricevuto. | +-----------------------------------+-----------------------------------+ | 10067220 | Ricevuto frame PUBACK non atteso. | +-----------------------------------+-----------------------------------+ | 10067221~2 | Errore nel frame PUBACK ricevuto. | +-----------------------------------+-----------------------------------+ | 10067230 | Ricevuto frame SUBACK non atteso. | +-----------------------------------+-----------------------------------+ | 10067231~3 | Errore nel frame SUBACK ricevuto. | +-----------------------------------+-----------------------------------+ | 10067240 | Ricevuto frame PINGRESP non | | | atteso. | +-----------------------------------+-----------------------------------+ | 10067241 | Errore nel frame PINGRESP | | | ricevuto. | +-----------------------------------+-----------------------------------+ | 10067280~9 | Errore nel frame PUBLISH | | | ricevuto. | +-----------------------------------+-----------------------------------+ | 10067300 | Errore connessione al server. | +-----------------------------------+-----------------------------------+ | 10067310 | Errore gestione ping verso | | | server. | +-----------------------------------+-----------------------------------+ | 10067320~1 | Errore esecuzione comando | | | publish. | +-----------------------------------+-----------------------------------+ | 10067330 | Errore esecuzione comando | | | subscribe. | +-----------------------------------+-----------------------------------+ | 10067400 | Valore stringa nullo. | +-----------------------------------+-----------------------------------+ | 10067402 | Stringa troppo lunga. | +-----------------------------------+-----------------------------------+ | 10067403 | Stringa contiene caratteri non | | | ascii. | +-----------------------------------+-----------------------------------+ **Esempio con App su smartphone** L'esempio permette la connessione ad un broker gratuito **iot.eclipse.org** dove viene pubblicato lo stato di un ingresso digitale del modulo CPU e viene sottoscritto il comando di una uscita digitale del modulo CPU. Nei rami seguenti viene istanziato il FB MQTTClient (Ramo 0001) e viene acquisito un eventuale errore di esecuzione che sarà trasferito nella variabile **LastError** (Ramo 0002). Come si vede è stato attivato il comando di spionaggio che permette da Telnet di spiare il funzionamento del blocco funzione. **Attenzione**\ *, per evitare di andare in conflitto con altri utenti che testano il programma conviene modificare il nome del topic e l'identificativo utente. Ci può solo essere un utente con lo stesso identificativo sullo stesso broker*. **Definizione variabili** |image51| **Esempio LD** *(PTP119B200, LD_MQTTTest)* |image52| Nei rami seguenti viene gestita la pubblicazione dello stato dell'ingresso 00 del modulo CPU. Siccome il comando di pubblicazione deve durare un solo loop di programma, il comando è sempre resettato (Ramo 0003) e viene settato ogni 5 secondi. Se l'input non è attivo viene inviata la stringa **Off** (Ramo 0005), se è attivo viene inviata la stringa **On** (Ramo 0006). |image53| Nei rami seguenti viene gestita la sottoscrizione del comando dell'uscita 00 del modulo CPU. Siccome il comando di sottoscrizione deve durare un solo loop di programma, il comando è sempre resettato (Ramo 0007) e viene settato sulla connessione del FB al broker (Ramo 0008). Nel ramo 0009 viene controllata la ricezione di un pubblicazione dal broker, e se il topic è **DOut/Do00** ed il valore è la stringa **Off** viene resettata l'uscita **Do00**. Nel ramo 0010 viene controllata la ricezione di un pubblicazione dal broker, e se il topic è **DOut/Do00** ed il valore è la stringa **On** viene settata l'uscita **Do00**. |image54| **Client per smartphone** |image55| E' possibile testare l'esempio utilizzando un client gratuito per smartphone, scaricando l'app Android **Linear MQTT Dashboard**. Questa App permette di creare delle schede nelle quali inserire oggetti per la visualizzazione ed il comando sul sistema SlimLine. Naturalmente il dialogo tra l'App e lo SlimLine passa attraverso il broker. **Visualizzazioni:** L'FB **MQTTClient** sullo SlimLine pubblica degli stati sul brocker e l'App sullo smartphone li sottoscrive visualizzandoli. **Comandi:** L'App sullo smartphone pubblica i comandi sul broker, comandi che l'FB **MQTTClient** sullo SlimLine ha sottoscritto e che quindi riceve per la gestione. Vediamo di seguito le operazioni da eseguire per configurare l'App in modo da farla funzionare c on il nostro programma di esempio sullo SlimLine. +-----------------------------------+-----------------------------------+ | Ecco la scheda che visualizza lo | |image61| | | stato dell'ingresso digitale | | | **Di00CPU** e permette il comando | | | dell'uscita digitale **Do000CPU** | | | del nostro sistem,a SlimLine | | | | | | In pratica un LED riporta lo | | | stato dell'ingresso mentre un | | | pulsante permette di impostare | | | l'uscita. | | +-----------------------------------+-----------------------------------+ | La prima operazione da eseguire è | |image62| | | nel menù **App settings...** | | | impostare i riferimenti al broker | | | utilizzato, indirizzo URL e | | | porta. Nel nostro esempio | | | **iot.eclipse.org** e porta | | | **1883**. | | | | | | Il server utilizzato è un server | | | dimostrativo gratuito pertanto | | | non è richiesta l'autenticazione, | | | quindi si lasceranno i campi | | | **Username** e **Password** | | | vuoti. | | +-----------------------------------+-----------------------------------+ | Impostato il broker è possibile | |image63| | | andare su uno dei tabs di | | | visualizzazione e definire gli | | | oggetti che si desiderano. Con il | | | broker disconnesso è possibile su | | | ogni oggetto impostare i relativi | | | parametri | | +-----------------------------------+-----------------------------------+ | Ecco le impostazioni per il LED | |image64| | | di visualizzazione stato | | | **Di00CPU**, come si vede viene | | | assegnato un nome all'oggetto e | | | viene definito il topic di | | | riferimento **DInp/Di00**. Questo | | | è lo stesso topic che il FB sullo | | | SlimLine pubblica alla variazione | | | dell'ingresso. | | | | | | Come si vede dal progetto | | | LogicLab se l'ingresso non è | | | attivo viene inviata la stringa | | | **Off** e se è attivo viene | | | inviata la stringa **On**. Alla | | | ricezione di queste stringhe | | | corrispondono i due relativi | | | stati del LED sulla App. | | +-----------------------------------+-----------------------------------+ | Ecco le impostazioni per il | |image65| | | pulsante di impostazione comando | | | **Do00CPU**, come si vede viene | | | assegnato un nome all'oggetto e | | | viene definito il topic di | | | riferimento **DOut/Do00**. Questo | | | è lo stesso topic che il FB sullo | | | SlimLine sottoscrive e controlla | | | sulla ricezione di un valore. | | | | | | Come si vede dal progetto | | | LogicLab alla ricezione della | | | stringa **Off** viene disattivata | | | l'uscita, ed alla ricezione della | | | stringa **On** viene settata | | | l'uscita. | | +-----------------------------------+-----------------------------------+ **Console di spionaggio** |image66| Ecco come si presenta la console di spionaggio su Toolly. Come si vede il comando **SpyData** permette di spiare tutto il funzionamento del FB. Mentre impostando il trigger (Comando **SpyData -t 00007000**) si vedrano solo i topic pubblicati, e la ricezione di quelli sottoscritti. **Esempio scambio dati tramite broker** Questo esempio si connette ad un broker gratuito ed esegue la pubblicazione dello stato di un ingresso logico sul topic **IOCommand**. Il programma si sottoscrive allo stesso topic così ne riceve dal broker lo stato ad ogni variazione, e lo stato ricevuto comanda una uscita logica. In questo modo lo stato dell'ingresso è riportato sull'uscita passando dal broker. E' possibile trasferire lo stesso programma su diversi sistemi e gestendo opportunamente la pubblicazione e la sottoscrizione dei topic sui sistemi è possibile realizzare uno scambio dati. Attivando **Di01CPU** si comanda la connessione al broker, a connessione avvenuta si attiva **Do01CPU**. Attivando **Di00CPU** ne viene pubblicato lo stato che è ricevuto e trasferito su **Do00CPU**. Quindi lo stato dell'ingresso è copiato sulla uscita passando attraverso la pubblicazione sul broker. **Attenzione**\ *, per evitare di andare in conflitto con altri utenti che testano il programma conviene modificare il nome del topic e l'identificativo utente. Ci può solo essere un utente con lo stesso identificativo sullo stesso broker*. **Definizione variabili** |image68| **Esempio ST** *(PTP119B200, ST_MQTTExchange)* .. code-block:: none (\* INIZIALIZZAZIONI \*) (\* Eseguo inizializzazioni. \*) IF (SysFirstLoop) THEN MQTT.SpyOn:=TRUE; (\* Spy active \*) MQTT.Server:=ADR('broker.mqttdashboard.com'); (\* Broker URL \*) MQTT.Port:=1883; (\* Broker TCP port \*) MQTT.Username:=NULL; (\* Broker username \*) MQTT.Password:=NULL; (\* Broker password \*) MQTT.ClientID:=ADR('Elsist'); (\* Client identifier \*) MQTT.KeepAlive:=180; (\* Keep alive time (S) \*) MQTT.Flags:=16#00000000; (\* Connection/Publish/Subscribe flags \*) MQTT.QoS:=1; (\* Quality of Service \*) MQTT.TBufferRxD:=ADR(TopicRxD); (\* Topic buffer (Received) \*) MQTT.TBLengthRxD:=SIZEOF(TopicRxD); (\* Topic buffer length (Received) \*) MQTT.VBufferRxD:=ADR(ValueRxD); (\* Value buffer (Received) \*) MQTT.VBLengthRxD:=SIZEOF(ValueRxD); (\* Value buffer length (Received) \*) END_IF; (\* MQTT CLIENT MANAGEMENT \*) (\* Gestione FB MQTTClient. \*) MQTT(); (\* MQTTClient management \*) IF (MQTT.Fault) THEN CaseNr:=0; END_IF; Do01CPU:=MQTT.Connected; (\* Connected to broker \*) (\* GESTIONE RICEZIONE TOPIC \*) (\* Gestione ricezione topic da broker. \*) IF (MQTT.TopicRxD) THEN (\* Eseguo controllo se topic corretto. \*) IF (SysStrFind(ADR(TopicRxD),ADR(Topic), FIND_DEFAULT) <> NULL) THEN (\* Eseguo controllo se comando "Off". \*) IF (SysStrFind(ADR(ValueRxD),ADR('Off'), FIND_DEFAULT) <> NULL) THEN Do00CPU:=FALSE; END_IF; (\* Eseguo controllo se comando "On". \*) IF (SysStrFind(ADR(ValueRxD),ADR('On'), FIND_DEFAULT) <> NULL) THEN Do00CPU:=TRUE; END_IF; END_IF; END_IF; (\* GESTIONE CASES PROGRAMMA \*) (\* Gestione cases programma. \*) CASE (CaseNr) OF (\* CONNECTION TO BROKER \*) (\* Eseguo connessione al broker. \*) 0: MQTT.Enable:=Di01CPU; (\* Connection enable \*) IF NOT(Di01CPU) THEN RETURN; END_IF; (\* Se broker già connesso gestisco publish. \*) IF (MQTT.Connected) THEN CaseNr:=10; RETURN; END_IF; CaseNr:=CaseNr+1; (\* Program case \*) (\* Eseguo attesa connessione al broker. \*) 1: IF NOT(MQTT.Connected) THEN RETURN; END_IF; CaseNr:=10; (\* Program case \*) (\* TOPIC SUBSCRIBE \*) (\* Eseguo sottoscrizione al topic. \*) 10: MQTT.Topic:=ADR(Topic); (\* Topic name \*) MQTT.Subscribe:=TRUE; (\* Topic subscribe \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Eseguo attesa sottoscrizione al topic. \*) 11: MQTT.Subscribe:=FALSE; (\* Topic subscribe \*) IF NOT(MQTT.Subscribed) THEN RETURN; END_IF; CaseNr:=20; (\* Program case \*) (\* TOPIC PUBLISH \*) (\* Eseguo pubblicazione evento pulsante. La pubblicazione avviene \*) (\* sul cambiamento di stato del pulsante. \*) 20: IF (Di00CPU = DiPulse) THEN RETURN; END_IF; DiPulse:=Di00CPU; (\* Digital input pulse \*) (\* Definisco nome topic da pubblicare. \*) MQTT.Topic:=ADR(Topic); (\* Topic name \*) (\* Definisco valore da pubblicare in base allo stato ingresso. \*) IF NOT(Di00CPU) THEN MQTT.Value:=ADR('Off'); END_IF; IF (Di00CPU) THEN MQTT.Value:=ADR('On'); END_IF; (\* Definisco lunghezza valore da pubblicare. \*) MQTT.VLength:=Sysstrlen(MQTT.Value); (\* Value length \*) MQTT.Publish:=TRUE; (\* Topic publish \*) CaseNr:=CaseNr+1; (\* Program case \*) (\* Eseguo attesa pubblicazione topic. \*) 21: MQTT.Publish:=FALSE; (\* Topic publish \*) IF NOT(MQTT.Published) THEN RETURN; END_IF; CaseNr:=0; (\* Program case \*) END_CASE; (\* [End of file] \*) EMailSend, sends an eMail ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +----------+----------------------+ | **Type** | **Library** | | | | +----------+----------------------+ | FB | eLLabNetworkLib_A400 | +----------+----------------------+ |image69| Questo blocco funzione permette di eseguire l'invio di una eMail. Il comando **Send** ne esegue l'invio all'indirizzo definito in **Recipient**. In **SMTPServer** ed **SMTPPort** occorre specificare l'URL o l'indirizzo IP e la porta del server SMTP da utilizzare per l'invio.In **Domain**, **Username** e **Password** occorre definire le credenziali di accesso al server. In **Subject** ed in **Data** occorre definire l'oggetto ed il contenuto della eMail, idati possono essere solo stringhe ASCII. Terminata l'esecuzione si attiva l'uscita **Done** che rimane attiva sino alla disabilitazione di **Send**. , in questo modo è possibile gestire i FB in cascata. L'uscita **Sent** si attiva per un loop se l'invio della eMail è andato a buon fine. In caso di errore si attiva per un loop l'uscita **Fault**. +-----------------------------------+-----------------------------------+ | **Send** (BOOL) | Comando invio eMail. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **Timeout** (REAL) | Tempo limite di esecuzione FB | | | (S). | +-----------------------------------+-----------------------------------+ | **Retrieve** (BOOL) | Comando trasferimento file da | | | server FTP a locale. | +-----------------------------------+-----------------------------------+ | **SMTPServer** (@BYTE) | Puntatore stringa definizione | | | server SMTP. | +-----------------------------------+-----------------------------------+ | **SMTPPort** (UINT) | Porta a cui connettersi sul | | | server SMTP. | +-----------------------------------+-----------------------------------+ | **Domain** (@BYTE) | Puntatore stringa definizione | | | dominio invio eMail. | +-----------------------------------+-----------------------------------+ | **Username** (@BYTE) | Puntatore stringa definizione | | | nome utente accesso server SMTP. | +-----------------------------------+-----------------------------------+ | **Password** (@BYTE) | Puntatore stringa definizione | | | password accesso server SMTP. | +-----------------------------------+-----------------------------------+ | **Sender** (@BYTE) | Puntatore stringa definizione | | | nome mittente. | +-----------------------------------+-----------------------------------+ | **Recipient** (@BYTE) | Puntatore stringa definizione | | | nome destinatario. | +-----------------------------------+-----------------------------------+ | **Subject** (@BYTE) | Puntatore stringa definizione | | | oggetto eMail. | +-----------------------------------+-----------------------------------+ | **Data** (@BYTE) | Puntatore stringa contenuto | | | eMail. | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Si attiva al termine della | | | esecuzione comando. Disabilitare | | | **Send** per disattivarla. | +-----------------------------------+-----------------------------------+ | **Sent** (BOOL) | Si attiva per un loop se l'invio | | | della eMail è riuscito. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop se errore | | | esecuzione comando. | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+-----------------------------------------------+ | **TFlags** | **Descrizione** | +-------------+-----------------------------------------------+ | 16#00000001 | **Tx:** Comandi inviati al server SMTP. | +-------------+-----------------------------------------------+ | 16#00000002 | **Rx:** Stringhe di risposta dal server SMTP. | +-------------+-----------------------------------------------+ | 16#10000000 | **Lg:** Messaggio di log. | +-------------+-----------------------------------------------+ | 16#40000000 | **Er:** Messaggio di errore. | +-------------+-----------------------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +------------+-----------------------------------------------------------+ | **Codice** | **Descrizione** | +------------+-----------------------------------------------------------+ | 10081020 | FB eseguita in una task diversa dalla task di background. | +------------+-----------------------------------------------------------+ | 10081050 | Timeout esecuzione. | +------------+-----------------------------------------------------------+ | 10081100 | Server SMTP ha chiuso la connessione. | +------------+-----------------------------------------------------------+ | 10081200~4 | Errore nella fase di autenticazione al server SMTP. | +------------+-----------------------------------------------------------+ | 10081300~2 | Errore nella fase di invio intestazioni eMail. | +------------+-----------------------------------------------------------+ | 10081400~1 | Errore nella fase di invio contenuto eMail. | +------------+-----------------------------------------------------------+ | 10081500 | Stringa ricevuta da Server SMTP troppo lunga. | +------------+-----------------------------------------------------------+ **Esempi** """""""""""""" Nell'esempio attivando **Di00CPU** viene inviato un messaggio eMail tramite il server SMTP di Virgilio. Naturalmente dovrete definire le vostre credenziali di accesso al server. **Definizione variabili** |image70| **Esempio FBD** *(PTP119B200, FBD_EmailSend)* |image71| **Esempi** """""""""""" Nell'esempio attivando **Di00CPU** viene inviato un messaggio eMail tramite il server SMTP di Virgilio. Naturalmente dovrete definire le vostre credenziali di accesso al server. **Definizione variabili** |image73| **Esempio ST** *(PTP119B200, ST_EmailSend)* .. code-block:: none (\* Eseguo inizializzazioni. \*) IF (SysFirstLoop) THEN Mailer.SpyOn:=TRUE; (\* Spy On \*) Mailer.Timeout:=2.0; (\* Timeout (S) \*) Mailer.SMTPServer:=ADR('out.virgilio.it'); (\* SMTP server \*) Mailer.SMTPPort:=25; (\* SMTP port \*) Mailer.Domain:=ADR('virgilio.it'); (\* Domain address \*) Mailer.Username:=ADR('elsist@virgilio.it'); (\* Access user name \*) Mailer.Password:=ADR('Password'); (\* Access password \*) Mailer.Sender:=ADR('elsist@virgilio.it'); (\* Sender address \*) Mailer.Recipient:=ADR('elsistsrl@libero.it'); (\* Recipient address \*) Mailer.Subject:=ADR(Subject); (\* eMail subject \*) Mailer.Data:=ADR(Data); (\* eMail data \*) END_IF; (\* Eseguo gestione mailer. \*) Mailer(); (\* EMailSend FB \*) Mailer.Send:=FALSE; (\* Send EMail \*) IF (Mailer.Fault) THEN SendErrors:=SendErrors+1; END_IF; (\* Eseguo invio eMail su attivazione ingresso digitale. \*) IF (Di00CPU <> Pulse) THEN Pulse:=Di00CPU; (\* Command pulse \*) IF (Di00CPU) THEN SendNr:=SendNr+1; (\* Send number \*) (\* Preparo l'oggetto della eMail. \*) i:=TO_UINT(SysVarsnprintf(Subject, SIZEOF(Subject), 'Test invio Nr:%d', UINT_TYPE, ADR(SendNr))); (\* Preparo il testo della eMail. \*) i:=TO_UINT(SysVarsnprintf(Data, SIZEOF(Data), 'Test invio Nr:%d$r$n', UINT_TYPE, ADR(SendNr))); i:=TO_UINT(SysLWVarsnprintf(Data, SIZEOF(Data), 'Errori invio Nr:%d', UINT_TYPE, ADR(SendErrors))); Mailer.Send:=TRUE; (\* Send EMail \*) END_IF; END_IF; (\* [End of file] \*) PushSafer, sends notifications to Pushsafer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-----------------------+-----------------------+ | **Type** | **Library** | +-----------------------+-----------------------+ | FB | eLLabNetworkLib_A700 | +-----------------------+-----------------------+ |image74| Questo blocco funzione permette di eseguire l'invio di una notifica tramite il servizio offerto da Pushsafer https://www.pushsafer.com/. Attivando **Enable** viene inviata la notifica con i parametri indicati. Terminato l'invio si attiva l'uscita **Done** che rimane attiva sino alla disabilitazione di **Enable**, in questo modo è possibile gestire i FB in cascata. Al termine dell'invio in **APICalls** è ritornato il numero di invii ancora disponibili, in **Status** lo stato dell'invio ed in **Result** un messaggio con il risultato dell'invio. In caso di errore si attiva per un loop l'uscita **Fault**. +-----------------------------------+-----------------------------------+ | **Enable** (BOOL) | Comando invio notifica. | +-----------------------------------+-----------------------------------+ | **SpyOn** (BOOL) | Se attivo permette di spiare il | | | funzionamento della FB. | +-----------------------------------+-----------------------------------+ | **PrivateKey** (@STRING) | Indirizzo definizione stringa | | | chiave privata (Assegnata dal | | | servizio PushSafer). | +-----------------------------------+-----------------------------------+ | **Device** (@STRING) | Indirizzo definizione dispositivo | | | (Assegnato dal servizio | | | PushSafer). | +-----------------------------------+-----------------------------------+ | **Title** (@STRING) | Indirizzo stringa definizione | | | titolo notifica. | +-----------------------------------+-----------------------------------+ | **Icon** (USINT) | Definizione icona notifica (Vedi | | | documentazione servizio | | | PushSafer). | +-----------------------------------+-----------------------------------+ | **Sound** (USINT) | Definizione suono notifica (Vedi | | | documentazione servizio | | | PushSafer). | +-----------------------------------+-----------------------------------+ | **Vibration** (USINT) | Definizione vibrazione notifica | | | (Vedi documentazione servizio | | | PushSafer). | +-----------------------------------+-----------------------------------+ | **Message** (@STRING) | Indirizzo stringa definizione | | | messaggio notifica. | +-----------------------------------+-----------------------------------+ | **Extras** (@STRING) | Indirizzo stringa definizione | | | eventuali parametri aggiuntivi | | | notifica. | +-----------------------------------+-----------------------------------+ | **Done** (BOOL) | Si attiva al termine della | | | esecuzione comando. Disabilitare | | | **Enable** per disattivarla. | +-----------------------------------+-----------------------------------+ | **Fault** (BOOL) | Attivo per un loop se errore | | | esecuzione comando. | +-----------------------------------+-----------------------------------+ | **APICalls** (UDINT) | Ritorna il numero di notifiche | | | ancora disponibili (Le notifiche | | | vanno acquistate). | +-----------------------------------+-----------------------------------+ | **Status** (USINT) | Ritorna lo stato invio (0: | | | Errore, 1: Invio Ok). | +-----------------------------------+-----------------------------------+ | **Result** (STRING[32]) | Ritorna il risultato dell'invio. | +-----------------------------------+-----------------------------------+ **Trigger di spy** Se **SpyOn** attivo viene eseguita la funzione `SysSpyData <#FctSysSpyData>`__ che permette di spiare il funzionamento della FB. Sono previsti vari livelli di triggers. +-------------+-----------------------------------+ | **TFlags** | **Descrizione** | +-------------+-----------------------------------+ | 16#00000001 | **Ok:** Risultato invio notifica. | +-------------+-----------------------------------+ | 16#40000000 | **Er:** Messaggio di errore. | +-------------+-----------------------------------+ **Codici di errore** In caso di errore si attiva l'uscita **Fault**, con `SysGetLastError <#FctSysGetLastError>`__ è possibile rilevare il codice di errore. +------------+-----------------------------------------------------------+ | **Codice** | **Descrizione** | +------------+-----------------------------------------------------------+ | 10083020 | FB eseguita in una task diversa dalla task di background. | +------------+-----------------------------------------------------------+ | 10083050 | Timeout esecuzione. | +------------+-----------------------------------------------------------+ | 10083100 | Errore in FB HTTPClient. | +------------+-----------------------------------------------------------+ | 10083200 | Superata dimensione massima messaggio (8192 Kb). | +------------+-----------------------------------------------------------+ | 10083300 | Errore risposta da server Pushsafer. | +------------+-----------------------------------------------------------+ **Esempi** Nell'esempio attivando **Di00CPU** viene inviato una notifica al server Pushsafer che la inoltrerà al dispositivo definito in **Device**. **Definizione variabili** VAR HTTPRq : HTTPClient; (\* HTTP client \*) Notify : PushSafer; (\* Push safer notify \*) END_VAR **Esempio FBD** *(PTP119B500, FBD_PushSafer)* |image75| **Esempi** Nell'esempio attivando **Send** viene inviato una notifica al server Pushsafer che la inoltrerà al dispositivo definito in **Device**. **Definizione variabili** VAR HTTPRq : HTTPClient; (\* HTTP client \*) Notify : PushSafer; (\* Push safer notify \*) Send : BOOL; (\* Send notify command \*) END_VAR **Esempio FBD** *(PTP119B500, ST_PushSafer)* .. code-block:: none (\* INIZIALIZZAZIONE \*) (\* Eseguo inizializzazione. \*) IF (SysFirstLoop) THEN Notify.PrivateKey:=ADR('My private key'); (\* Private key \*) Notify.Device:=ADR('1234'); (\* Device to notify \*) Notify.HTTPClient:=ADR(HTTPRq); (\* HTTP client \*) END_IF; (\* GESTIONE INVIO NOTIFICHE \*) (\* Gestione invio notifiche. \*) Notify(); (\* Push safer notify \*) IF (Notify.Done) THEN Notify.Enable:=FALSE; END_IF; (\* INVIO RICHIESTA CHIAMATA \*) (\* Alle 16:15 viene inviata la richiesta di chiamata. \*) IF (Send) THEN Send:=FALSE; (\* Send notify command \*) Notify.Enable:=TRUE; (\* Notify enable \*) Notify.Icon:=8; (\* Notify icon \*) Notify.Sound:=14; (\* Notify sound \*) Notify.Vibration:=1; (\* Notify vibration \*) Notify.Title:=ADR('Title'); (\* Notify title \*) Notify.Message:=ADR('Message'); (\* Notify message \*) END_IF; (\* [End of file] \*) .. |image0| image:: media/image1.jpg :width: 1.75208in :height: 2.075in .. |image1| image:: media/image1.jpg :width: 1.75208in :height: 2.075in .. |image2| image:: media/image2.jpg :width: 7.08681in :height: 0.55139in .. |image3| image:: media/image3.jpg :width: 7.36389in :height: 4.10833in .. |image4| image:: media/image4.jpg :width: 7.08681in :height: 0.90972in .. |image5| image:: media/image5.jpg :width: 4.72431in :height: 3.95694in .. |image6| image:: media/image6.jpg :width: 1.74028in :height: 2.09444in .. |image7| image:: media/image7.jpg :width: 7.08681in :height: 0.55139in .. |image8| image:: media/image8.jpg :width: 7.36389in :height: 2.59236in .. |image9| image:: media/image9.jpg :width: 7.08681in :height: 0.61042in .. |image10| image:: media/image10.jpg :width: 4.72431in :height: 3.98403in .. |image11| image:: media/image11.jpg :width: 1.74028in :height: 2.08264in .. |image12| image:: media/image12.jpg :width: 7.08681in :height: 0.55139in .. |image13| image:: media/image13.jpg :width: 7.36389in :height: 4.11389in .. |image14| image:: media/image14.jpg :width: 7.08681in :height: 0.93681in .. |image15| image:: media/image15.jpg :width: 4.72431in :height: 3.29931in .. |image16| image:: media/image16.jpg :width: 1.72847in :height: 2.08264in .. |image17| image:: media/image17.jpg :width: 7.08681in :height: 0.55139in .. |image18| image:: media/image18.jpg :width: 6.93403in :height: 3.65903in .. |image19| image:: media/image19.jpg :width: 7.08681in :height: 0.61042in .. |image20| image:: media/image19.jpg :width: 7.08681in :height: 0.61042in .. |image21| image:: media/image20.jpg :width: 4.72431in :height: 3.29931in .. |image22| image:: media/image21.jpg :width: 1.36597in :height: 0.94861in .. |image23| image:: media/image22.jpg :width: 7.36389in :height: 0.72153in .. |image24| image:: media/image23.jpg :width: 5.67708in :height: 3.51944in .. |image25| image:: media/image24.jpg :width: 1.34236in :height: 0.94861in .. |image26| image:: media/image25.jpg :width: 7.28333in :height: 0.56944in .. |image27| image:: media/image26.jpg :width: 6.74444in :height: 1.53125in .. |image28| image:: media/image27.jpg :width: 1.62569in :height: 1.75208in .. |image29| image:: media/image28.jpg :width: 7.08681in :height: 1.60625in .. |image30| image:: media/image29.jpg :width: 7.08681in :height: 6.18472in .. |image31| image:: media/image30.jpg :width: 1.53125in :height: 1.32292in .. |image32| image:: media/image31.jpg :width: 7.28333in :height: 0.93681in .. |image33| image:: media/image31.jpg :width: 7.28333in :height: 0.93681in .. |image34| image:: media/image32.jpg :width: 1.69653in :height: 1.70833in .. |image35| image:: media/image33.jpg :width: 7.08681in :height: 5.14931in .. |image36| image:: media/image34.jpg :width: 1.67708in :height: 1.5in .. |image37| image:: media/image35.jpg :width: 7.08681in :height: 0.53542in .. |image38| image:: media/image36.jpg :width: 7.08681in :height: 3.3625in .. |image39| image:: media/image37.jpg :width: 7.36389in :height: 0.65625in .. |image40| image:: media/image35.jpg :width: 7.08681in :height: 0.53542in .. |image41| image:: media/image36.jpg :width: 7.08681in :height: 3.3625in .. |image42| image:: media/image37.jpg :width: 7.36389in :height: 0.65625in .. |image43| image:: media/image38.jpg :width: 1.92917in :height: 1.32292in .. |image44| image:: media/image39.jpg :width: 7.08681in :height: 0.38958in .. |image45| image:: media/image40.jpg :width: 7.08681in :height: 3.20069in .. |image46| image:: media/image41.jpg :width: 1.72847in :height: 2.25208in .. |image47| image:: media/image42.jpg :width: 1.30347in :height: 2.85417in .. |image48| image:: media/image43.jpg :width: 7.08681in :height: 0.56319in .. |image49| image:: media/image43.jpg :width: 7.08681in :height: 0.56319in .. |image50| image:: media/image44.jpg :width: 2.06319in :height: 3.93681in .. |image51| image:: media/image45.jpg :width: 7.08681in :height: 1.26806in .. |image52| image:: media/image46.jpg :width: 7.08681in :height: 5.425in .. |image53| image:: media/image47.jpg :width: 7.08681in :height: 4.83889in .. |image54| image:: media/image48.jpg :width: 7.08681in :height: 6.01181in .. |image55| image:: media/image49.jpg :width: 3.14931in :height: 2.64583in .. |image56| image:: media/image50.jpg :width: 2.44722in :height: 1.875in .. |image57| image:: media/image51.jpg :width: 2.44722in :height: 3.63056in .. |image58| image:: media/image52.jpg :width: 2.44722in :height: 1.44861in .. |image59| image:: media/image53.jpg :width: 2.44722in :height: 1.63472in .. |image60| image:: media/image54.jpg :width: 2.44722in :height: 1.92986in .. |image61| image:: media/image50.jpg :width: 2.44722in :height: 1.875in .. |image62| image:: media/image51.jpg :width: 2.44722in :height: 3.63056in .. |image63| image:: media/image52.jpg :width: 2.44722in :height: 1.44861in .. |image64| image:: media/image53.jpg :width: 2.44722in :height: 1.63472in .. |image65| image:: media/image54.jpg :width: 2.44722in :height: 1.92986in .. |image66| image:: media/image55.jpg :width: 4.72431in :height: 2.75625in .. |image67| image:: media/image56.jpg :width: 7.08681in :height: 1.25972in .. |image68| image:: media/image56.jpg :width: 7.08681in :height: 1.25972in .. |image69| image:: media/image57.jpg :width: 1.90556in :height: 2.64583in .. |image70| image:: media/image58.jpg :width: 7.08681in :height: 0.3625in .. |image71| image:: media/image59.jpg :width: 6.07292in :height: 4.70833in .. |image72| image:: media/image60.jpg :width: 7.08681in :height: 1.44861in .. |image73| image:: media/image60.jpg :width: 7.08681in :height: 1.44861in .. |image74| image:: media/image61.jpg :width: 1.34236in :height: 2.45694in .. |image75| image:: media/image62.jpg :width: 4.77986in :height: 3.25972in