using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;

namespace IOB_WIN_OMRON.Iob
{
    public class Omron : Iob.GenericNext
    {
        #region Public Constructors

        /// <summary>
        /// estende l'init della classe base...
        /// </summary>
        /// <param name="caller">Form chiamante</param>
        /// <param name="IobConfFull">Configurazione (v 4.x)</param>
        public Omron(AdapterFormNext caller, IobConfTree IobConfFull) : base(caller, IobConfFull)
        {
            // gestione invio ritardato contapezzi
            
            lastPzCountSend = DateTime.Now;
            lastWarnODL = DateTime.Now;

            // imposto i parametri PLC
            setParamPlc();
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Processo i task richiesti e li elimino dalla coda 1:1
        /// </summary>
        /// <param name="task2exe"></param>
        public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe, string codTav)
        {
            // uso metodo base x ora
            return base.executeTasks(task2exe, codTav);
        }

        /// <summary>
        /// Recupero dati dinamici...
        /// </summary>
        public override Dictionary<string, string> getDynData()
        {
            // valore non presente in vers default... se gestito fare override
            Dictionary<string, string> outVal = new Dictionary<string, string>();
            outVal.Add("kgAct", pesoRilevato.ToString());
            outVal.Add("kgImp", pesoRichiesto.ToString());
            return outVal;
        }

        /// <summary>
        /// Effettua vero processing contapezzi
        /// </summary>
        public override void processContapezzi()
        {
            if (utils.CRB("enableContapezzi"))
            {
#if false
        try
        {
          // hard coded... !!!FARE!!! rivedere megio conf
          contapezziPLC = pzCounter;
          // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area)
          if (cIobConf.optPar.Count > 0 && IOBConfFull.Device.PzCountMode != "")
          {
          }
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in contapezzi OMRON");
        }
#endif
            }
        }

        /// <summary>
        /// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
        /// aggiornare x display in form</paramref>
        /// </summary>
        public override void readSemafori(ref newDisplayData currDispData)
        {
            base.readSemafori(ref currDispData);
            try
            {
                if (verboseLog)
                {
                    lgInfo("inizio read semafori");
                }

                currDispData.semIn = Semaforo.SV;

                // effettuo TUTTE le letture
                OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 0, 60, out memReadCIO_IN);
                OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 100, 10, out memReadCIO_OUT);
                //OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 0, 8, out memReadDM);
                //OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 8, out memReadWR);

