Come si utilizza la console di spionaggio

List

Questa pagina fa parte del Manuale Programmazione IEC 61131-3. Vai all indice.

Certo non vi sarà sfuggito che quasi tutti i blocchi funzione forniti con le nostre libreria hanno un ingresso definito come SpyOn.  Non pensiamo al grande fratello che ci stà spiando od a guerre tra spie, l’attivazione di questo ingresso permette di poter “spiare” il funzionamento del FB. Per lo “spionaggio” viene eseguita la funzione SysWrSpyData che permette da programma utente di inviare dati verso la console di spionaggio accessibile da Telnet. Naturalmente l’esecuzione dello spionaggio (Solo se è attiva la console da telnet) rallenta l’esecuzione del FB.

In questo topic sul forum si trova un esempio che illustra il funzionamento “spiando” un FB di comunicazione ModbusMaster.

Vantaggi dello spionaggio

Il vantaggio di questo metodo di debug è che il sistema operativo memorizza le informazioni ricevute sulla chiamata alla funzione SysWrSpyData rendendo disponibili i dati anche a seguito di chiamate consecutive molto ravvicinate (Anche pochi mS). Nella visualizzazione, in testa ad ogni record sono riportati i riferimenti temporali in base ai parametri indicati con il comando SpyData.

Nell’esempio sotto viene spiato un client NTP che esegue richieste al server ogni 60 secondi  si vede che ogni richiesta inizia 60 secondi dopo il termine della richiesta precedente. Nel caso in cui le chiamate alla funzione SysWrSpyData siano troppo ravvicinate e non vi sia il tempo di visualizzarle nella console di spionaggio si perdono le memorizzazioni, questo è indicato dal valore (—-) nella intestazione del record.

Gruppo di funzioni e FB

Console di spionaggio

Accedendo al sistema in Telnet, si può utilizzare l’utility terminal menù Utilities→Terminal del nostro programma Toolly. Utilizzando una connessione TcpIp Client all’indirizzo IP del sistema porta 23, dopo l’autenticazione (Login: Admin, Password Admin) digitando il comando SpyData, saranno visualizzati i dati inviati dalle chiamate alla funzione SysWrSpyData eseguite nel programma. Come si vede nella figura la console di spionaggio sta spiando un FB SNTPRequest che esegue la sincronizzazione con un server di tempo su Internet.

Immagine console di spionaggio con Toolly

Utilizzo del trigger

Nei vari oggetti che prevedono lo spionaggio nel capitolo Trigger di spy si trova indicazione del livello di trigger. Il trigger permette di attivare lo spionaggio solo su alcuni eventi tra quelli generati, in modo da evitare di saturare il buffer di spionaggio concentrandosi solo sugli eventi che ci interessano. Il livello di trigger si compone di 32 bits che possono essere attivati in combinazione di OR logico tra di loro.

Esempio utilizzo trigger

Se prendiamo ad esempio la tabella trigger del FB ModbusMaster che riporto qui sotto:

TriggerDescrizione
16#00000001Tx: Invio frame comando modbus.
16#00000002Rx: Ricezione frame risposta modbus.
16#40000000Er: Errore di esecuzione.
  • Per visualizzare solo i frame di invio comandi modbus, dovremo dare da Telnet il comando SpyData -t 00000001.
  • Per visualizzare solo gli errori di esecuzione, dovremo dare da Telnet il comando SpyData -t 40000000.
  • Per visualizzare sia i frame di comando che le risposte modbus, dovremo dare da Telnet il comando SpyData -t 00000003.

Consigli

Se nel programma si hanno molti FB eseguiti contemporaneamente è preferibile attivare lo spionaggio solo su uno alla volta in modo da non intasare il buffer di memorizzazione perdendo records.

Utilizzate nei vostri programmi la funzione SysWrSpyData questo vi permette di eseguire il debug e/o visualizzare informazioni utili sul funzionamento del programma semplicemente accedendo anche da remoto in Telnet al sistema. E quanto più il record di spionaggio che generate è chiaro più è indicativo del problema.

Di seguito riportiamo il programma SpyCapture (Download) che grazie ad una connessione in localhost cattura tutti i record di spionaggio e li salva su disco. E’ possibile aggiungerlo al proprio programma per catturare lo spionaggio e poter eseguire una diagnosi a posteriori del funzionamento.

LogicLab (Ptp195), SpyCapture
PROGRAM SpyCapture
VAR
    Start : BOOL;    (* Start command *)
    CaseNr : USINT;    (* Program case *)
    i : UDINT;    (* Auxiliary variable *)
    Ptr : @BYTE;    (* Auxiliary pointer *)
    TimeBf : ARRAY[0..1] OF UDINT;    (* Time buffer (uS) *)
    TCPClient : SysTCPClient;    (* TCP Client *)
    RxData : PVOID;    (* Rx data memory (SysRMAlloc) *)
    RDIDx : UDINT;    (* Rx Data index *)
    DSize : UDINT := 1024;    (* Data size *)
    CLI : CLIClient;    (* Command line interface client *)
    Logger : StringToLogFile_v3;    (* Data logger *)
END_VAR