                contapezziPLC = pesoRilevato;
                // decodifica e gestione
                decodeToBaseBitmap();
                reportRawInput(ref currDispData);
            }
            catch
            {
                currDispData.semIn = Semaforo.SR;
            }
        }

        /// <summary>
        /// Effettua reset del contapezzi, in questo caso il conteggio dei KG
        /// </summary>
        /// <returns></returns>
        public override bool resetContapezziPLC(string codTav)
        {
            bool answ = false;
#if false
      // ...SE abilitato da conf IOB
      if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
      {
        // scrivo valore 0 x il contapezzi
        try
        {
          pzCounter = 0;
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in RESET contapezzi OMRON");
          connectionOk = false;
        }
        answ = true;
      }
      else
      {
        lgError("Impossibile effettuare RESET contapezzi OMRON, mancanza parametro OPT:ENABLE_PZ_RESET");
      }
#endif
            return answ;
        }

        /// <summary>
        /// Effettua IMPOSTAZIONE FORZATA del contapezzi, in questo caso il conteggio dei KG
        /// </summary>
        /// <returns></returns>
        public override bool setcontapezziPLC(int newPzCount, string codTav)
        {
            bool answ = false;
#if false
      // ...SE abilitato da conf IOB
      if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
      {
        // scrivo valore 0 x il contapezzi
        try
        {
          pzCounter = newPzCount;
        }
        catch (Exception exc)
        {
          lgError(exc, "Errore in SET contapezzi OMRON");
          connectionOk = false;
        }
        answ = true;
      }
      else
      {
        lgError("Impossibile effettuare SET contapezzi OMRON, mancanza parametro OPT:ENABLE_PZ_RESET");
      }
#endif
            return answ;
        }

        /// <summary>
        /// Override connessione
        /// </summary>
        public override void tryConnect()
        {
            if (!connectionOk)
            {
                // controllo che il ping sia stato tentato almeno pingTestSec fa...
                if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
                {
                    if (verboseLog || periodicLog)
                    {
                        lgInfo("OMRON: ConnKO - tryConnect");
                    }
                    // in primis salvo data ping...
                    lastPING = DateTime.Now;
                    // se passa il ping faccio il resto...
                    if (testPingMachine == IPStatus.Success)
                    {
                        string szStatusConnection = "";
                        try
                        {
                            // ora provo connessione...
                            parentForm.commPlcActive = true;
                            short esitoLink = doConnect();
                            lgInfo($"szStatusConnection OMRON, esitoLink: {esitoLink}");
                            parentForm.commPlcActive = false;
                            // imposto i parametri...
                            setParamPlc();
                            connectionOk = true;
                            // refresh stato connessione!!!
                            if (connectionOk)
                            {
                                queueInEnabCurr = true;
                                if (adpRunning)
                                {
                                    lgInfo("Connessione OK");
                                }
                            }
                            else
                            {
                                lgError("Impossibile procedere, connessione mancante...");
                            }
                        }
                        catch (Exception exc)
                        {
                            lgFatal($"Errore nella connessione all'adapter OMRON: {szStatusConnection}{Environment.NewLine}{exc}");
                            connectionOk = false;
                            lgInfo($"Eccezione in TryConnect, Adapter OMRON NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
                        }
                    }
                    else
                    {
                        // loggo no risposta ping ...
                        connectionOk = false;
                        if (verboseLog || periodicLog)
                        {
                            lgInfo($"Attenzione: OMRON controllo PING fallito per IP {IOBConfFull.Device.Connect.PingIpAddr}");
                        }
                    }
                }
            }
            else
            {
                needRefresh = true;
            }
            // se non è ancora connesso faccio procesisng memoria caso disconnesso...
            if (!connectionOk)
            {
                // processo semafori ed invio...
                processMemoryDiscon();
            }
        }

        /// <summary>
        /// Override disconnessione
        /// </summary>
        public override void tryDisconnect()
        {
            if (connectionOk)
            {
                string szStatusConnection = "";
                try
                {
                    OMRON_ref.Close();
                    connectionOk = false;
                    lgInfo(szStatusConnection);
                    lgInfo("Effettuata disconnessione adapter OMRON!");
                }
                catch (Exception exc)
                {
                    lgFatal(exc, "Errore nella disconnessione dall'adapter OMRON");
                }
            }
            else
            {
                lgError("IMPOSSIBILE effettuare disconnessione OMRON: Connessione non disponibile...");
            }
            queueInEnabCurr = false;
        }

        #endregion Public Methods

        #region Protected Fields

        /// <summary>
        /// Array valori letti da memoria CIO INGRESSI
        /// </summary>
        protected short[] memReadCIO_IN;

        /// <summary>
        /// Array valori letti da memoria CIO USCITE
        /// </summary>
        protected short[] memReadCIO_OUT;

        /// <summary>
        /// Array valori letti da memoria DM
        /// </summary>
        protected short[] memReadDM;

        /// <summary>
        /// Array valori letti da memoria WR
        /// </summary>
        protected short[] memReadWR;

        /// <summary>
        /// Array valori SCRITTI su memoria CIO
        /// </summary>
        protected short[] memWriteCIO;

        /// <summary>
        /// Array valori SCRITTI su memoria DM
        /// </summary>
        protected short[] memWriteDM;

        /// <summary>
        /// Array valori SCRITTI su memoria WR
        /// </summary>
        protected short[] memWriteWR;

        /// <summary>
        /// Oggetto MAIN x connessione OMRON
        /// </summary>
        protected OmronFinsTCP.Net.EtherNetPLC OMRON_ref;

        /// <summary>
        /// Array delle risposte dal controllo OMRON
        /// </summary>
        protected System.Collections.ArrayList resDataArray;

        #endregion Protected Fields

        #region Protected Properties

        /// <summary>
        /// Lettura scrittura commessa da OMRON (come array di coppie di byte)
        /// </summary>
        protected string commessa
        {
            get
            {
                string answ = "";
                short[] response;
                byte[] byteData = new byte[20];
                try
                {
                    // leggo
                    OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 10, out response);
                    // copio come byte...
                    Buffer.BlockCopy(response, 0, byteData, 0, response.Length);
                    answ = Encoding.ASCII.GetString(byteData);
                }
                catch
                { }
                return answ;
            }
            set
            {
                // converto in byte la mia stringa
                byte[] valByte = Encoding.ASCII.GetBytes(value);
                // limite 20 char... imposto a 20!
                int maxChar = valByte.Length < 20 ? valByte.Length : 20;
                // creao un array di 10 short MAX
                short[] valoriWord = new short[10];
                // copio i valori
                Buffer.BlockCopy(valByte, 0, valoriWord, 0, maxChar);
                // scrivo su OMRON!
                OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 10, valoriWord);
            }
        }

        /// <summary>
        /// Verifico se abbia ALMENO un errore...
        /// </summary>
        protected bool hasError
        {
            get
            {
                bool answ = false;
                if (memReadCIO_OUT != null)
                {
                    answ = ((memReadCIO_OUT[4] & (1 << 7)) != 0);
                }
#if false
        bool answ = false;
        // controllo primi errori, parto dal primo e poi OR
        answ = answ || ((memReadCIO[0] & (1 << 7)) == 1);
        answ = answ || ((memReadCIO[1] & (1 << 0)) == 1);
        answ = answ || ((memReadCIO[1] & (1 << 1)) == 1);
        answ = answ || ((memReadCIO[1] & (1 << 3)) == 1);
        answ = answ || (memReadCIO[2] > 0);
        answ = answ || ((memReadCIO[3] & (1 << 0)) == 1);
        answ = answ || ((memReadCIO[3] & (1 << 1)) == 1);
#endif
                return answ;
            }
        }

        /// <summary>
        /// Oggetto get/set per lettura (DM22-23) /scrittura (DM26-27) PESO RICHIESTO
        /// </summary>
        protected int pesoRichiesto
        {
            get
            {
                int answ = 0;
                try
                {
                    short[] valDM;
                    OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 22, 2, out valDM);
                    answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
                }
                catch
                { }
                return answ;
            }
            set
            {
                short[] valDM = intToShort(value);
                OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.DM, 26, 2, valDM);
                // ora devo "comandare scrittura" su OMRON...

                // sollevo bit 65.0 x azzeramento
                OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 1);
                Thread.Sleep(500);
                // ora sollevo bit e 65.1 x indicare nuovo valore...
                OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 2);
                // ora attendo ed abbasso tutti i bit
                Thread.Sleep(500);
                OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 0);
            }
        }

        /// <summary>
        /// Oggetto per lettura PESO rilevato (DM20-21)
        /// </summary>
        protected int pesoRilevato
        {
            get
            {
                int answ = 0;
                try
                {
                    short[] valDM;
                    OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 20, 2, out valDM);
                    // legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati,
                    // dove il primo è x 1 e il secondo x 10000 (in pratica va in testa) esempio
                    // 12540 --> diviso in 1 | 2540 --> in HEX diventa 1 | 9472, ma il 9472 va su
                    // byte[0] e 1 su byte[1]
                    answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
                }
                catch
                { }
                return answ;
            }
        }

        /// <summary>
        /// Oggetto get/set x portata
        /// </summary>
        protected int portata
        {
            get
            {
                int answ = 0;
                try
                {
                    short valDM;
                    OMRON_ref.ReadWord(OmronFinsTCP.Net.PlcMemory.DM, 50, out valDM);
                    answ = convDHD(valDM);
                }
                catch
                { }
                return answ;
            }
            set
            {
                // scrivo portata su memoria DM50...
                short portata = (short)convHD("0x" + value.ToString("0000"));
                OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.DM, 50, portata);
            }
        }

        /// <summary>
        /// Oggetto get/set x quantità richiesta LOTTO
        /// </summary>
        protected int quantitaLotto
        {
            get
            {
                int answ = 0;
                try
                {
                    short[] valDM;
                    OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 52, 2, out valDM);
                    answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
                }
                catch
                { }
                return answ;
            }
            set
            {
                short[] valDM = intToShort(value);
                OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.DM, 52, 2, valDM);
            }
        }

        #endregion Protected Properties

        #region Protected Methods

        /// <summary>
        /// Calcola la conversione da byte --&gt; num decimale --&gt; HEX --&gt; conversione come
        /// stringa in INT
        /// </summary>
        /// <param name="valore"></param>
        /// <returns></returns>
        protected static int convDHD(short valore)
        {
            // legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove il
            // primo è x 1 e il secondo x 10000 (in pratica va in testa) esempio 12540 --> diviso in
            // 1 | 2540 --> in HEX diventa 1 | 9472, ma il 9472 va su byte[0] e 1 su byte[1]
            int answ = 0;
            string hexVal = valore.ToString("x");
            int.TryParse(hexVal, out answ);
            return answ;
        }

        /// <summary>
        /// Converte un valore di 2 short in un unico numero accostato:
        /// es: legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove il
        /// primo è x 1 e il secondo x 10000 (in pratica va in testa) 12540 --&gt; diviso in 1 |
        /// 2540 --&gt; in HEX diventa 1 | 9472, ma il 9472 va su byte[0] e 1 su byte[1]
        /// </summary>
        /// <param name="valori"></param>
        /// <returns></returns>
        protected static int convFromHex(short[] valori)
        {
            int answ = 0;
            string fullVal = $"{convDHD(valori[1]).ToString("D4")}{convDHD(valori[0]).ToString("D4")}";
            int.TryParse(fullVal, out answ);
            return answ;
        }

        /// <summary>
        /// Calcola la conversione da INTERO a intero HEX x OMRON
        /// </summary>
        /// <param name="valore"></param>
        /// <returns></returns>
        protected static int convHD(string hexVal)
        {
            int answ = 0;
            if (!string.IsNullOrEmpty(hexVal))
            {
                try
                {
                    if (!hexVal.StartsWith("0x"))
                    {
                        hexVal = "0x" + hexVal;
                    }
                    answ = Convert.ToInt32(hexVal, 16);
                }
                catch
                { }
            }
            return answ;
        }

        /// <summary>
        /// Converte un valore INT in un array di due SHORT valido x scrivere su OMRON
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        protected static short[] intToShort(int value)
        {
            short[] valDM = new short[2];
            short highVal = (short)(value / 10000);
            short lowVal = (short)(value - highVal * 10000);
            valDM[0] = (short)convHD("0x" + lowVal.ToString("0000"));
            valDM[1] = (short)convHD("0x" + highVal.ToString("0000"));
            return valDM;
        }

        /// <summary>
        /// OVerride metodo x scrittura parametri su PLC
        /// </summary>
        /// <param name="updatedPar"></param>
        protected override void plcWriteParams(ref List<objItem> updatedPar)
        {
            int valInt = 0;
            if (updatedPar != null)
            {
                // controllo i parametri... ne gestisco 4...
                foreach (var item in updatedPar)
                {
                    lgInfo($"Richiesti processing plcWriteParams per {item.name} | valore richiesto {item.reqValue} | valore attuale {item.value}");
                    string readBackVal = "";
                    switch (item.uid)
                    {
                        case "kgRich":
                            // 2023.09.19 value --> reqValue
                            int.TryParse(item.reqValue, out valInt);
                            pesoRichiesto = valInt;
                            readBackVal = pesoRichiesto.ToString();
                            break;

                        case "kgLotto":
                            // 2023.09.19 value --> reqValue
                            int.TryParse(item.reqValue, out valInt);
                            quantitaLotto = valInt;
                            readBackVal = quantitaLotto.ToString();
                            break;

                        case "portata":
                            // 2023.09.19 value --> reqValue
                            int.TryParse(item.reqValue, out valInt);
                            portata = valInt;
                            readBackVal = portata.ToString();
                            break;

                        case "setComm":
                            // 2023.09.19 value --> reqValue
                            commessa = item.reqValue;
                            readBackVal = commessa;
                            break;

                        default:
                            break;
                    }
                    // SE non corrispondessero LOGGO ERRORE...
                    if (item.value != readBackVal)
                    {
                        lgError($"Errore in plcWriteParams: uid {item.uid} | Wrote {item.value} | ReadBack {readBackVal}");
                    }
                    // 2023.09.19 resetto richiesta
                    else
                    {
                        item.reqValue = "";
                    }
                }
            }
        }

        #endregion Protected Methods

        #region Private Fields

        /// <summary>
        /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO
        /// </summary>
        private Dictionary<string, string> signLUT = new Dictionary<string, string>();

        #endregion Private Fields

        #region Private Methods

        /// <summary>
        /// Effettua decodifica aree memoria alla bitmap usata x MAPO
        /// </summary>
        private void decodeToBaseBitmap()
        {
            // init a zero...
            B_input = 0;

            /* -----------------------------------------------------
               * bitmap MAPO
               * B0: POWER_ON
               * B1: RUN
               * B2: pzCount -- non usato
               * B3: allarme
               * B4: manuale -- non usato
               * B5: carico SILOS
               * B6: carico AUTOBOTTE
              ----------------------------------------------------- */

            // in primis test ping!
            bool pingOk = testPingMachine == IPStatus.Success;
            if (pingOk)
            {
                // versione pre 2023: controllo SOLO ping...
                //// bit 0 (poweron) imposto a 1 SE pingo...
                //B_input = testPingMachine == IPStatus.Success ? 1 : 0;

                // recupero i bit! check poweron = aux inseriti
                bool runAux = ((memReadCIO_IN[0] & (1 << 0)) != 0);
                // check lavora = filtro ON (DEVE ANDARE ma VIENE RILEVATO DOPO, POTREBBE andare da
                // solo x scaricare...)
                bool runFiltro = ((memReadCIO_IN[0] & (1 << 1)) != 0);
                // check carico silos/autobotte
                bool caricoSilos = ((memReadCIO_IN[55] & (1 << 2)) != 0);
                bool caricoAutobotte = ((memReadCIO_IN[50] & (1 << 2)) != 0);

                // Costruzione HEX B_input

                // RUN se CIO_bit 0.00 è POWER ON...
                B_input = runAux ? 1 : 0;
                // RUN se CIO_bit 0.01 è RUN FILTRO...
                if (runFiltro || caricoAutobotte || caricoSilos)
                {
                    // SE HO carico silos OPPURE carico autobotte --> RUN
                    B_input += (1 << 1);
                }
                // ERROR generale (CORREGGERE!)
                if (hasError)
                {
                    B_input += (1 << 3);
                }

                // carico SILOS
                if (caricoSilos)
                {
                    B_input += (1 << 5);
                }
                // carico AUTOBOTTE
                if (caricoAutobotte)
                {
                    B_input += (1 << 6);
                }

                // procedo SOLO SE è enabled IOB
                if (IobOnline)
                {
                    try
                    {
                        currODL = utils.callUrl(urlGetCurrODL);
                        // solo SE HO un ODL...
                        if (string.IsNullOrEmpty(currODL) || currODL == "0")
                        {
                            if (periodicLog)
                            {
                                lgInfo(string.Format("OMRON | Lettura ODL andata a vuoto: currODL: {0}", currODL));
                            }
                        }
                        else
                        {
                            // se variato o scaduto timeout log...
                            if (periodicLog || (currIdxODL.ToString() != currODL))
                            {
                                lgInfo(string.Format("OMRON | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL));
                            }
                            // provo a salvare nuovo ODL
                            int.TryParse(currODL, out currIdxODL);
                        }
                    }
                    catch (Exception exc)
                    {
                        if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15)
                        {
                            lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL);
                            lastWarnODL = DateTime.Now;
                        }
                    }
                }
                else
                {
                    // imposto currODL a vuoto!
                    currODL = "";
                    if (periodicLog)
                    {
                        lgInfo($"Omron | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto");
                    }
                }
                // log opzionale!
                if (verboseLog)
                {
                    lgInfo(string.Format("Trasformazione B_input: {0}", B_input));
                }
            }
        }

        /// <summary>
        /// Vera connessione ad OMRON
        /// </summary>
        /// <returns></returns>
        private short doConnect()
        {
            // avvio un oggetto di comunicazione OMRON
            OMRON_ref = new OmronFinsTCP.Net.EtherNetPLC();
            short port = 9600;
            short.TryParse(IOBConfFull.Device.Connect.Port, out port);
            lgInfo($"Chiamata apertura OMRON FINS: {IOBConfFull.Device.Connect.IpAddr}:{port}");
            short esitoLink = OMRON_ref.Link(IOBConfFull.Device.Connect.IpAddr, port, (short)IOBConfFull.Device.Connect.PingMsTimeout);
            return esitoLink;
        }

        /// <summary>
        /// Test completo funzioni OMRON
        /// </summary>
        private void omronWriteTest()
        {
            commessa = "OMRON EDF TEST";

            // scrivo portata
            portata = 444;

            // scrivo pesatura richiesta
            pesoRichiesto = 22222;

            // scrivo DM 52-53 del lotto richiesto
            quantitaLotto = 66666;
        }

        /// <summary>
        /// Lettura e log valori x debug
        /// </summary>
        private void readAndLog()
        {
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 0, 8, out memReadCIO_IN);
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 100, 8, out memReadCIO_OUT);
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 0, 8, out memReadDM);
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 8, out memReadWR);

            if (isVerboseLog)
            {
                lgInfo("Effettuata lettura dati CIO");
                foreach (var item in memReadCIO_IN)
                {
                    lgInfo($"Valori: {item} -->  {baseUtils.binaryForm(item)}");
                }
                lgInfo("Effettuata lettura dati DM");
                foreach (var item in memReadDM)
                {
                    lgInfo($"Valori: {item} -->  {baseUtils.binaryForm(item)}");
                }
                lgInfo("Effettuata lettura dati WR");
                foreach (var item in memReadWR)
                {
                    lgInfo($"Valori: {item} -->  {baseUtils.binaryForm(item)}");
                }
            }
            short[] respDM20;
            short[] respDM22;
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 20, 2, out respDM20);
            OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 22, 2, out respDM22);
            if (isVerboseLog)
            {
                // legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove
                // il primo è x 1 e il secondo x 10000 (in pratica va in testa)
                lgInfo("Effettuata lettura dati respDM20");
                foreach (var item in respDM20)
                {
                    lgInfo($"Valori: {item} -->  {baseUtils.binaryForm(item)}");
                }
                lgInfo("Effettuata lettura dati respDM22");
                foreach (var item in respDM22)
                {
                    lgInfo($"Valori: {item} -->  {baseUtils.binaryForm(item)}");
                }
            }
        }

        #endregion Private Methods
    }
}