// *****************************************************************************
// PROGRAM "SpyCapture"
// *****************************************************************************
// It's managed the telnet connection as localhost, after authentication the
// SpyData command is issued and all the spying records read are stored on the
// defined file.
// -----------------------------------------------------------------------------
// TimeBf[0]: Used to manage timeout error
// TimeBf[1]: Used to free "RxData" memory
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------
    // Program initializations.

    IF (SysFirstLoop) THEN

        // TCPClient initialization, it connects to localhost.

        TCPClient.PeerAdd:=ADR('127.0.0.1'); //Peer address
        TCPClient.PeerPort:=23; //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

        // Command line interface initialization.

        CLI.SpyOn:=TRUE; //Spy On
        CLI.CWTime:=0.1; //Character wait time (S)
        CLI.PTime:=10.0; //Prompt time (S)
        CLI.ABLength:=1024; //Answer buffer length

        // Logger initialization.

        Logger.Mode:=1; //AsciiHex mode
        Logger.LDLength:=0; //Log data length
        Logger.Header:=eNULL; //Header string
        Logger.Filename:=ADR('D:/SpyData.txt'); //Log file
    END_IF;

    // -------------------------------------------------------------------------
    // FBs EXECUTION
    // -------------------------------------------------------------------------
    // Manage the TCP client.

    TCPClient(); //TCPClient
    CLI.Fp:=TCPClient.File; //File pointer
    IF (CaseNr < 100) THEN CLI(); END_IF;
    IF (CLI.Fault) THEN CaseNr:=0; END_IF;

    // -------------------------------------------------------------------------
    // TIMEOUT CONTROL
    // -------------------------------------------------------------------------
    // The sequences execution timeout is checked.

    IF ((CaseNr = 0) OR (CaseNr = 100)) THEN TimeBf[0]:=SysGetSysTime(TRUE); END_IF;
    IF ((SysGetSysTime(TRUE)-TimeBf[0]) > 50000000) THEN CaseNr:=0; RETURN; END_IF;

    // If "RxData" memory is not longer used it's deallocated.

    IF (RxData <> eNULL) THEN
        IF ((SysGetSysTime(TRUE)-TimeBf[1]) > 5000000) THEN i:=SysRMFree(ADR(RxData)); END_IF;
    END_IF;
    
    // -------------------------------------------------------------------------
    // PROGRAM CASES
    // -------------------------------------------------------------------------
    // Program cases management.

    CASE (CaseNr) OF

        // ---------------------------------------------------------------------
        // CONNECTION TO LOCALHOST
        // ---------------------------------------------------------------------
        // St "Start" command to start sequencies.

        0:
        CLI.CSend:=FALSE; //Command send
        TCPClient.Connect:=FALSE; //Connect command
        IF NOT(Start) THEN RETURN; END_IF;

        // Connect to the server.

        TCPClient.Connect:=TRUE; //Connect command
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Check if client connect and wait for "Login:" string.

        1:
        IF NOT(TCPClient.Connected) THEN RETURN; END_IF;
        CLI.CStr:=NULL; CLI.PStr:=NULL; CLI.EAStr:=ADR('Login:'); CLI.CSend:=TRUE;
        IF NOT(CLI.EOL) THEN RETURN; END_IF;
        CLI.CSend:=FALSE; //Command send
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Send login username and wait for "Password:" string.

        2:
        CLI.CStr:=ADR('Admin$r'); CLI.PStr:=NULL; CLI.EAStr:=ADR('Password:'); CLI.CSend:=TRUE;
        IF NOT(CLI.EOL) THEN RETURN; END_IF;
        CLI.CSend:=FALSE; //Command send
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Send password and wait for "[Admin]>" string as a prompt.

        3:
        CLI.CStr:=ADR('Admin$r'); CLI.PStr:=ADR('[Admin]>'); CLI.EAStr:=NULL; CLI.CSend:=TRUE;
        IF NOT(CLI.EOL) THEN RETURN; END_IF;
        CLI.CSend:=FALSE; //Command send
        CaseNr:=10; //Program case

        // ---------------------------------------------------------------------
        // SPYDATA COMMAND
        // ---------------------------------------------------------------------
        // SEnd the "SpyData" command.

        10:
        CLI.CStr:=ADR('SpyData$r'); CLI.PStr:=eNULL; CLI.EAStr:=ADR('Spy data active'); CLI.CSend:=TRUE;
        IF NOT(CLI.EOL) THEN RETURN; END_IF;
        CLI.CSend:=FALSE; //Command send
        CaseNr:=100; //Program case

        // ---------------------------------------------------------------------
        // SPYING DATA ACQUISITION
        // ---------------------------------------------------------------------
        // Initialize data acquisition.

        100:
        IF NOT(Start) THEN CaseNr:=0; RETURN; END_IF;
        IF (SysFGetIChars(TCPClient.File) = 0) THEN RETURN; END_IF;
        TimeBf[1]:=SysGetSysTime(TRUE); //Time buffer (uS)

        // Allocate "RxData" memory.

        IF (RxData = eNULL) THEN
            IF NOT(SysRMAlloc(DSize, ADR(RxData))) THEN RETURN; END_IF;
        END_IF;

        i:=Sysmemset(RxData, 0, DSize);
        RDIDx:=0; //Rx Data index
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // The spying record terminates with .

        101:
        WHILE (SysFGetIChars(TCPClient.File) > 0) DO

            Ptr:=RxData+RDIDx; @Ptr:=TO_BYTE(Sysfgetc(TCPClient.File));
            IF (@Ptr = 16#0A) THEN
                Logger(LData:=RxData); //Write data to file
                CaseNr:=100; //Program case
                RETURN;
            END_IF;

            IF (RDIDx < DSize) THEN RDIDx:=RDIDx+1; END_IF;
        END_WHILE;
    END_CASE;

// [End of file]
Was this article helpful?